xref: /openbsd-src/sys/dev/pci/if_bnxt.c (revision 2783188a65d179771b59689a8006ab2b8e0f033a)
1*2783188aSjmatthew /*	$OpenBSD: if_bnxt.c,v 1.52 2024/10/06 23:43:18 jmatthew Exp $	*/
2a7c0060aSjmatthew /*-
3a7c0060aSjmatthew  * Broadcom NetXtreme-C/E network driver.
4a7c0060aSjmatthew  *
5a7c0060aSjmatthew  * Copyright (c) 2016 Broadcom, All Rights Reserved.
6a7c0060aSjmatthew  * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
7a7c0060aSjmatthew  *
8a7c0060aSjmatthew  * Redistribution and use in source and binary forms, with or without
9a7c0060aSjmatthew  * modification, are permitted provided that the following conditions
10a7c0060aSjmatthew  * are met:
11a7c0060aSjmatthew  * 1. Redistributions of source code must retain the above copyright
12a7c0060aSjmatthew  *    notice, this list of conditions and the following disclaimer.
13a7c0060aSjmatthew  * 2. Redistributions in binary form must reproduce the above copyright
14a7c0060aSjmatthew  *    notice, this list of conditions and the following disclaimer in the
15a7c0060aSjmatthew  *    documentation and/or other materials provided with the distribution.
16a7c0060aSjmatthew  *
17a7c0060aSjmatthew  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
18a7c0060aSjmatthew  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19a7c0060aSjmatthew  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20a7c0060aSjmatthew  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21a7c0060aSjmatthew  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22a7c0060aSjmatthew  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23a7c0060aSjmatthew  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24a7c0060aSjmatthew  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25a7c0060aSjmatthew  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26a7c0060aSjmatthew  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27a7c0060aSjmatthew  * THE POSSIBILITY OF SUCH DAMAGE.
28a7c0060aSjmatthew  */
29a7c0060aSjmatthew 
30a7c0060aSjmatthew /*
31a7c0060aSjmatthew  * Copyright (c) 2018 Jonathan Matthew <jmatthew@openbsd.org>
32a7c0060aSjmatthew  *
33a7c0060aSjmatthew  * Permission to use, copy, modify, and distribute this software for any
34a7c0060aSjmatthew  * purpose with or without fee is hereby granted, provided that the above
35a7c0060aSjmatthew  * copyright notice and this permission notice appear in all copies.
36a7c0060aSjmatthew  *
37a7c0060aSjmatthew  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
38a7c0060aSjmatthew  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
39a7c0060aSjmatthew  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
40a7c0060aSjmatthew  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41a7c0060aSjmatthew  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
42a7c0060aSjmatthew  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
43a7c0060aSjmatthew  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44a7c0060aSjmatthew  */
45a7c0060aSjmatthew 
46a7c0060aSjmatthew 
47a7c0060aSjmatthew #include "bpfilter.h"
48af7e9c1bSjmatthew #include "vlan.h"
49a7c0060aSjmatthew 
50a7c0060aSjmatthew #include <sys/param.h>
51a7c0060aSjmatthew #include <sys/systm.h>
52a7c0060aSjmatthew #include <sys/mbuf.h>
53a7c0060aSjmatthew #include <sys/malloc.h>
54a7c0060aSjmatthew #include <sys/device.h>
55a7c0060aSjmatthew #include <sys/stdint.h>
56a7c0060aSjmatthew #include <sys/sockio.h>
57a7c0060aSjmatthew #include <sys/atomic.h>
58d160d8f0Sjmatthew #include <sys/intrmap.h>
59a7c0060aSjmatthew 
60a7c0060aSjmatthew #include <machine/bus.h>
61a7c0060aSjmatthew 
62a7c0060aSjmatthew #include <dev/pci/pcivar.h>
63a7c0060aSjmatthew #include <dev/pci/pcidevs.h>
64a7c0060aSjmatthew 
65a7c0060aSjmatthew #include <dev/pci/if_bnxtreg.h>
66a7c0060aSjmatthew 
67a7c0060aSjmatthew #include <net/if.h>
68a7c0060aSjmatthew #include <net/if_media.h>
698a756155Sjmatthew #include <net/route.h>
70d160d8f0Sjmatthew #include <net/toeplitz.h>
71a7c0060aSjmatthew 
72a7c0060aSjmatthew #if NBPFILTER > 0
73a7c0060aSjmatthew #include <net/bpf.h>
74a7c0060aSjmatthew #endif
75a7c0060aSjmatthew 
76a7c0060aSjmatthew #include <netinet/in.h>
77a7c0060aSjmatthew #include <netinet/if_ether.h>
788a756155Sjmatthew #include <netinet/tcp.h>
798a756155Sjmatthew #include <netinet/tcp_timer.h>
808a756155Sjmatthew #include <netinet/tcp_var.h>
81a7c0060aSjmatthew 
82a7c0060aSjmatthew #define BNXT_HWRM_BAR		0x10
83a7c0060aSjmatthew #define BNXT_DOORBELL_BAR	0x18
84a7c0060aSjmatthew 
85765dc391Sjmatthew #define BNXT_MAX_QUEUES		8
86765dc391Sjmatthew 
87765dc391Sjmatthew #define BNXT_CP_RING_ID_BASE	0
88765dc391Sjmatthew #define BNXT_RX_RING_ID_BASE	(BNXT_MAX_QUEUES + 1)
89765dc391Sjmatthew #define BNXT_AG_RING_ID_BASE	((BNXT_MAX_QUEUES * 2) + 1)
90765dc391Sjmatthew #define BNXT_TX_RING_ID_BASE	((BNXT_MAX_QUEUES * 3) + 1)
91a7c0060aSjmatthew 
92270601a5Sjmatthew #define BNXT_MAX_MTU		9500
93c4f53494Sjmatthew #define BNXT_AG_BUFFER_SIZE	8192
94c4f53494Sjmatthew 
95c4f53494Sjmatthew #define BNXT_CP_PAGES		4
96a7c0060aSjmatthew 
978490bd92Sjmatthew #define BNXT_MAX_TX_SEGS	31
98af7e9c1bSjmatthew #define BNXT_TX_SLOTS(bs)	(bs->bs_map->dm_nsegs + 1)
99a7c0060aSjmatthew 
100a7c0060aSjmatthew #define BNXT_HWRM_SHORT_REQ_LEN	sizeof(struct hwrm_short_input)
101a7c0060aSjmatthew 
102a7c0060aSjmatthew #define BNXT_HWRM_LOCK_INIT(_sc, _name)	\
103a7c0060aSjmatthew 	mtx_init_flags(&sc->sc_lock, IPL_NET, _name, 0)
104a7c0060aSjmatthew #define BNXT_HWRM_LOCK(_sc) 		mtx_enter(&_sc->sc_lock)
105a7c0060aSjmatthew #define BNXT_HWRM_UNLOCK(_sc) 		mtx_leave(&_sc->sc_lock)
106a7c0060aSjmatthew #define BNXT_HWRM_LOCK_DESTROY(_sc)	/* nothing */
107a7c0060aSjmatthew #define BNXT_HWRM_LOCK_ASSERT(_sc)	MUTEX_ASSERT_LOCKED(&_sc->sc_lock)
108a7c0060aSjmatthew 
109a7c0060aSjmatthew #define BNXT_FLAG_VF            0x0001
110a7c0060aSjmatthew #define BNXT_FLAG_NPAR          0x0002
111a7c0060aSjmatthew #define BNXT_FLAG_WOL_CAP       0x0004
112a7c0060aSjmatthew #define BNXT_FLAG_SHORT_CMD     0x0008
11361ed761cSsf #define BNXT_FLAG_MSIX          0x0010
114a7c0060aSjmatthew 
1150c45b53cSjmatthew /* NVRam stuff has a five minute timeout */
1160c45b53cSjmatthew #define BNXT_NVM_TIMEO	(5 * 60 * 1000)
1170c45b53cSjmatthew 
118a7c0060aSjmatthew #define NEXT_CP_CONS_V(_ring, _cons, _v_bit)		\
119a7c0060aSjmatthew do {	 						\
120a7c0060aSjmatthew 	if (++(_cons) == (_ring)->ring_size)		\
121a7c0060aSjmatthew 		((_cons) = 0, (_v_bit) = !_v_bit);	\
122a7c0060aSjmatthew } while (0);
123a7c0060aSjmatthew 
124a7c0060aSjmatthew struct bnxt_ring {
125a7c0060aSjmatthew 	uint64_t		paddr;
126a7c0060aSjmatthew 	uint64_t		doorbell;
127a7c0060aSjmatthew 	caddr_t			vaddr;
128a7c0060aSjmatthew 	uint32_t		ring_size;
129a7c0060aSjmatthew 	uint16_t		id;
130a7c0060aSjmatthew 	uint16_t		phys_id;
131a7c0060aSjmatthew };
132a7c0060aSjmatthew 
133a7c0060aSjmatthew struct bnxt_cp_ring {
134a7c0060aSjmatthew 	struct bnxt_ring	ring;
135a7c0060aSjmatthew 	void			*irq;
136a7c0060aSjmatthew 	struct bnxt_softc	*softc;
137a7c0060aSjmatthew 	uint32_t		cons;
138a7c0060aSjmatthew 	int			v_bit;
139c4f53494Sjmatthew 	uint32_t		commit_cons;
140c4f53494Sjmatthew 	int			commit_v_bit;
141a7c0060aSjmatthew 	struct ctx_hw_stats	*stats;
142a7c0060aSjmatthew 	uint32_t		stats_ctx_id;
143765dc391Sjmatthew 	struct bnxt_dmamem	*ring_mem;
144a7c0060aSjmatthew };
145a7c0060aSjmatthew 
146a7c0060aSjmatthew struct bnxt_grp_info {
147a7c0060aSjmatthew 	uint32_t		grp_id;
148a7c0060aSjmatthew 	uint16_t		stats_ctx;
149a7c0060aSjmatthew 	uint16_t		rx_ring_id;
150a7c0060aSjmatthew 	uint16_t		cp_ring_id;
151a7c0060aSjmatthew 	uint16_t		ag_ring_id;
152a7c0060aSjmatthew };
153a7c0060aSjmatthew 
154a7c0060aSjmatthew struct bnxt_vnic_info {
155a7c0060aSjmatthew 	uint16_t		id;
156a7c0060aSjmatthew 	uint16_t		def_ring_grp;
157a7c0060aSjmatthew 	uint16_t		cos_rule;
158a7c0060aSjmatthew 	uint16_t		lb_rule;
159a7c0060aSjmatthew 	uint16_t		mru;
160a7c0060aSjmatthew 
161a7c0060aSjmatthew 	uint32_t		flags;
162a7c0060aSjmatthew #define BNXT_VNIC_FLAG_DEFAULT		0x01
163a7c0060aSjmatthew #define BNXT_VNIC_FLAG_BD_STALL		0x02
164a7c0060aSjmatthew #define BNXT_VNIC_FLAG_VLAN_STRIP	0x04
165a7c0060aSjmatthew 
166a7c0060aSjmatthew 	uint64_t		filter_id;
167a7c0060aSjmatthew 	uint32_t		flow_id;
168a7c0060aSjmatthew 
169a7c0060aSjmatthew 	uint16_t		rss_id;
170a7c0060aSjmatthew };
171a7c0060aSjmatthew 
172a7c0060aSjmatthew struct bnxt_slot {
173a7c0060aSjmatthew 	bus_dmamap_t		bs_map;
174a7c0060aSjmatthew 	struct mbuf		*bs_m;
175a7c0060aSjmatthew };
176a7c0060aSjmatthew 
177a7c0060aSjmatthew struct bnxt_dmamem {
178a7c0060aSjmatthew 	bus_dmamap_t		bdm_map;
179a7c0060aSjmatthew 	bus_dma_segment_t	bdm_seg;
180a7c0060aSjmatthew 	size_t			bdm_size;
181a7c0060aSjmatthew 	caddr_t			bdm_kva;
182a7c0060aSjmatthew };
183a7c0060aSjmatthew #define BNXT_DMA_MAP(_bdm)	((_bdm)->bdm_map)
184a7c0060aSjmatthew #define BNXT_DMA_LEN(_bdm)	((_bdm)->bdm_size)
185a7c0060aSjmatthew #define BNXT_DMA_DVA(_bdm)	((u_int64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr)
186a7c0060aSjmatthew #define BNXT_DMA_KVA(_bdm)	((void *)(_bdm)->bdm_kva)
187a7c0060aSjmatthew 
188765dc391Sjmatthew struct bnxt_rx_queue {
189765dc391Sjmatthew 	struct bnxt_softc	*rx_softc;
190765dc391Sjmatthew 	struct ifiqueue		*rx_ifiq;
191765dc391Sjmatthew 	struct bnxt_dmamem	*rx_ring_mem;	/* rx and ag */
192765dc391Sjmatthew 	struct bnxt_ring	rx_ring;
193765dc391Sjmatthew 	struct bnxt_ring	rx_ag_ring;
194765dc391Sjmatthew 	struct if_rxring	rxr[2];
195765dc391Sjmatthew 	struct bnxt_slot	*rx_slots;
196765dc391Sjmatthew 	struct bnxt_slot	*rx_ag_slots;
197765dc391Sjmatthew 	int			rx_prod;
198765dc391Sjmatthew 	int			rx_cons;
199765dc391Sjmatthew 	int			rx_ag_prod;
200765dc391Sjmatthew 	int			rx_ag_cons;
201765dc391Sjmatthew 	struct timeout		rx_refill;
202765dc391Sjmatthew };
203765dc391Sjmatthew 
204765dc391Sjmatthew struct bnxt_tx_queue {
205765dc391Sjmatthew 	struct bnxt_softc	*tx_softc;
206765dc391Sjmatthew 	struct ifqueue		*tx_ifq;
207765dc391Sjmatthew 	struct bnxt_dmamem	*tx_ring_mem;
208765dc391Sjmatthew 	struct bnxt_ring	tx_ring;
209765dc391Sjmatthew 	struct bnxt_slot	*tx_slots;
210765dc391Sjmatthew 	int			tx_prod;
211765dc391Sjmatthew 	int			tx_cons;
212765dc391Sjmatthew 	int			tx_ring_prod;
213765dc391Sjmatthew 	int			tx_ring_cons;
214765dc391Sjmatthew };
215765dc391Sjmatthew 
216765dc391Sjmatthew struct bnxt_queue {
217765dc391Sjmatthew 	char			q_name[8];
218765dc391Sjmatthew 	int			q_index;
219765dc391Sjmatthew 	void			*q_ihc;
220765dc391Sjmatthew 	struct bnxt_softc	*q_sc;
221765dc391Sjmatthew 	struct bnxt_cp_ring	q_cp;
222765dc391Sjmatthew 	struct bnxt_rx_queue	q_rx;
223765dc391Sjmatthew 	struct bnxt_tx_queue	q_tx;
224765dc391Sjmatthew 	struct bnxt_grp_info	q_rg;
225765dc391Sjmatthew };
226765dc391Sjmatthew 
227a7c0060aSjmatthew struct bnxt_softc {
228a7c0060aSjmatthew 	struct device		sc_dev;
229a7c0060aSjmatthew 	struct arpcom		sc_ac;
230a7c0060aSjmatthew 	struct ifmedia		sc_media;
231a7c0060aSjmatthew 
232a7c0060aSjmatthew 	struct mutex		sc_lock;
233a7c0060aSjmatthew 
234a7c0060aSjmatthew 	pci_chipset_tag_t	sc_pc;
235a7c0060aSjmatthew 	pcitag_t		sc_tag;
236a7c0060aSjmatthew 	bus_dma_tag_t		sc_dmat;
237a7c0060aSjmatthew 
238a7c0060aSjmatthew 	bus_space_tag_t		sc_hwrm_t;
239a7c0060aSjmatthew 	bus_space_handle_t	sc_hwrm_h;
240a7c0060aSjmatthew 	bus_size_t		sc_hwrm_s;
241a7c0060aSjmatthew 
242a7c0060aSjmatthew 	struct bnxt_dmamem	*sc_cmd_resp;
243a7c0060aSjmatthew 	uint16_t		sc_cmd_seq;
244a7c0060aSjmatthew 	uint16_t		sc_max_req_len;
245a7c0060aSjmatthew 	uint32_t		sc_cmd_timeo;
246a7c0060aSjmatthew 	uint32_t		sc_flags;
247a7c0060aSjmatthew 
248a7c0060aSjmatthew 	bus_space_tag_t		sc_db_t;
249a7c0060aSjmatthew 	bus_space_handle_t	sc_db_h;
250a7c0060aSjmatthew 	bus_size_t		sc_db_s;
251a7c0060aSjmatthew 
252a7c0060aSjmatthew 	void			*sc_ih;
253a7c0060aSjmatthew 
25492586e53Sjmatthew 	int			sc_hwrm_ver;
255d460f6dcSjmatthew 	int			sc_tx_queue_id;
256a7c0060aSjmatthew 
257a7c0060aSjmatthew 	struct bnxt_vnic_info	sc_vnic;
258a7c0060aSjmatthew 	struct bnxt_dmamem	*sc_stats_ctx_mem;
259d160d8f0Sjmatthew 	struct bnxt_dmamem	*sc_rx_cfg;
260a7c0060aSjmatthew 
261a7c0060aSjmatthew 	struct bnxt_cp_ring	sc_cp_ring;
262a7c0060aSjmatthew 
263765dc391Sjmatthew 	int			sc_nqueues;
264765dc391Sjmatthew 	struct intrmap		*sc_intrmap;
265765dc391Sjmatthew 	struct bnxt_queue	sc_queues[BNXT_MAX_QUEUES];
266a7c0060aSjmatthew };
267a7c0060aSjmatthew #define DEVNAME(_sc)	((_sc)->sc_dev.dv_xname)
268a7c0060aSjmatthew 
269a7c0060aSjmatthew const struct pci_matchid bnxt_devices[] = {
270a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57301 },
271a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57302 },
272a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57304 },
273a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57311 },
274a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57312 },
275a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57314 },
276a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57402 },
277a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57404 },
278a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57406 },
279a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57407 },
280a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57412 },
281a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57414 },
282a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57416 },
283a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57416_SFP },
284a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57417 },
285a7c0060aSjmatthew 	{ PCI_VENDOR_BROADCOM,	PCI_PRODUCT_BROADCOM_BCM57417_SFP }
286a7c0060aSjmatthew };
287a7c0060aSjmatthew 
288a7c0060aSjmatthew int		bnxt_match(struct device *, void *, void *);
289a7c0060aSjmatthew void		bnxt_attach(struct device *, struct device *, void *);
290a7c0060aSjmatthew 
291a7c0060aSjmatthew void		bnxt_up(struct bnxt_softc *);
292a7c0060aSjmatthew void		bnxt_down(struct bnxt_softc *);
293a7c0060aSjmatthew void		bnxt_iff(struct bnxt_softc *);
294a7c0060aSjmatthew int		bnxt_ioctl(struct ifnet *, u_long, caddr_t);
295a7c0060aSjmatthew int		bnxt_rxrinfo(struct bnxt_softc *, struct if_rxrinfo *);
296a7c0060aSjmatthew void		bnxt_start(struct ifqueue *);
297d160d8f0Sjmatthew int		bnxt_admin_intr(void *);
298a7c0060aSjmatthew int		bnxt_intr(void *);
299a7c0060aSjmatthew void		bnxt_watchdog(struct ifnet *);
300a7c0060aSjmatthew void		bnxt_media_status(struct ifnet *, struct ifmediareq *);
301a7c0060aSjmatthew int		bnxt_media_change(struct ifnet *);
302c6900e6bSjmatthew int		bnxt_media_autonegotiate(struct bnxt_softc *);
303a7c0060aSjmatthew 
304c4f53494Sjmatthew struct cmpl_base *bnxt_cpr_next_cmpl(struct bnxt_softc *, struct bnxt_cp_ring *);
305c4f53494Sjmatthew void		bnxt_cpr_commit(struct bnxt_softc *, struct bnxt_cp_ring *);
306c4f53494Sjmatthew void		bnxt_cpr_rollback(struct bnxt_softc *, struct bnxt_cp_ring *);
307c4f53494Sjmatthew 
308a7c0060aSjmatthew void		bnxt_mark_cpr_invalid(struct bnxt_cp_ring *);
309a7c0060aSjmatthew void		bnxt_write_cp_doorbell(struct bnxt_softc *, struct bnxt_ring *,
310a7c0060aSjmatthew 		    int);
311a7c0060aSjmatthew void		bnxt_write_cp_doorbell_index(struct bnxt_softc *,
312a7c0060aSjmatthew 		    struct bnxt_ring *, uint32_t, int);
313a7c0060aSjmatthew void		bnxt_write_rx_doorbell(struct bnxt_softc *, struct bnxt_ring *,
314a7c0060aSjmatthew 		    int);
315a7c0060aSjmatthew void		bnxt_write_tx_doorbell(struct bnxt_softc *, struct bnxt_ring *,
316a7c0060aSjmatthew 		    int);
317a7c0060aSjmatthew 
318765dc391Sjmatthew int		bnxt_rx_fill(struct bnxt_queue *);
319*2783188aSjmatthew int		bnxt_rx_fill_ag(struct bnxt_queue *);
320c4f53494Sjmatthew u_int		bnxt_rx_fill_slots(struct bnxt_softc *, struct bnxt_ring *, void *,
321c4f53494Sjmatthew 		    struct bnxt_slot *, uint *, int, uint16_t, u_int);
322a7c0060aSjmatthew void		bnxt_refill(void *);
323765dc391Sjmatthew int		bnxt_rx(struct bnxt_softc *, struct bnxt_rx_queue *,
324765dc391Sjmatthew 		    struct bnxt_cp_ring *, struct mbuf_list *, int *, int *,
325765dc391Sjmatthew 		    struct cmpl_base *);
326a7c0060aSjmatthew 
327765dc391Sjmatthew void		bnxt_txeof(struct bnxt_softc *, struct bnxt_tx_queue *, int *,
328765dc391Sjmatthew 		    struct cmpl_base *);
329765dc391Sjmatthew 
330765dc391Sjmatthew int		bnxt_set_cp_ring_aggint(struct bnxt_softc *, struct bnxt_cp_ring *);
331a7c0060aSjmatthew 
3320c45b53cSjmatthew int		_hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
3330c45b53cSjmatthew int		hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
3340c45b53cSjmatthew void		bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *, void *, uint16_t);
3350c45b53cSjmatthew int 		bnxt_hwrm_err_map(uint16_t err);
336a7c0060aSjmatthew 
337a7c0060aSjmatthew /* HWRM Function Prototypes */
338a7c0060aSjmatthew int		bnxt_hwrm_ring_alloc(struct bnxt_softc *, uint8_t,
339a7c0060aSjmatthew 		    struct bnxt_ring *, uint16_t, uint32_t, int);
340a7c0060aSjmatthew int		bnxt_hwrm_ring_free(struct bnxt_softc *, uint8_t,
341a7c0060aSjmatthew 		    struct bnxt_ring *);
342a7c0060aSjmatthew int		bnxt_hwrm_ver_get(struct bnxt_softc *);
343a7c0060aSjmatthew int		bnxt_hwrm_queue_qportcfg(struct bnxt_softc *);
344a7c0060aSjmatthew int		bnxt_hwrm_func_drv_rgtr(struct bnxt_softc *);
345a7c0060aSjmatthew int		bnxt_hwrm_func_qcaps(struct bnxt_softc *);
346a7c0060aSjmatthew int		bnxt_hwrm_func_qcfg(struct bnxt_softc *);
347a7c0060aSjmatthew int		bnxt_hwrm_func_reset(struct bnxt_softc *);
348a7c0060aSjmatthew int		bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *, uint16_t *);
349a7c0060aSjmatthew int		bnxt_hwrm_vnic_ctx_free(struct bnxt_softc *, uint16_t *);
350a7c0060aSjmatthew int		bnxt_hwrm_vnic_cfg(struct bnxt_softc *,
351a7c0060aSjmatthew 		    struct bnxt_vnic_info *);
352c4f53494Sjmatthew int		bnxt_hwrm_vnic_cfg_placement(struct bnxt_softc *,
353c4f53494Sjmatthew 		    struct bnxt_vnic_info *vnic);
354a7c0060aSjmatthew int		bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *,
355a7c0060aSjmatthew 		    struct bnxt_cp_ring *, uint64_t);
356a7c0060aSjmatthew int		bnxt_hwrm_stat_ctx_free(struct bnxt_softc *,
357a7c0060aSjmatthew 		    struct bnxt_cp_ring *);
358a7c0060aSjmatthew int		bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *,
359a7c0060aSjmatthew 		    struct bnxt_grp_info *);
360a7c0060aSjmatthew int		bnxt_hwrm_ring_grp_free(struct bnxt_softc *,
361a7c0060aSjmatthew 		    struct bnxt_grp_info *);
362a7c0060aSjmatthew int		bnxt_hwrm_vnic_alloc(struct bnxt_softc *,
363a7c0060aSjmatthew 		    struct bnxt_vnic_info *);
364a7c0060aSjmatthew int		bnxt_hwrm_vnic_free(struct bnxt_softc *,
365a7c0060aSjmatthew 		    struct bnxt_vnic_info *);
366a7c0060aSjmatthew int		bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *,
367b12ece3dSjmatthew 		    uint32_t, uint32_t, uint64_t, uint32_t);
368a7c0060aSjmatthew int		bnxt_hwrm_set_filter(struct bnxt_softc *,
369a7c0060aSjmatthew 		    struct bnxt_vnic_info *);
370a7c0060aSjmatthew int		bnxt_hwrm_free_filter(struct bnxt_softc *,
371a7c0060aSjmatthew 		    struct bnxt_vnic_info *);
372d160d8f0Sjmatthew int		bnxt_hwrm_vnic_rss_cfg(struct bnxt_softc *,
373d160d8f0Sjmatthew 		    struct bnxt_vnic_info *, uint32_t, daddr_t, daddr_t);
374765dc391Sjmatthew int		bnxt_cfg_async_cr(struct bnxt_softc *, struct bnxt_cp_ring *);
375a7c0060aSjmatthew int		bnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *, uint16_t *,
376a7c0060aSjmatthew 		    uint16_t *, uint32_t *, uint32_t *, uint32_t *, uint32_t *);
377a7c0060aSjmatthew int		bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *,
378a7c0060aSjmatthew 		    struct ifmediareq *);
379a7c0060aSjmatthew int		bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *);
38040247284Sjmatthew int		bnxt_get_sffpage(struct bnxt_softc *, struct if_sffpage *);
381a7c0060aSjmatthew 
382a7c0060aSjmatthew /* not used yet: */
383a7c0060aSjmatthew #if 0
384a7c0060aSjmatthew int bnxt_hwrm_func_drv_unrgtr(struct bnxt_softc *softc, bool shutdown);
385a7c0060aSjmatthew 
386a7c0060aSjmatthew int bnxt_hwrm_port_qstats(struct bnxt_softc *softc);
387a7c0060aSjmatthew 
388a7c0060aSjmatthew 
389a7c0060aSjmatthew int bnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc);
390a7c0060aSjmatthew void bnxt_validate_hw_lro_settings(struct bnxt_softc *softc);
391a7c0060aSjmatthew int bnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor,
392a7c0060aSjmatthew     uint8_t *selfreset);
393a7c0060aSjmatthew int bnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type,
394a7c0060aSjmatthew     uint8_t *selfreset);
395a7c0060aSjmatthew int bnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year,
396a7c0060aSjmatthew     uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute,
397a7c0060aSjmatthew     uint8_t *second, uint16_t *millisecond, uint16_t *zone);
398a7c0060aSjmatthew int bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year,
399a7c0060aSjmatthew     uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
400a7c0060aSjmatthew     uint16_t millisecond, uint16_t zone);
401a7c0060aSjmatthew 
402a7c0060aSjmatthew #endif
403a7c0060aSjmatthew 
404a7c0060aSjmatthew 
4058d2c75e4Smpi const struct cfattach bnxt_ca = {
406a7c0060aSjmatthew 	sizeof(struct bnxt_softc), bnxt_match, bnxt_attach
407a7c0060aSjmatthew };
408a7c0060aSjmatthew 
409a7c0060aSjmatthew struct cfdriver bnxt_cd = {
410a7c0060aSjmatthew 	NULL, "bnxt", DV_IFNET
411a7c0060aSjmatthew };
412a7c0060aSjmatthew 
413a7c0060aSjmatthew struct bnxt_dmamem *
414a7c0060aSjmatthew bnxt_dmamem_alloc(struct bnxt_softc *sc, size_t size)
415a7c0060aSjmatthew {
416a7c0060aSjmatthew 	struct bnxt_dmamem *m;
417a7c0060aSjmatthew 	int nsegs;
418a7c0060aSjmatthew 
419a7c0060aSjmatthew 	m = malloc(sizeof(*m), M_DEVBUF, M_NOWAIT | M_ZERO);
420a7c0060aSjmatthew 	if (m == NULL)
421a7c0060aSjmatthew 		return (NULL);
422a7c0060aSjmatthew 
423a7c0060aSjmatthew 	m->bdm_size = size;
424a7c0060aSjmatthew 
425a7c0060aSjmatthew 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
426a7c0060aSjmatthew 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &m->bdm_map) != 0)
427a7c0060aSjmatthew 		goto bdmfree;
428a7c0060aSjmatthew 
429a7c0060aSjmatthew 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &m->bdm_seg, 1,
430a7c0060aSjmatthew 	    &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
431a7c0060aSjmatthew 		goto destroy;
432a7c0060aSjmatthew 
433a7c0060aSjmatthew 	if (bus_dmamem_map(sc->sc_dmat, &m->bdm_seg, nsegs, size, &m->bdm_kva,
434a7c0060aSjmatthew 	    BUS_DMA_NOWAIT) != 0)
435a7c0060aSjmatthew 		goto free;
436a7c0060aSjmatthew 
437a7c0060aSjmatthew 	if (bus_dmamap_load(sc->sc_dmat, m->bdm_map, m->bdm_kva, size, NULL,
438a7c0060aSjmatthew 	    BUS_DMA_NOWAIT) != 0)
439a7c0060aSjmatthew 		goto unmap;
440a7c0060aSjmatthew 
441a7c0060aSjmatthew 	return (m);
442a7c0060aSjmatthew 
443a7c0060aSjmatthew unmap:
444a7c0060aSjmatthew 	bus_dmamem_unmap(sc->sc_dmat, m->bdm_kva, m->bdm_size);
445a7c0060aSjmatthew free:
446a7c0060aSjmatthew 	bus_dmamem_free(sc->sc_dmat, &m->bdm_seg, 1);
447a7c0060aSjmatthew destroy:
448a7c0060aSjmatthew 	bus_dmamap_destroy(sc->sc_dmat, m->bdm_map);
449a7c0060aSjmatthew bdmfree:
450a7c0060aSjmatthew 	free(m, M_DEVBUF, sizeof *m);
451a7c0060aSjmatthew 
452a7c0060aSjmatthew 	return (NULL);
453a7c0060aSjmatthew }
454a7c0060aSjmatthew 
455a7c0060aSjmatthew void
456a7c0060aSjmatthew bnxt_dmamem_free(struct bnxt_softc *sc, struct bnxt_dmamem *m)
457a7c0060aSjmatthew {
4588dd611f8Sdlg 	bus_dmamap_unload(sc->sc_dmat, m->bdm_map);
459a7c0060aSjmatthew 	bus_dmamem_unmap(sc->sc_dmat, m->bdm_kva, m->bdm_size);
460a7c0060aSjmatthew 	bus_dmamem_free(sc->sc_dmat, &m->bdm_seg, 1);
461a7c0060aSjmatthew 	bus_dmamap_destroy(sc->sc_dmat, m->bdm_map);
462a7c0060aSjmatthew 	free(m, M_DEVBUF, sizeof *m);
463a7c0060aSjmatthew }
464a7c0060aSjmatthew 
465a7c0060aSjmatthew int
466a7c0060aSjmatthew bnxt_match(struct device *parent, void *match, void *aux)
467a7c0060aSjmatthew {
468a7c0060aSjmatthew 	return (pci_matchbyid(aux, bnxt_devices, nitems(bnxt_devices)));
469a7c0060aSjmatthew }
470a7c0060aSjmatthew 
471a7c0060aSjmatthew void
472a7c0060aSjmatthew bnxt_attach(struct device *parent, struct device *self, void *aux)
473a7c0060aSjmatthew {
474a7c0060aSjmatthew 	struct bnxt_softc *sc = (struct bnxt_softc *)self;
475a7c0060aSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
476a7c0060aSjmatthew 	struct pci_attach_args *pa = aux;
477765dc391Sjmatthew 	struct bnxt_cp_ring *cpr;
478a7c0060aSjmatthew 	pci_intr_handle_t ih;
479a7c0060aSjmatthew 	const char *intrstr;
480a7c0060aSjmatthew 	u_int memtype;
481765dc391Sjmatthew 	int i;
482a7c0060aSjmatthew 
483a7c0060aSjmatthew 	sc->sc_pc = pa->pa_pc;
484a7c0060aSjmatthew 	sc->sc_tag = pa->pa_tag;
485a7c0060aSjmatthew 	sc->sc_dmat = pa->pa_dmat;
486a7c0060aSjmatthew 
487a7c0060aSjmatthew 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BNXT_HWRM_BAR);
488a7c0060aSjmatthew 	if (pci_mapreg_map(pa, BNXT_HWRM_BAR, memtype, 0, &sc->sc_hwrm_t,
489a7c0060aSjmatthew 	    &sc->sc_hwrm_h, NULL, &sc->sc_hwrm_s, 0)) {
490a7c0060aSjmatthew 		printf(": failed to map hwrm\n");
491a7c0060aSjmatthew 		return;
492a7c0060aSjmatthew 	}
493a7c0060aSjmatthew 
494a7c0060aSjmatthew 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BNXT_DOORBELL_BAR);
495a7c0060aSjmatthew 	if (pci_mapreg_map(pa, BNXT_DOORBELL_BAR, memtype, 0, &sc->sc_db_t,
496a7c0060aSjmatthew 	    &sc->sc_db_h, NULL, &sc->sc_db_s, 0)) {
497a7c0060aSjmatthew 		printf(": failed to map doorbell\n");
498a7c0060aSjmatthew 		goto unmap_1;
499a7c0060aSjmatthew 	}
500a7c0060aSjmatthew 
501a7c0060aSjmatthew 	BNXT_HWRM_LOCK_INIT(sc, DEVNAME(sc));
502a7c0060aSjmatthew 	sc->sc_cmd_resp = bnxt_dmamem_alloc(sc, PAGE_SIZE);
503a7c0060aSjmatthew 	if (sc->sc_cmd_resp == NULL) {
504a7c0060aSjmatthew 		printf(": failed to allocate command response buffer\n");
505a7c0060aSjmatthew 		goto unmap_2;
506a7c0060aSjmatthew 	}
507a7c0060aSjmatthew 
508a7c0060aSjmatthew 	if (bnxt_hwrm_ver_get(sc) != 0) {
509a7c0060aSjmatthew 		printf(": failed to query version info\n");
510a7c0060aSjmatthew 		goto free_resp;
511a7c0060aSjmatthew 	}
512a7c0060aSjmatthew 
513a7c0060aSjmatthew 	if (bnxt_hwrm_nvm_get_dev_info(sc, NULL, NULL, NULL, NULL, NULL, NULL)
514a7c0060aSjmatthew 	    != 0) {
515a7c0060aSjmatthew 		printf(": failed to get nvram info\n");
516a7c0060aSjmatthew 		goto free_resp;
517a7c0060aSjmatthew 	}
518a7c0060aSjmatthew 
519a7c0060aSjmatthew 	if (bnxt_hwrm_func_drv_rgtr(sc) != 0) {
520a7c0060aSjmatthew 		printf(": failed to register driver with firmware\n");
521a7c0060aSjmatthew 		goto free_resp;
522a7c0060aSjmatthew 	}
523a7c0060aSjmatthew 
524a7c0060aSjmatthew 	if (bnxt_hwrm_func_rgtr_async_events(sc) != 0) {
525a7c0060aSjmatthew 		printf(": failed to register async events\n");
526a7c0060aSjmatthew 		goto free_resp;
527a7c0060aSjmatthew 	}
528a7c0060aSjmatthew 
529a7c0060aSjmatthew 	if (bnxt_hwrm_func_qcaps(sc) != 0) {
530a7c0060aSjmatthew 		printf(": failed to get queue capabilities\n");
531a7c0060aSjmatthew 		goto free_resp;
532a7c0060aSjmatthew 	}
533a7c0060aSjmatthew 
534a7c0060aSjmatthew 	/*
535a7c0060aSjmatthew 	 * devices advertise msi support, but there's no way to tell a
536a7c0060aSjmatthew 	 * completion queue to use msi mode, only legacy or msi-x.
537a7c0060aSjmatthew 	 */
53861ed761cSsf 	if (pci_intr_map_msix(pa, 0, &ih) == 0) {
539d160d8f0Sjmatthew 		int nmsix;
540d160d8f0Sjmatthew 
54161ed761cSsf 		sc->sc_flags |= BNXT_FLAG_MSIX;
542d160d8f0Sjmatthew 		intrstr = pci_intr_string(sc->sc_pc, ih);
543d160d8f0Sjmatthew 
544bc8858ceSjmatthew 		nmsix = pci_intr_msix_count(pa);
545d160d8f0Sjmatthew 		if (nmsix > 1) {
546d160d8f0Sjmatthew 			sc->sc_ih = pci_intr_establish(sc->sc_pc, ih,
547d160d8f0Sjmatthew 			    IPL_NET | IPL_MPSAFE, bnxt_admin_intr, sc, DEVNAME(sc));
548d160d8f0Sjmatthew 			sc->sc_intrmap = intrmap_create(&sc->sc_dev,
549d160d8f0Sjmatthew 			    nmsix - 1, BNXT_MAX_QUEUES, INTRMAP_POWEROF2);
550d160d8f0Sjmatthew 			sc->sc_nqueues = intrmap_count(sc->sc_intrmap);
551d160d8f0Sjmatthew 			KASSERT(sc->sc_nqueues > 0);
552d160d8f0Sjmatthew 			KASSERT(powerof2(sc->sc_nqueues));
553d160d8f0Sjmatthew 		} else {
554d160d8f0Sjmatthew 			sc->sc_ih = pci_intr_establish(sc->sc_pc, ih,
555d160d8f0Sjmatthew 			    IPL_NET | IPL_MPSAFE, bnxt_intr, &sc->sc_queues[0],
556d160d8f0Sjmatthew 			    DEVNAME(sc));
557d160d8f0Sjmatthew 			sc->sc_nqueues = 1;
558a7c0060aSjmatthew 		}
559d160d8f0Sjmatthew 	} else if (pci_intr_map(pa, &ih) == 0) {
560a7c0060aSjmatthew 		intrstr = pci_intr_string(sc->sc_pc, ih);
561a7c0060aSjmatthew 		sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_NET | IPL_MPSAFE,
562765dc391Sjmatthew 		    bnxt_intr, &sc->sc_queues[0], DEVNAME(sc));
563d160d8f0Sjmatthew 		sc->sc_nqueues = 1;
564d160d8f0Sjmatthew 	} else {
565d160d8f0Sjmatthew 		printf(": unable to map interrupt\n");
566d160d8f0Sjmatthew 		goto free_resp;
567d160d8f0Sjmatthew 	}
568a7c0060aSjmatthew 	if (sc->sc_ih == NULL) {
569a7c0060aSjmatthew 		printf(": unable to establish interrupt");
570a7c0060aSjmatthew 		if (intrstr != NULL)
571a7c0060aSjmatthew 			printf(" at %s", intrstr);
572a7c0060aSjmatthew 		printf("\n");
573a7c0060aSjmatthew 		goto deintr;
574a7c0060aSjmatthew 	}
575d160d8f0Sjmatthew 	printf("%s, %d queues, address %s\n", intrstr, sc->sc_nqueues,
576d160d8f0Sjmatthew 	    ether_sprintf(sc->sc_ac.ac_enaddr));
577a7c0060aSjmatthew 
578a7c0060aSjmatthew 	if (bnxt_hwrm_func_qcfg(sc) != 0) {
579a7c0060aSjmatthew 		printf("%s: failed to query function config\n", DEVNAME(sc));
580a7c0060aSjmatthew 		goto deintr;
581a7c0060aSjmatthew 	}
582a7c0060aSjmatthew 
583a7c0060aSjmatthew 	if (bnxt_hwrm_queue_qportcfg(sc) != 0) {
584a7c0060aSjmatthew 		printf("%s: failed to query port config\n", DEVNAME(sc));
585a7c0060aSjmatthew 		goto deintr;
586a7c0060aSjmatthew 	}
587a7c0060aSjmatthew 
588a7c0060aSjmatthew 	if (bnxt_hwrm_func_reset(sc) != 0) {
589a7c0060aSjmatthew 		printf("%s: reset failed\n", DEVNAME(sc));
590a7c0060aSjmatthew 		goto deintr;
591a7c0060aSjmatthew 	}
592a7c0060aSjmatthew 
593e9c3085bSjmatthew 	if (sc->sc_intrmap == NULL)
594765dc391Sjmatthew 		cpr = &sc->sc_queues[0].q_cp;
595765dc391Sjmatthew 	else
596765dc391Sjmatthew 		cpr = &sc->sc_cp_ring;
597765dc391Sjmatthew 
598765dc391Sjmatthew 	cpr->stats_ctx_id = HWRM_NA_SIGNATURE;
599765dc391Sjmatthew 	cpr->ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE;
600765dc391Sjmatthew 	cpr->softc = sc;
601765dc391Sjmatthew 	cpr->ring.id = 0;
602765dc391Sjmatthew 	cpr->ring.doorbell = cpr->ring.id * 0x80;
603765dc391Sjmatthew 	cpr->ring.ring_size = (PAGE_SIZE * BNXT_CP_PAGES) /
604c4f53494Sjmatthew 	    sizeof(struct cmpl_base);
605765dc391Sjmatthew 	cpr->ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE *
606765dc391Sjmatthew 	    BNXT_CP_PAGES);
607765dc391Sjmatthew 	if (cpr->ring_mem == NULL) {
608a7c0060aSjmatthew 		printf("%s: failed to allocate completion queue memory\n",
609a7c0060aSjmatthew 		    DEVNAME(sc));
610a7c0060aSjmatthew 		goto deintr;
611a7c0060aSjmatthew 	}
612765dc391Sjmatthew 	cpr->ring.vaddr = BNXT_DMA_KVA(cpr->ring_mem);
613765dc391Sjmatthew 	cpr->ring.paddr = BNXT_DMA_DVA(cpr->ring_mem);
614765dc391Sjmatthew 	cpr->cons = UINT32_MAX;
615765dc391Sjmatthew 	cpr->v_bit = 1;
616765dc391Sjmatthew 	bnxt_mark_cpr_invalid(cpr);
617a7c0060aSjmatthew 	if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL,
618765dc391Sjmatthew 	    &cpr->ring, (uint16_t)HWRM_NA_SIGNATURE,
619a7c0060aSjmatthew 	    HWRM_NA_SIGNATURE, 1) != 0) {
620a7c0060aSjmatthew 		printf("%s: failed to allocate completion queue\n",
621a7c0060aSjmatthew 		    DEVNAME(sc));
622a7c0060aSjmatthew 		goto free_cp_mem;
623a7c0060aSjmatthew 	}
624765dc391Sjmatthew 	if (bnxt_cfg_async_cr(sc, cpr) != 0) {
625a7c0060aSjmatthew 		printf("%s: failed to set async completion ring\n",
626a7c0060aSjmatthew 		    DEVNAME(sc));
627a7c0060aSjmatthew 		goto free_cp_mem;
628a7c0060aSjmatthew 	}
629765dc391Sjmatthew 	bnxt_write_cp_doorbell(sc, &cpr->ring, 1);
630a7c0060aSjmatthew 
631765dc391Sjmatthew 	if (bnxt_set_cp_ring_aggint(sc, cpr) != 0) {
632765dc391Sjmatthew 		printf("%s: failed to set interrupt aggregation\n",
633765dc391Sjmatthew 		    DEVNAME(sc));
63416a10298Sjmatthew 		goto free_cp_mem;
635765dc391Sjmatthew 	}
63616a10298Sjmatthew 
637a7c0060aSjmatthew 	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
638a7c0060aSjmatthew 	ifp->if_softc = sc;
639a7c0060aSjmatthew 	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
640a7c0060aSjmatthew 	ifp->if_xflags = IFXF_MPSAFE;
641a7c0060aSjmatthew 	ifp->if_ioctl = bnxt_ioctl;
642a7c0060aSjmatthew 	ifp->if_qstart = bnxt_start;
643a7c0060aSjmatthew 	ifp->if_watchdog = bnxt_watchdog;
644a7c0060aSjmatthew 	ifp->if_hardmtu = BNXT_MAX_MTU;
645af7e9c1bSjmatthew 	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 |
646af7e9c1bSjmatthew 	    IFCAP_CSUM_UDPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv6 |
647af7e9c1bSjmatthew 	    IFCAP_CSUM_TCPv6;
6488a756155Sjmatthew 	ifp->if_capabilities |= IFCAP_TSOv4 | IFCAP_TSOv6;
649af7e9c1bSjmatthew #if NVLAN > 0
650af7e9c1bSjmatthew 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
651af7e9c1bSjmatthew #endif
652cf96265bSbluhm 	ifq_init_maxlen(&ifp->if_snd, 1024);	/* ? */
653a7c0060aSjmatthew 
654a7c0060aSjmatthew 	ifmedia_init(&sc->sc_media, IFM_IMASK, bnxt_media_change,
655a7c0060aSjmatthew 	    bnxt_media_status);
656a7c0060aSjmatthew 
657a7c0060aSjmatthew 	if_attach(ifp);
658a7c0060aSjmatthew 	ether_ifattach(ifp);
659a7c0060aSjmatthew 
660765dc391Sjmatthew 	if_attach_iqueues(ifp, sc->sc_nqueues);
661765dc391Sjmatthew 	if_attach_queues(ifp, sc->sc_nqueues);
662765dc391Sjmatthew 	for (i = 0; i < sc->sc_nqueues; i++) {
663765dc391Sjmatthew 		struct ifiqueue *ifiq = ifp->if_iqs[i];
664765dc391Sjmatthew 		struct ifqueue *ifq = ifp->if_ifqs[i];
665765dc391Sjmatthew 		struct bnxt_queue *bq = &sc->sc_queues[i];
666d160d8f0Sjmatthew 		struct bnxt_cp_ring *cp = &bq->q_cp;
667765dc391Sjmatthew 		struct bnxt_rx_queue *rx = &bq->q_rx;
668765dc391Sjmatthew 		struct bnxt_tx_queue *tx = &bq->q_tx;
669765dc391Sjmatthew 
670765dc391Sjmatthew 		bq->q_index = i;
671765dc391Sjmatthew 		bq->q_sc = sc;
672765dc391Sjmatthew 
673765dc391Sjmatthew 		rx->rx_softc = sc;
674765dc391Sjmatthew 		rx->rx_ifiq = ifiq;
675765dc391Sjmatthew 		timeout_set(&rx->rx_refill, bnxt_refill, bq);
676765dc391Sjmatthew 		ifiq->ifiq_softc = rx;
677765dc391Sjmatthew 
678765dc391Sjmatthew 		tx->tx_softc = sc;
679765dc391Sjmatthew 		tx->tx_ifq = ifq;
680765dc391Sjmatthew 		ifq->ifq_softc = tx;
681d160d8f0Sjmatthew 
682e9c3085bSjmatthew 		if (sc->sc_intrmap != NULL) {
683d160d8f0Sjmatthew 			cp->stats_ctx_id = HWRM_NA_SIGNATURE;
684d160d8f0Sjmatthew 			cp->ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE;
685d160d8f0Sjmatthew 			cp->ring.id = i + 1;	/* first cp ring is async only */
686d160d8f0Sjmatthew 			cp->softc = sc;
687d160d8f0Sjmatthew 			cp->ring.doorbell = bq->q_cp.ring.id * 0x80;
688d160d8f0Sjmatthew 			cp->ring.ring_size = (PAGE_SIZE * BNXT_CP_PAGES) /
689d160d8f0Sjmatthew 			    sizeof(struct cmpl_base);
690d160d8f0Sjmatthew 			if (pci_intr_map_msix(pa, i + 1, &ih) != 0) {
691d160d8f0Sjmatthew 				printf("%s: unable to map queue interrupt %d\n",
692d160d8f0Sjmatthew 				    DEVNAME(sc), i);
693d160d8f0Sjmatthew 				goto intrdisestablish;
694d160d8f0Sjmatthew 			}
695d160d8f0Sjmatthew 			snprintf(bq->q_name, sizeof(bq->q_name), "%s:%d",
696d160d8f0Sjmatthew 			    DEVNAME(sc), i);
697d160d8f0Sjmatthew 			bq->q_ihc = pci_intr_establish_cpu(sc->sc_pc, ih,
698d160d8f0Sjmatthew 			    IPL_NET | IPL_MPSAFE, intrmap_cpu(sc->sc_intrmap, i),
699d160d8f0Sjmatthew 			    bnxt_intr, bq, bq->q_name);
700d160d8f0Sjmatthew 			if (bq->q_ihc == NULL) {
701d160d8f0Sjmatthew 				printf("%s: unable to establish interrupt %d\n",
702d160d8f0Sjmatthew 				    DEVNAME(sc), i);
703d160d8f0Sjmatthew 				goto intrdisestablish;
704d160d8f0Sjmatthew 			}
705d160d8f0Sjmatthew 		}
706765dc391Sjmatthew 	}
707a7c0060aSjmatthew 
708c6900e6bSjmatthew 	bnxt_media_autonegotiate(sc);
709a7c0060aSjmatthew 	bnxt_hwrm_port_phy_qcfg(sc, NULL);
710a7c0060aSjmatthew 	return;
711a7c0060aSjmatthew 
712d160d8f0Sjmatthew intrdisestablish:
713d160d8f0Sjmatthew 	for (i = 0; i < sc->sc_nqueues; i++) {
714d160d8f0Sjmatthew 		struct bnxt_queue *bq = &sc->sc_queues[i];
715d160d8f0Sjmatthew 		if (bq->q_ihc == NULL)
716d160d8f0Sjmatthew 			continue;
717d160d8f0Sjmatthew 		pci_intr_disestablish(sc->sc_pc, bq->q_ihc);
718d160d8f0Sjmatthew 		bq->q_ihc = NULL;
719d160d8f0Sjmatthew 	}
720a7c0060aSjmatthew free_cp_mem:
721765dc391Sjmatthew 	bnxt_dmamem_free(sc, cpr->ring_mem);
722a7c0060aSjmatthew deintr:
723d160d8f0Sjmatthew 	if (sc->sc_intrmap != NULL) {
724d160d8f0Sjmatthew 		intrmap_destroy(sc->sc_intrmap);
725d160d8f0Sjmatthew 		sc->sc_intrmap = NULL;
726d160d8f0Sjmatthew 	}
727a7c0060aSjmatthew 	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
728a7c0060aSjmatthew 	sc->sc_ih = NULL;
729a7c0060aSjmatthew free_resp:
730a7c0060aSjmatthew 	bnxt_dmamem_free(sc, sc->sc_cmd_resp);
731a7c0060aSjmatthew unmap_2:
732a7c0060aSjmatthew 	bus_space_unmap(sc->sc_db_t, sc->sc_db_h, sc->sc_db_s);
733a7c0060aSjmatthew 	sc->sc_db_s = 0;
734416e388eSdenis unmap_1:
735416e388eSdenis 	bus_space_unmap(sc->sc_hwrm_t, sc->sc_hwrm_h, sc->sc_hwrm_s);
736416e388eSdenis 	sc->sc_hwrm_s = 0;
737a7c0060aSjmatthew }
738a7c0060aSjmatthew 
739a7c0060aSjmatthew void
740a7c0060aSjmatthew bnxt_free_slots(struct bnxt_softc *sc, struct bnxt_slot *slots, int allocated,
741a7c0060aSjmatthew     int total)
742a7c0060aSjmatthew {
743a7c0060aSjmatthew 	struct bnxt_slot *bs;
744a7c0060aSjmatthew 
745a7c0060aSjmatthew 	int i = allocated;
746a7c0060aSjmatthew 	while (i-- > 0) {
747a7c0060aSjmatthew 		bs = &slots[i];
748a7c0060aSjmatthew 		bus_dmamap_destroy(sc->sc_dmat, bs->bs_map);
74934df0755Sjmatthew 		if (bs->bs_m != NULL)
75034df0755Sjmatthew 			m_freem(bs->bs_m);
751a7c0060aSjmatthew 	}
752a7c0060aSjmatthew 	free(slots, M_DEVBUF, total * sizeof(*bs));
753a7c0060aSjmatthew }
754a7c0060aSjmatthew 
755765dc391Sjmatthew int
756765dc391Sjmatthew bnxt_set_cp_ring_aggint(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr)
757765dc391Sjmatthew {
758765dc391Sjmatthew 	struct hwrm_ring_cmpl_ring_cfg_aggint_params_input aggint;
759765dc391Sjmatthew 
760765dc391Sjmatthew 	/*
761765dc391Sjmatthew 	 * set interrupt aggregation parameters for around 10k interrupts
762765dc391Sjmatthew 	 * per second.  the timers are in units of 80usec, and the counters
763765dc391Sjmatthew 	 * are based on the minimum rx ring size of 32.
764765dc391Sjmatthew 	 */
765765dc391Sjmatthew 	memset(&aggint, 0, sizeof(aggint));
766765dc391Sjmatthew         bnxt_hwrm_cmd_hdr_init(sc, &aggint,
767765dc391Sjmatthew 	    HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
768765dc391Sjmatthew 	aggint.ring_id = htole16(cpr->ring.phys_id);
769765dc391Sjmatthew 	aggint.num_cmpl_dma_aggr = htole16(32);
770765dc391Sjmatthew 	aggint.num_cmpl_dma_aggr_during_int  = aggint.num_cmpl_dma_aggr;
771765dc391Sjmatthew 	aggint.cmpl_aggr_dma_tmr = htole16((1000000000 / 20000) / 80);
772765dc391Sjmatthew 	aggint.cmpl_aggr_dma_tmr_during_int = aggint.cmpl_aggr_dma_tmr;
773765dc391Sjmatthew 	aggint.int_lat_tmr_min = htole16((1000000000 / 20000) / 80);
774765dc391Sjmatthew 	aggint.int_lat_tmr_max = htole16((1000000000 / 10000) / 80);
775765dc391Sjmatthew 	aggint.num_cmpl_aggr_int = htole16(16);
776765dc391Sjmatthew 	return (hwrm_send_message(sc, &aggint, sizeof(aggint)));
777765dc391Sjmatthew }
778765dc391Sjmatthew 
779765dc391Sjmatthew int
780765dc391Sjmatthew bnxt_queue_up(struct bnxt_softc *sc, struct bnxt_queue *bq)
781765dc391Sjmatthew {
782765dc391Sjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
783765dc391Sjmatthew 	struct bnxt_cp_ring *cp = &bq->q_cp;
784765dc391Sjmatthew 	struct bnxt_rx_queue *rx = &bq->q_rx;
785765dc391Sjmatthew 	struct bnxt_tx_queue *tx = &bq->q_tx;
786765dc391Sjmatthew 	struct bnxt_grp_info *rg = &bq->q_rg;
787765dc391Sjmatthew 	struct bnxt_slot *bs;
788765dc391Sjmatthew 	int i;
789765dc391Sjmatthew 
790765dc391Sjmatthew 	tx->tx_ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE);
791765dc391Sjmatthew 	if (tx->tx_ring_mem == NULL) {
792765dc391Sjmatthew 		printf("%s: failed to allocate tx ring %d\n", DEVNAME(sc), bq->q_index);
793765dc391Sjmatthew 		return ENOMEM;
794765dc391Sjmatthew 	}
795765dc391Sjmatthew 
796765dc391Sjmatthew 	rx->rx_ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE * 2);
797765dc391Sjmatthew 	if (rx->rx_ring_mem == NULL) {
798765dc391Sjmatthew 		printf("%s: failed to allocate rx ring %d\n", DEVNAME(sc), bq->q_index);
799765dc391Sjmatthew 		goto free_tx;
800765dc391Sjmatthew 	}
801765dc391Sjmatthew 
802e9c3085bSjmatthew 	/* completion ring is already allocated if we're not using an intrmap */
803e9c3085bSjmatthew 	if (sc->sc_intrmap != NULL) {
804765dc391Sjmatthew 		cp->ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE * BNXT_CP_PAGES);
805765dc391Sjmatthew 		if (cp->ring_mem == NULL) {
806765dc391Sjmatthew 			printf("%s: failed to allocate completion ring %d mem\n",
807765dc391Sjmatthew 			    DEVNAME(sc), bq->q_index);
808765dc391Sjmatthew 			goto free_rx;
809765dc391Sjmatthew 		}
810765dc391Sjmatthew 		cp->ring.vaddr = BNXT_DMA_KVA(cp->ring_mem);
811765dc391Sjmatthew 		cp->ring.paddr = BNXT_DMA_DVA(cp->ring_mem);
812765dc391Sjmatthew 		cp->cons = UINT32_MAX;
813765dc391Sjmatthew 		cp->v_bit = 1;
814765dc391Sjmatthew 		bnxt_mark_cpr_invalid(cp);
815765dc391Sjmatthew 
816765dc391Sjmatthew 		if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL,
817765dc391Sjmatthew 		    &cp->ring, (uint16_t)HWRM_NA_SIGNATURE,
818765dc391Sjmatthew 		    HWRM_NA_SIGNATURE, 1) != 0) {
819765dc391Sjmatthew 			printf("%s: failed to allocate completion queue %d\n",
820765dc391Sjmatthew 			    DEVNAME(sc), bq->q_index);
821765dc391Sjmatthew 			goto free_rx;
822765dc391Sjmatthew 		}
823765dc391Sjmatthew 
824765dc391Sjmatthew 		if (bnxt_set_cp_ring_aggint(sc, cp) != 0) {
825765dc391Sjmatthew 			printf("%s: failed to set interrupt %d aggregation\n",
826765dc391Sjmatthew 			    DEVNAME(sc), bq->q_index);
827765dc391Sjmatthew 			goto free_rx;
828765dc391Sjmatthew 		}
829765dc391Sjmatthew 		bnxt_write_cp_doorbell(sc, &cp->ring, 1);
830b59ce775Sjmatthew 	}
831765dc391Sjmatthew 
832765dc391Sjmatthew 	if (bnxt_hwrm_stat_ctx_alloc(sc, &bq->q_cp,
833765dc391Sjmatthew 	    BNXT_DMA_DVA(sc->sc_stats_ctx_mem) +
834765dc391Sjmatthew 	    (bq->q_index * sizeof(struct ctx_hw_stats))) != 0) {
835765dc391Sjmatthew 		printf("%s: failed to set up stats context\n", DEVNAME(sc));
836765dc391Sjmatthew 		goto free_rx;
837765dc391Sjmatthew 	}
838765dc391Sjmatthew 
839765dc391Sjmatthew 	tx->tx_ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE;
840765dc391Sjmatthew 	tx->tx_ring.id = BNXT_TX_RING_ID_BASE + bq->q_index;
841765dc391Sjmatthew 	tx->tx_ring.doorbell = tx->tx_ring.id * 0x80;
842765dc391Sjmatthew 	tx->tx_ring.ring_size = PAGE_SIZE / sizeof(struct tx_bd_short);
843765dc391Sjmatthew 	tx->tx_ring.vaddr = BNXT_DMA_KVA(tx->tx_ring_mem);
844765dc391Sjmatthew 	tx->tx_ring.paddr = BNXT_DMA_DVA(tx->tx_ring_mem);
845765dc391Sjmatthew 	if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_TX,
846765dc391Sjmatthew 	    &tx->tx_ring, cp->ring.phys_id, HWRM_NA_SIGNATURE, 1) != 0) {
847765dc391Sjmatthew 		printf("%s: failed to set up tx ring\n",
848765dc391Sjmatthew 		    DEVNAME(sc));
849765dc391Sjmatthew 		goto dealloc_stats;
850765dc391Sjmatthew 	}
851765dc391Sjmatthew 	bnxt_write_tx_doorbell(sc, &tx->tx_ring, 0);
852765dc391Sjmatthew 
853765dc391Sjmatthew 	rx->rx_ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE;
854765dc391Sjmatthew 	rx->rx_ring.id = BNXT_RX_RING_ID_BASE + bq->q_index;
855765dc391Sjmatthew 	rx->rx_ring.doorbell = rx->rx_ring.id * 0x80;
856765dc391Sjmatthew 	rx->rx_ring.ring_size = PAGE_SIZE / sizeof(struct rx_prod_pkt_bd);
857765dc391Sjmatthew 	rx->rx_ring.vaddr = BNXT_DMA_KVA(rx->rx_ring_mem);
858765dc391Sjmatthew 	rx->rx_ring.paddr = BNXT_DMA_DVA(rx->rx_ring_mem);
859765dc391Sjmatthew 	if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX,
860765dc391Sjmatthew 	    &rx->rx_ring, cp->ring.phys_id, HWRM_NA_SIGNATURE, 1) != 0) {
861765dc391Sjmatthew 		printf("%s: failed to set up rx ring\n",
862765dc391Sjmatthew 		    DEVNAME(sc));
863765dc391Sjmatthew 		goto dealloc_tx;
864765dc391Sjmatthew 	}
865765dc391Sjmatthew 	bnxt_write_rx_doorbell(sc, &rx->rx_ring, 0);
866765dc391Sjmatthew 
867765dc391Sjmatthew 	rx->rx_ag_ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE;
868765dc391Sjmatthew 	rx->rx_ag_ring.id = BNXT_AG_RING_ID_BASE + bq->q_index;
869765dc391Sjmatthew 	rx->rx_ag_ring.doorbell = rx->rx_ag_ring.id * 0x80;
870765dc391Sjmatthew 	rx->rx_ag_ring.ring_size = PAGE_SIZE / sizeof(struct rx_prod_pkt_bd);
871765dc391Sjmatthew 	rx->rx_ag_ring.vaddr = BNXT_DMA_KVA(rx->rx_ring_mem) + PAGE_SIZE;
872765dc391Sjmatthew 	rx->rx_ag_ring.paddr = BNXT_DMA_DVA(rx->rx_ring_mem) + PAGE_SIZE;
873765dc391Sjmatthew 	if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX,
874765dc391Sjmatthew 	    &rx->rx_ag_ring, cp->ring.phys_id, HWRM_NA_SIGNATURE, 1) != 0) {
875765dc391Sjmatthew 		printf("%s: failed to set up rx ag ring\n",
876765dc391Sjmatthew 		    DEVNAME(sc));
877765dc391Sjmatthew 		goto dealloc_rx;
878765dc391Sjmatthew 	}
879765dc391Sjmatthew 	bnxt_write_rx_doorbell(sc, &rx->rx_ag_ring, 0);
880765dc391Sjmatthew 
881765dc391Sjmatthew 	rg->grp_id = HWRM_NA_SIGNATURE;
882765dc391Sjmatthew 	rg->stats_ctx = cp->stats_ctx_id;
883765dc391Sjmatthew 	rg->rx_ring_id = rx->rx_ring.phys_id;
884765dc391Sjmatthew 	rg->ag_ring_id = rx->rx_ag_ring.phys_id;
885765dc391Sjmatthew 	rg->cp_ring_id = cp->ring.phys_id;
886765dc391Sjmatthew 	if (bnxt_hwrm_ring_grp_alloc(sc, rg) != 0) {
887765dc391Sjmatthew 		printf("%s: failed to allocate ring group\n",
888765dc391Sjmatthew 		    DEVNAME(sc));
889765dc391Sjmatthew 		goto dealloc_ag;
890765dc391Sjmatthew 	}
891765dc391Sjmatthew 
892765dc391Sjmatthew 	rx->rx_slots = mallocarray(sizeof(*bs), rx->rx_ring.ring_size,
893765dc391Sjmatthew 	    M_DEVBUF, M_WAITOK | M_ZERO);
894765dc391Sjmatthew 	if (rx->rx_slots == NULL) {
895765dc391Sjmatthew 		printf("%s: failed to allocate rx slots\n", DEVNAME(sc));
896765dc391Sjmatthew 		goto dealloc_ring_group;
897765dc391Sjmatthew 	}
898765dc391Sjmatthew 
899765dc391Sjmatthew 	for (i = 0; i < rx->rx_ring.ring_size; i++) {
900765dc391Sjmatthew 		bs = &rx->rx_slots[i];
901765dc391Sjmatthew 		if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
902765dc391Sjmatthew 		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bs->bs_map) != 0) {
903765dc391Sjmatthew 			printf("%s: failed to allocate rx dma maps\n",
904765dc391Sjmatthew 			    DEVNAME(sc));
905765dc391Sjmatthew 			goto destroy_rx_slots;
906765dc391Sjmatthew 		}
907765dc391Sjmatthew 	}
908765dc391Sjmatthew 
909765dc391Sjmatthew 	rx->rx_ag_slots = mallocarray(sizeof(*bs), rx->rx_ag_ring.ring_size,
910765dc391Sjmatthew 	    M_DEVBUF, M_WAITOK | M_ZERO);
911765dc391Sjmatthew 	if (rx->rx_ag_slots == NULL) {
912765dc391Sjmatthew 		printf("%s: failed to allocate rx ag slots\n", DEVNAME(sc));
913765dc391Sjmatthew 		goto destroy_rx_slots;
914765dc391Sjmatthew 	}
915765dc391Sjmatthew 
916765dc391Sjmatthew 	for (i = 0; i < rx->rx_ag_ring.ring_size; i++) {
917765dc391Sjmatthew 		bs = &rx->rx_ag_slots[i];
918765dc391Sjmatthew 		if (bus_dmamap_create(sc->sc_dmat, BNXT_AG_BUFFER_SIZE, 1,
919765dc391Sjmatthew 		    BNXT_AG_BUFFER_SIZE, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
920765dc391Sjmatthew 		    &bs->bs_map) != 0) {
921765dc391Sjmatthew 			printf("%s: failed to allocate rx ag dma maps\n",
922765dc391Sjmatthew 			    DEVNAME(sc));
923765dc391Sjmatthew 			goto destroy_rx_ag_slots;
924765dc391Sjmatthew 		}
925765dc391Sjmatthew 	}
926765dc391Sjmatthew 
927765dc391Sjmatthew 	tx->tx_slots = mallocarray(sizeof(*bs), tx->tx_ring.ring_size,
928765dc391Sjmatthew 	    M_DEVBUF, M_WAITOK | M_ZERO);
929765dc391Sjmatthew 	if (tx->tx_slots == NULL) {
930765dc391Sjmatthew 		printf("%s: failed to allocate tx slots\n", DEVNAME(sc));
931765dc391Sjmatthew 		goto destroy_rx_ag_slots;
932765dc391Sjmatthew 	}
933765dc391Sjmatthew 
934765dc391Sjmatthew 	for (i = 0; i < tx->tx_ring.ring_size; i++) {
935765dc391Sjmatthew 		bs = &tx->tx_slots[i];
9368a756155Sjmatthew 		if (bus_dmamap_create(sc->sc_dmat, MAXMCLBYTES, BNXT_MAX_TX_SEGS,
937765dc391Sjmatthew 		    BNXT_MAX_MTU, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
938765dc391Sjmatthew 		    &bs->bs_map) != 0) {
939765dc391Sjmatthew 			printf("%s: failed to allocate tx dma maps\n",
940765dc391Sjmatthew 			    DEVNAME(sc));
941765dc391Sjmatthew 			goto destroy_tx_slots;
942765dc391Sjmatthew 		}
943765dc391Sjmatthew 	}
944765dc391Sjmatthew 
945765dc391Sjmatthew 	/*
946765dc391Sjmatthew 	 * initially, the rx ring must be filled at least some distance beyond
947765dc391Sjmatthew 	 * the current consumer index, as it looks like the firmware assumes the
948765dc391Sjmatthew 	 * ring is full on creation, but doesn't prefetch the whole thing.
949765dc391Sjmatthew 	 * once the whole ring has been used once, we should be able to back off
950765dc391Sjmatthew 	 * to 2 or so slots, but we currently don't have a way of doing that.
951765dc391Sjmatthew 	 */
952765dc391Sjmatthew 	if_rxr_init(&rx->rxr[0], 32, rx->rx_ring.ring_size - 1);
953765dc391Sjmatthew 	if_rxr_init(&rx->rxr[1], 32, rx->rx_ag_ring.ring_size - 1);
954765dc391Sjmatthew 	rx->rx_prod = 0;
955765dc391Sjmatthew 	rx->rx_cons = 0;
956765dc391Sjmatthew 	rx->rx_ag_prod = 0;
957765dc391Sjmatthew 	rx->rx_ag_cons = 0;
958765dc391Sjmatthew 	bnxt_rx_fill(bq);
959*2783188aSjmatthew 	bnxt_rx_fill_ag(bq);
960765dc391Sjmatthew 
961765dc391Sjmatthew 	tx->tx_cons = 0;
962765dc391Sjmatthew 	tx->tx_prod = 0;
963765dc391Sjmatthew 	tx->tx_ring_cons = 0;
964765dc391Sjmatthew 	tx->tx_ring_prod = 0;
965765dc391Sjmatthew 	ifq_clr_oactive(ifp->if_ifqs[bq->q_index]);
966765dc391Sjmatthew 	ifq_restart(ifp->if_ifqs[bq->q_index]);
967765dc391Sjmatthew 	return 0;
968765dc391Sjmatthew 
969765dc391Sjmatthew destroy_tx_slots:
970765dc391Sjmatthew 	bnxt_free_slots(sc, tx->tx_slots, i, tx->tx_ring.ring_size);
971765dc391Sjmatthew 	tx->tx_slots = NULL;
972765dc391Sjmatthew 
973765dc391Sjmatthew 	i = rx->rx_ag_ring.ring_size;
974765dc391Sjmatthew destroy_rx_ag_slots:
975765dc391Sjmatthew 	bnxt_free_slots(sc, rx->rx_ag_slots, i, rx->rx_ag_ring.ring_size);
976765dc391Sjmatthew 	rx->rx_ag_slots = NULL;
977765dc391Sjmatthew 
978765dc391Sjmatthew 	i = rx->rx_ring.ring_size;
979765dc391Sjmatthew destroy_rx_slots:
980765dc391Sjmatthew 	bnxt_free_slots(sc, rx->rx_slots, i, rx->rx_ring.ring_size);
981765dc391Sjmatthew 	rx->rx_slots = NULL;
982765dc391Sjmatthew dealloc_ring_group:
983765dc391Sjmatthew 	bnxt_hwrm_ring_grp_free(sc, &bq->q_rg);
984765dc391Sjmatthew dealloc_ag:
985765dc391Sjmatthew 	bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX,
986765dc391Sjmatthew 	    &rx->rx_ag_ring);
987765dc391Sjmatthew dealloc_tx:
988765dc391Sjmatthew 	bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_TX,
989765dc391Sjmatthew 	    &tx->tx_ring);
990765dc391Sjmatthew dealloc_rx:
991765dc391Sjmatthew 	bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX,
992765dc391Sjmatthew 	    &rx->rx_ring);
993765dc391Sjmatthew dealloc_stats:
994765dc391Sjmatthew 	bnxt_hwrm_stat_ctx_free(sc, cp);
995765dc391Sjmatthew free_rx:
996765dc391Sjmatthew 	bnxt_dmamem_free(sc, rx->rx_ring_mem);
997765dc391Sjmatthew 	rx->rx_ring_mem = NULL;
998765dc391Sjmatthew free_tx:
999765dc391Sjmatthew 	bnxt_dmamem_free(sc, tx->tx_ring_mem);
1000765dc391Sjmatthew 	tx->tx_ring_mem = NULL;
1001765dc391Sjmatthew 	return ENOMEM;
1002765dc391Sjmatthew }
1003765dc391Sjmatthew 
1004765dc391Sjmatthew void
1005765dc391Sjmatthew bnxt_queue_down(struct bnxt_softc *sc, struct bnxt_queue *bq)
1006765dc391Sjmatthew {
1007765dc391Sjmatthew 	struct bnxt_cp_ring *cp = &bq->q_cp;
1008765dc391Sjmatthew 	struct bnxt_rx_queue *rx = &bq->q_rx;
1009765dc391Sjmatthew 	struct bnxt_tx_queue *tx = &bq->q_tx;
1010765dc391Sjmatthew 
1011765dc391Sjmatthew 	bnxt_free_slots(sc, tx->tx_slots, tx->tx_ring.ring_size,
1012765dc391Sjmatthew 	    tx->tx_ring.ring_size);
1013765dc391Sjmatthew 	tx->tx_slots = NULL;
1014765dc391Sjmatthew 
1015765dc391Sjmatthew 	bnxt_free_slots(sc, rx->rx_ag_slots, rx->rx_ag_ring.ring_size,
1016765dc391Sjmatthew 	    rx->rx_ag_ring.ring_size);
1017765dc391Sjmatthew 	rx->rx_ag_slots = NULL;
1018765dc391Sjmatthew 
1019765dc391Sjmatthew 	bnxt_free_slots(sc, rx->rx_slots, rx->rx_ring.ring_size,
1020765dc391Sjmatthew 	    rx->rx_ring.ring_size);
1021765dc391Sjmatthew 	rx->rx_slots = NULL;
1022765dc391Sjmatthew 
1023765dc391Sjmatthew 	bnxt_hwrm_ring_grp_free(sc, &bq->q_rg);
1024765dc391Sjmatthew 	bnxt_hwrm_stat_ctx_free(sc, &bq->q_cp);
1025765dc391Sjmatthew 
1026765dc391Sjmatthew 	/* may need to wait for 500ms here before we can free the rings */
1027765dc391Sjmatthew 
1028765dc391Sjmatthew 	bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_TX,
1029765dc391Sjmatthew 	    &tx->tx_ring);
1030765dc391Sjmatthew 	bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX,
1031765dc391Sjmatthew 	    &rx->rx_ag_ring);
1032765dc391Sjmatthew 	bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX,
1033765dc391Sjmatthew 	    &rx->rx_ring);
1034b59ce775Sjmatthew 
1035e9c3085bSjmatthew 	/* if no intrmap, leave cp ring in place for async events */
1036e9c3085bSjmatthew 	if (sc->sc_intrmap != NULL) {
1037765dc391Sjmatthew 		bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL,
1038765dc391Sjmatthew 		    &cp->ring);
1039765dc391Sjmatthew 
1040b59ce775Sjmatthew 		bnxt_dmamem_free(sc, cp->ring_mem);
1041b59ce775Sjmatthew 		cp->ring_mem = NULL;
1042b59ce775Sjmatthew 	}
1043b59ce775Sjmatthew 
1044765dc391Sjmatthew 	bnxt_dmamem_free(sc, rx->rx_ring_mem);
1045765dc391Sjmatthew 	rx->rx_ring_mem = NULL;
1046765dc391Sjmatthew 
1047765dc391Sjmatthew 	bnxt_dmamem_free(sc, tx->tx_ring_mem);
1048765dc391Sjmatthew 	tx->tx_ring_mem = NULL;
1049765dc391Sjmatthew }
1050765dc391Sjmatthew 
1051a7c0060aSjmatthew void
1052a7c0060aSjmatthew bnxt_up(struct bnxt_softc *sc)
1053a7c0060aSjmatthew {
1054a7c0060aSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1055a7c0060aSjmatthew 	int i;
1056a7c0060aSjmatthew 
1057a7c0060aSjmatthew 	sc->sc_stats_ctx_mem = bnxt_dmamem_alloc(sc,
1058765dc391Sjmatthew 	    sizeof(struct ctx_hw_stats) * sc->sc_nqueues);
1059a7c0060aSjmatthew 	if (sc->sc_stats_ctx_mem == NULL) {
1060a7c0060aSjmatthew 		printf("%s: failed to allocate stats contexts\n", DEVNAME(sc));
1061a7c0060aSjmatthew 		return;
1062a7c0060aSjmatthew 	}
1063a7c0060aSjmatthew 
1064d160d8f0Sjmatthew 	sc->sc_rx_cfg = bnxt_dmamem_alloc(sc, PAGE_SIZE * 2);
1065d160d8f0Sjmatthew 	if (sc->sc_rx_cfg == NULL) {
1066d160d8f0Sjmatthew 		printf("%s: failed to allocate rx config buffer\n",
1067765dc391Sjmatthew 		    DEVNAME(sc));
1068a7c0060aSjmatthew 		goto free_stats;
1069a7c0060aSjmatthew 	}
1070a7c0060aSjmatthew 
1071765dc391Sjmatthew 	for (i = 0; i < sc->sc_nqueues; i++) {
1072765dc391Sjmatthew 		if (bnxt_queue_up(sc, &sc->sc_queues[i]) != 0) {
1073765dc391Sjmatthew 			goto down_queues;
1074a7c0060aSjmatthew 		}
1075a7c0060aSjmatthew 	}
1076a7c0060aSjmatthew 
10777a844086Sjmatthew 	sc->sc_vnic.rss_id = (uint16_t)HWRM_NA_SIGNATURE;
1078a7c0060aSjmatthew 	if (bnxt_hwrm_vnic_ctx_alloc(sc, &sc->sc_vnic.rss_id) != 0) {
1079a7c0060aSjmatthew 		printf("%s: failed to allocate vnic rss context\n",
1080a7c0060aSjmatthew 		    DEVNAME(sc));
10819a5ce850Sjmatthew 		goto down_all_queues;
1082a7c0060aSjmatthew 	}
1083a7c0060aSjmatthew 
10847a844086Sjmatthew 	sc->sc_vnic.id = (uint16_t)HWRM_NA_SIGNATURE;
1085765dc391Sjmatthew 	sc->sc_vnic.def_ring_grp = sc->sc_queues[0].q_rg.grp_id;
1086c4f53494Sjmatthew 	sc->sc_vnic.mru = BNXT_MAX_MTU;
1087a7c0060aSjmatthew 	sc->sc_vnic.cos_rule = (uint16_t)HWRM_NA_SIGNATURE;
1088a7c0060aSjmatthew 	sc->sc_vnic.lb_rule = (uint16_t)HWRM_NA_SIGNATURE;
1089870f5687Sjmatthew 	sc->sc_vnic.flags = BNXT_VNIC_FLAG_DEFAULT |
1090870f5687Sjmatthew 	    BNXT_VNIC_FLAG_VLAN_STRIP;
1091a7c0060aSjmatthew 	if (bnxt_hwrm_vnic_alloc(sc, &sc->sc_vnic) != 0) {
1092a7c0060aSjmatthew 		printf("%s: failed to allocate vnic\n", DEVNAME(sc));
1093a7c0060aSjmatthew 		goto dealloc_vnic_ctx;
1094a7c0060aSjmatthew 	}
1095a7c0060aSjmatthew 
1096a7c0060aSjmatthew 	if (bnxt_hwrm_vnic_cfg(sc, &sc->sc_vnic) != 0) {
1097a7c0060aSjmatthew 		printf("%s: failed to configure vnic\n", DEVNAME(sc));
1098a7c0060aSjmatthew 		goto dealloc_vnic;
1099a7c0060aSjmatthew 	}
1100a7c0060aSjmatthew 
1101c4f53494Sjmatthew 	if (bnxt_hwrm_vnic_cfg_placement(sc, &sc->sc_vnic) != 0) {
1102c4f53494Sjmatthew 		printf("%s: failed to configure vnic placement mode\n",
1103c4f53494Sjmatthew 		    DEVNAME(sc));
1104c4f53494Sjmatthew 		goto dealloc_vnic;
1105c4f53494Sjmatthew 	}
1106c4f53494Sjmatthew 
1107a7c0060aSjmatthew 	sc->sc_vnic.filter_id = -1;
1108a7c0060aSjmatthew 	if (bnxt_hwrm_set_filter(sc, &sc->sc_vnic) != 0) {
1109a7c0060aSjmatthew 		printf("%s: failed to set vnic filter\n", DEVNAME(sc));
1110a7c0060aSjmatthew 		goto dealloc_vnic;
1111a7c0060aSjmatthew 	}
1112a7c0060aSjmatthew 
1113d160d8f0Sjmatthew 	if (sc->sc_nqueues > 1) {
1114d160d8f0Sjmatthew 		uint16_t *rss_table = (BNXT_DMA_KVA(sc->sc_rx_cfg) + PAGE_SIZE);
1115d160d8f0Sjmatthew 		uint8_t *hash_key = (uint8_t *)(rss_table + HW_HASH_INDEX_SIZE);
1116d160d8f0Sjmatthew 
1117d160d8f0Sjmatthew 		for (i = 0; i < HW_HASH_INDEX_SIZE; i++) {
1118d160d8f0Sjmatthew 			struct bnxt_queue *bq;
1119d160d8f0Sjmatthew 
1120d160d8f0Sjmatthew 			bq = &sc->sc_queues[i % sc->sc_nqueues];
1121d160d8f0Sjmatthew 			rss_table[i] = htole16(bq->q_rg.grp_id);
1122d160d8f0Sjmatthew 		}
1123d160d8f0Sjmatthew 		stoeplitz_to_key(hash_key, HW_HASH_KEY_SIZE);
1124d160d8f0Sjmatthew 
1125d160d8f0Sjmatthew 		if (bnxt_hwrm_vnic_rss_cfg(sc, &sc->sc_vnic,
1126d160d8f0Sjmatthew 		    HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV4 |
1127d160d8f0Sjmatthew 		    HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_TCP_IPV4 |
1128d160d8f0Sjmatthew 		    HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV6 |
1129d160d8f0Sjmatthew 		    HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_TCP_IPV6,
1130d160d8f0Sjmatthew 		    BNXT_DMA_DVA(sc->sc_rx_cfg) + PAGE_SIZE,
1131d160d8f0Sjmatthew 		    BNXT_DMA_DVA(sc->sc_rx_cfg) + PAGE_SIZE +
1132d160d8f0Sjmatthew 		    (HW_HASH_INDEX_SIZE * sizeof(uint16_t))) != 0) {
1133d160d8f0Sjmatthew 			printf("%s: failed to set RSS config\n", DEVNAME(sc));
1134d160d8f0Sjmatthew 			goto dealloc_vnic;
1135d160d8f0Sjmatthew 		}
1136d160d8f0Sjmatthew 	}
1137d160d8f0Sjmatthew 
1138a7c0060aSjmatthew 	bnxt_iff(sc);
1139a7c0060aSjmatthew 	SET(ifp->if_flags, IFF_RUNNING);
1140a7c0060aSjmatthew 
1141a7c0060aSjmatthew 	return;
1142a7c0060aSjmatthew 
1143a7c0060aSjmatthew dealloc_vnic:
1144a7c0060aSjmatthew 	bnxt_hwrm_vnic_free(sc, &sc->sc_vnic);
1145a7c0060aSjmatthew dealloc_vnic_ctx:
1146a7c0060aSjmatthew 	bnxt_hwrm_vnic_ctx_free(sc, &sc->sc_vnic.rss_id);
11479a5ce850Sjmatthew 
11489a5ce850Sjmatthew down_all_queues:
11499a5ce850Sjmatthew 	i = sc->sc_nqueues;
1150765dc391Sjmatthew down_queues:
11519a5ce850Sjmatthew 	while (i-- > 0)
1152765dc391Sjmatthew 		bnxt_queue_down(sc, &sc->sc_queues[i]);
1153765dc391Sjmatthew 
1154d160d8f0Sjmatthew 	bnxt_dmamem_free(sc, sc->sc_rx_cfg);
1155d160d8f0Sjmatthew 	sc->sc_rx_cfg = NULL;
1156a7c0060aSjmatthew free_stats:
1157a7c0060aSjmatthew 	bnxt_dmamem_free(sc, sc->sc_stats_ctx_mem);
1158a7c0060aSjmatthew 	sc->sc_stats_ctx_mem = NULL;
1159a7c0060aSjmatthew }
1160a7c0060aSjmatthew 
1161a7c0060aSjmatthew void
1162a7c0060aSjmatthew bnxt_down(struct bnxt_softc *sc)
1163a7c0060aSjmatthew {
1164a7c0060aSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1165765dc391Sjmatthew 	int i;
1166a7c0060aSjmatthew 
1167a7c0060aSjmatthew 	CLR(ifp->if_flags, IFF_RUNNING);
1168a7c0060aSjmatthew 
11692bbed9a6Sjmatthew 	intr_barrier(sc->sc_ih);
11702bbed9a6Sjmatthew 
1171765dc391Sjmatthew 	for (i = 0; i < sc->sc_nqueues; i++) {
1172765dc391Sjmatthew 		ifq_clr_oactive(ifp->if_ifqs[i]);
1173765dc391Sjmatthew 		ifq_barrier(ifp->if_ifqs[i]);
1174a7c0060aSjmatthew 
11752bbed9a6Sjmatthew 		timeout_del_barrier(&sc->sc_queues[i].q_rx.rx_refill);
11762bbed9a6Sjmatthew 
11772bbed9a6Sjmatthew 		if (sc->sc_intrmap != NULL)
11782bbed9a6Sjmatthew 			intr_barrier(sc->sc_queues[i].q_ihc);
1179765dc391Sjmatthew 	}
1180a7c0060aSjmatthew 
1181a7c0060aSjmatthew 	bnxt_hwrm_free_filter(sc, &sc->sc_vnic);
1182a7c0060aSjmatthew 	bnxt_hwrm_vnic_free(sc, &sc->sc_vnic);
1183a7c0060aSjmatthew 	bnxt_hwrm_vnic_ctx_free(sc, &sc->sc_vnic.rss_id);
1184a7c0060aSjmatthew 
1185765dc391Sjmatthew 	for (i = 0; i < sc->sc_nqueues; i++)
1186765dc391Sjmatthew 		bnxt_queue_down(sc, &sc->sc_queues[i]);
1187a7c0060aSjmatthew 
1188d160d8f0Sjmatthew 	bnxt_dmamem_free(sc, sc->sc_rx_cfg);
1189d160d8f0Sjmatthew 	sc->sc_rx_cfg = NULL;
1190b12ece3dSjmatthew 
1191a7c0060aSjmatthew 	bnxt_dmamem_free(sc, sc->sc_stats_ctx_mem);
1192a7c0060aSjmatthew 	sc->sc_stats_ctx_mem = NULL;
1193a7c0060aSjmatthew }
1194a7c0060aSjmatthew 
1195a7c0060aSjmatthew void
1196a7c0060aSjmatthew bnxt_iff(struct bnxt_softc *sc)
1197a7c0060aSjmatthew {
1198a7c0060aSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1199b12ece3dSjmatthew 	struct ether_multi *enm;
1200b12ece3dSjmatthew 	struct ether_multistep step;
1201b12ece3dSjmatthew 	char *mc_list;
1202b12ece3dSjmatthew 	uint32_t rx_mask, mc_count;
1203a7c0060aSjmatthew 
1204b12ece3dSjmatthew 	rx_mask = HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_BCAST
1205b12ece3dSjmatthew 	    | HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_MCAST
1206b12ece3dSjmatthew 	    | HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ANYVLAN_NONVLAN;
1207a7c0060aSjmatthew 
1208d160d8f0Sjmatthew 	mc_list = BNXT_DMA_KVA(sc->sc_rx_cfg);
1209b12ece3dSjmatthew 	mc_count = 0;
1210a7c0060aSjmatthew 
1211b12ece3dSjmatthew 	if (ifp->if_flags & IFF_PROMISC) {
1212b12ece3dSjmatthew 		SET(ifp->if_flags, IFF_ALLMULTI);
1213b12ece3dSjmatthew 		rx_mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_PROMISCUOUS;
1214b12ece3dSjmatthew 	} else if ((sc->sc_ac.ac_multirangecnt > 0) ||
1215b12ece3dSjmatthew 	    (sc->sc_ac.ac_multicnt > (PAGE_SIZE / ETHER_ADDR_LEN))) {
1216b12ece3dSjmatthew 		SET(ifp->if_flags, IFF_ALLMULTI);
1217b12ece3dSjmatthew 		rx_mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ALL_MCAST;
1218b12ece3dSjmatthew 	} else {
1219b12ece3dSjmatthew 		CLR(ifp->if_flags, IFF_ALLMULTI);
1220b12ece3dSjmatthew 		ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
1221b12ece3dSjmatthew 		while (enm != NULL) {
1222b12ece3dSjmatthew 			memcpy(mc_list, enm->enm_addrlo, ETHER_ADDR_LEN);
1223b12ece3dSjmatthew 			mc_list += ETHER_ADDR_LEN;
1224b12ece3dSjmatthew 			mc_count++;
1225b12ece3dSjmatthew 
1226b12ece3dSjmatthew 			ETHER_NEXT_MULTI(step, enm);
1227b12ece3dSjmatthew 		}
1228b12ece3dSjmatthew 	}
1229b12ece3dSjmatthew 
1230b12ece3dSjmatthew 	bnxt_hwrm_cfa_l2_set_rx_mask(sc, sc->sc_vnic.id, rx_mask,
1231d160d8f0Sjmatthew 	    BNXT_DMA_DVA(sc->sc_rx_cfg), mc_count);
1232a7c0060aSjmatthew }
1233a7c0060aSjmatthew 
1234a7c0060aSjmatthew int
1235a7c0060aSjmatthew bnxt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1236a7c0060aSjmatthew {
1237a7c0060aSjmatthew 	struct bnxt_softc 	*sc = (struct bnxt_softc *)ifp->if_softc;
1238a7c0060aSjmatthew 	struct ifreq		*ifr = (struct ifreq *)data;
1239a7c0060aSjmatthew 	int			s, error = 0;
1240a7c0060aSjmatthew 
1241a7c0060aSjmatthew 	s = splnet();
1242a7c0060aSjmatthew 	switch (cmd) {
1243a7c0060aSjmatthew 	case SIOCSIFADDR:
1244a7c0060aSjmatthew 		ifp->if_flags |= IFF_UP;
1245a7c0060aSjmatthew 		/* FALLTHROUGH */
1246a7c0060aSjmatthew 
1247a7c0060aSjmatthew 	case SIOCSIFFLAGS:
1248a7c0060aSjmatthew 		if (ISSET(ifp->if_flags, IFF_UP)) {
1249a7c0060aSjmatthew 			if (ISSET(ifp->if_flags, IFF_RUNNING))
1250a7c0060aSjmatthew 				error = ENETRESET;
1251a7c0060aSjmatthew 			else
1252a7c0060aSjmatthew 				bnxt_up(sc);
1253a7c0060aSjmatthew 		} else {
1254a7c0060aSjmatthew 			if (ISSET(ifp->if_flags, IFF_RUNNING))
1255a7c0060aSjmatthew 				bnxt_down(sc);
1256a7c0060aSjmatthew 		}
1257a7c0060aSjmatthew 		break;
1258a7c0060aSjmatthew 
1259a7c0060aSjmatthew 	case SIOCGIFMEDIA:
1260a7c0060aSjmatthew 	case SIOCSIFMEDIA:
1261a7c0060aSjmatthew 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
1262a7c0060aSjmatthew 		break;
1263a7c0060aSjmatthew 
1264a7c0060aSjmatthew 	case SIOCGIFRXR:
1265a7c0060aSjmatthew 		error = bnxt_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
1266a7c0060aSjmatthew 		break;
1267a7c0060aSjmatthew 
126840247284Sjmatthew 	case SIOCGIFSFFPAGE:
126940247284Sjmatthew 		error = bnxt_get_sffpage(sc, (struct if_sffpage *)data);
127040247284Sjmatthew 		break;
127140247284Sjmatthew 
1272a7c0060aSjmatthew 	default:
1273a7c0060aSjmatthew 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
1274a7c0060aSjmatthew 	}
1275a7c0060aSjmatthew 
1276a7c0060aSjmatthew 	if (error == ENETRESET) {
1277a7c0060aSjmatthew 		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
1278a7c0060aSjmatthew 		    (IFF_UP | IFF_RUNNING))
1279a7c0060aSjmatthew 			bnxt_iff(sc);
1280a7c0060aSjmatthew 		error = 0;
1281a7c0060aSjmatthew 	}
1282a7c0060aSjmatthew 
1283a7c0060aSjmatthew 	splx(s);
1284a7c0060aSjmatthew 
1285a7c0060aSjmatthew 	return (error);
1286a7c0060aSjmatthew }
1287a7c0060aSjmatthew 
1288a7c0060aSjmatthew int
1289a7c0060aSjmatthew bnxt_rxrinfo(struct bnxt_softc *sc, struct if_rxrinfo *ifri)
1290a7c0060aSjmatthew {
1291765dc391Sjmatthew 	struct if_rxring_info *ifr;
1292765dc391Sjmatthew 	int i;
1293765dc391Sjmatthew 	int error;
1294a7c0060aSjmatthew 
1295765dc391Sjmatthew 	ifr = mallocarray(sc->sc_nqueues * 2, sizeof(*ifr), M_TEMP,
1296765dc391Sjmatthew 	    M_WAITOK | M_ZERO | M_CANFAIL);
1297765dc391Sjmatthew 	if (ifr == NULL)
1298765dc391Sjmatthew 		return (ENOMEM);
1299a7c0060aSjmatthew 
1300765dc391Sjmatthew 	for (i = 0; i < sc->sc_nqueues; i++) {
1301765dc391Sjmatthew 		ifr[(i * 2)].ifr_size = MCLBYTES;
1302765dc391Sjmatthew 		ifr[(i * 2)].ifr_info = sc->sc_queues[i].q_rx.rxr[0];
1303c4f53494Sjmatthew 
1304765dc391Sjmatthew 		ifr[(i * 2) + 1].ifr_size = BNXT_AG_BUFFER_SIZE;
1305765dc391Sjmatthew 		ifr[(i * 2) + 1].ifr_info = sc->sc_queues[i].q_rx.rxr[1];
1306765dc391Sjmatthew 	}
1307765dc391Sjmatthew 
1308765dc391Sjmatthew 	error = if_rxr_info_ioctl(ifri, sc->sc_nqueues * 2, ifr);
1309765dc391Sjmatthew 	free(ifr, M_TEMP, sc->sc_nqueues * 2 * sizeof(*ifr));
1310765dc391Sjmatthew 
1311765dc391Sjmatthew 	return (error);
1312a7c0060aSjmatthew }
1313a7c0060aSjmatthew 
1314a7c0060aSjmatthew int
1315a7c0060aSjmatthew bnxt_load_mbuf(struct bnxt_softc *sc, struct bnxt_slot *bs, struct mbuf *m)
1316a7c0060aSjmatthew {
1317a7c0060aSjmatthew 	switch (bus_dmamap_load_mbuf(sc->sc_dmat, bs->bs_map, m,
1318a7c0060aSjmatthew 	    BUS_DMA_STREAMING | BUS_DMA_NOWAIT)) {
1319a7c0060aSjmatthew 	case 0:
1320a7c0060aSjmatthew 		break;
1321a7c0060aSjmatthew 
1322a7c0060aSjmatthew 	case EFBIG:
1323a7c0060aSjmatthew 		if (m_defrag(m, M_DONTWAIT) == 0 &&
1324a7c0060aSjmatthew 		    bus_dmamap_load_mbuf(sc->sc_dmat, bs->bs_map, m,
1325a7c0060aSjmatthew 		    BUS_DMA_STREAMING | BUS_DMA_NOWAIT) == 0)
1326a7c0060aSjmatthew 			break;
1327a7c0060aSjmatthew 
1328a7c0060aSjmatthew 	default:
1329a7c0060aSjmatthew 		return (1);
1330a7c0060aSjmatthew 	}
1331a7c0060aSjmatthew 
1332a7c0060aSjmatthew 	bs->bs_m = m;
1333a7c0060aSjmatthew 	return (0);
1334a7c0060aSjmatthew }
1335a7c0060aSjmatthew 
1336a7c0060aSjmatthew void
1337a7c0060aSjmatthew bnxt_start(struct ifqueue *ifq)
1338a7c0060aSjmatthew {
1339a7c0060aSjmatthew 	struct ifnet *ifp = ifq->ifq_if;
1340a7c0060aSjmatthew 	struct tx_bd_short *txring;
1341af7e9c1bSjmatthew 	struct tx_bd_long_hi *txhi;
1342765dc391Sjmatthew 	struct bnxt_tx_queue *tx = ifq->ifq_softc;
1343765dc391Sjmatthew 	struct bnxt_softc *sc = tx->tx_softc;
1344a7c0060aSjmatthew 	struct bnxt_slot *bs;
13458a756155Sjmatthew 	struct ether_extracted ext;
1346a7c0060aSjmatthew 	bus_dmamap_t map;
1347a7c0060aSjmatthew 	struct mbuf *m;
1348058d3950Sjmatthew 	u_int idx, free, used, laststart;
13498a756155Sjmatthew 	uint16_t txflags, lflags;
13508a756155Sjmatthew 	int i, slen;
1351a7c0060aSjmatthew 
1352765dc391Sjmatthew 	txring = (struct tx_bd_short *)BNXT_DMA_KVA(tx->tx_ring_mem);
1353a7c0060aSjmatthew 
1354765dc391Sjmatthew 	idx = tx->tx_ring_prod;
1355765dc391Sjmatthew 	free = tx->tx_ring_cons;
1356a7c0060aSjmatthew 	if (free <= idx)
1357765dc391Sjmatthew 		free += tx->tx_ring.ring_size;
1358a7c0060aSjmatthew 	free -= idx;
1359a7c0060aSjmatthew 
1360a7c0060aSjmatthew 	used = 0;
1361a7c0060aSjmatthew 
1362a7c0060aSjmatthew 	for (;;) {
1363af7e9c1bSjmatthew 		/* +1 for tx_bd_long_hi */
1364af7e9c1bSjmatthew 		if (used + BNXT_MAX_TX_SEGS + 1 > free) {
1365a7c0060aSjmatthew 			ifq_set_oactive(ifq);
1366a7c0060aSjmatthew 			break;
1367a7c0060aSjmatthew 		}
1368a7c0060aSjmatthew 
1369a7c0060aSjmatthew 		m = ifq_dequeue(ifq);
1370a7c0060aSjmatthew 		if (m == NULL)
1371a7c0060aSjmatthew 			break;
1372a7c0060aSjmatthew 
1373765dc391Sjmatthew 		bs = &tx->tx_slots[tx->tx_prod];
1374a7c0060aSjmatthew 		if (bnxt_load_mbuf(sc, bs, m) != 0) {
1375a7c0060aSjmatthew 			m_freem(m);
1376a7c0060aSjmatthew 			ifp->if_oerrors++;
1377a7c0060aSjmatthew 			continue;
1378a7c0060aSjmatthew 		}
1379a7c0060aSjmatthew 
1380a7c0060aSjmatthew #if NBPFILTER > 0
1381a7c0060aSjmatthew 		if (ifp->if_bpf)
1382a7c0060aSjmatthew 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
1383a7c0060aSjmatthew #endif
1384a7c0060aSjmatthew 		map = bs->bs_map;
1385a7c0060aSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1386a7c0060aSjmatthew 		    BUS_DMASYNC_PREWRITE);
1387af7e9c1bSjmatthew 		used += BNXT_TX_SLOTS(bs);
1388af7e9c1bSjmatthew 
1389af7e9c1bSjmatthew 		/* first segment */
1390af7e9c1bSjmatthew 		laststart = idx;
1391af7e9c1bSjmatthew 		txring[idx].len = htole16(map->dm_segs[0].ds_len);
1392765dc391Sjmatthew 		txring[idx].opaque = tx->tx_prod;
1393af7e9c1bSjmatthew 		txring[idx].addr = htole64(map->dm_segs[0].ds_addr);
13948a756155Sjmatthew 		if (m->m_pkthdr.csum_flags & M_TCP_TSO)
13958a756155Sjmatthew 			slen = m->m_pkthdr.ph_mss;
13968a756155Sjmatthew 		else
13978a756155Sjmatthew 			slen = map->dm_mapsize;
1398a7c0060aSjmatthew 
13998a756155Sjmatthew 		if (slen < 512)
1400af7e9c1bSjmatthew 			txflags = TX_BD_LONG_FLAGS_LHINT_LT512;
14018a756155Sjmatthew 		else if (slen < 1024)
1402af7e9c1bSjmatthew 			txflags = TX_BD_LONG_FLAGS_LHINT_LT1K;
14038a756155Sjmatthew 		else if (slen < 2048)
1404af7e9c1bSjmatthew 			txflags = TX_BD_LONG_FLAGS_LHINT_LT2K;
1405a7c0060aSjmatthew 		else
1406af7e9c1bSjmatthew 			txflags = TX_BD_LONG_FLAGS_LHINT_GTE2K;
1407af7e9c1bSjmatthew 		txflags |= TX_BD_LONG_TYPE_TX_BD_LONG |
14088490bd92Sjmatthew 		    TX_BD_LONG_FLAGS_NO_CMPL;
14098490bd92Sjmatthew 		txflags |= (BNXT_TX_SLOTS(bs) << TX_BD_LONG_FLAGS_BD_CNT_SFT) &
14108490bd92Sjmatthew 		    TX_BD_LONG_FLAGS_BD_CNT_MASK;
1411af7e9c1bSjmatthew 		if (map->dm_nsegs == 1)
1412af7e9c1bSjmatthew 			txflags |= TX_BD_SHORT_FLAGS_PACKET_END;
1413a7c0060aSjmatthew 		txring[idx].flags_type = htole16(txflags);
1414af7e9c1bSjmatthew 
1415af7e9c1bSjmatthew 		idx++;
1416765dc391Sjmatthew 		if (idx == tx->tx_ring.ring_size)
1417af7e9c1bSjmatthew 			idx = 0;
1418af7e9c1bSjmatthew 
1419af7e9c1bSjmatthew 		/* long tx descriptor */
1420af7e9c1bSjmatthew 		txhi = (struct tx_bd_long_hi *)&txring[idx];
1421af7e9c1bSjmatthew 		memset(txhi, 0, sizeof(*txhi));
14228a756155Sjmatthew 
14238a756155Sjmatthew 		lflags = 0;
14248a756155Sjmatthew 		if (m->m_pkthdr.csum_flags & M_TCP_TSO) {
14258a756155Sjmatthew 			uint16_t hdrsize;
14268a756155Sjmatthew 			uint32_t outlen;
14278a756155Sjmatthew 			uint32_t paylen;
14288a756155Sjmatthew 
14298a756155Sjmatthew 			ether_extract_headers(m, &ext);
14307f8ccd64Sjan 			if (ext.tcp && m->m_pkthdr.ph_mss > 0) {
14318a756155Sjmatthew 				lflags |= TX_BD_LONG_LFLAGS_LSO;
14328a756155Sjmatthew 				hdrsize = sizeof(*ext.eh);
1433ac5f541aSbluhm 				if (ext.ip4 || ext.ip6)
1434ac5f541aSbluhm 					hdrsize += ext.iphlen;
14358a756155Sjmatthew 				else
14368a756155Sjmatthew 					tcpstat_inc(tcps_outbadtso);
14378a756155Sjmatthew 
1438e78a66e5Sbluhm 				hdrsize += ext.tcphlen;
14398a756155Sjmatthew 				txhi->hdr_size = htole16(hdrsize / 2);
14408a756155Sjmatthew 
14418a756155Sjmatthew 				outlen = m->m_pkthdr.ph_mss;
14428a756155Sjmatthew 				txhi->mss = htole32(outlen);
14438a756155Sjmatthew 
14448a756155Sjmatthew 				paylen = m->m_pkthdr.len - hdrsize;
14458a756155Sjmatthew 				tcpstat_add(tcps_outpkttso,
14468a756155Sjmatthew 				    (paylen + outlen + 1) / outlen);
14478a756155Sjmatthew 			} else {
14488a756155Sjmatthew 				tcpstat_inc(tcps_outbadtso);
14498a756155Sjmatthew 			}
14508a756155Sjmatthew 		} else {
14518a756155Sjmatthew 			if (m->m_pkthdr.csum_flags & (M_UDP_CSUM_OUT |
14528a756155Sjmatthew 			    M_TCP_CSUM_OUT))
14538a756155Sjmatthew 				lflags |= TX_BD_LONG_LFLAGS_TCP_UDP_CHKSUM;
1454af7e9c1bSjmatthew 			if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
14558a756155Sjmatthew 				lflags |= TX_BD_LONG_LFLAGS_IP_CHKSUM;
14568a756155Sjmatthew 		}
14578a756155Sjmatthew 		txhi->lflags = htole16(lflags);
1458af7e9c1bSjmatthew 
1459870f5687Sjmatthew #if NVLAN > 0
1460af7e9c1bSjmatthew 		if (m->m_flags & M_VLANTAG) {
1461af7e9c1bSjmatthew 			txhi->cfa_meta = htole32(m->m_pkthdr.ether_vtag |
1462af7e9c1bSjmatthew 			    TX_BD_LONG_CFA_META_VLAN_TPID_TPID8100 |
1463af7e9c1bSjmatthew 			    TX_BD_LONG_CFA_META_KEY_VLAN_TAG);
1464af7e9c1bSjmatthew 		}
1465870f5687Sjmatthew #endif
1466af7e9c1bSjmatthew 
1467af7e9c1bSjmatthew 		idx++;
1468765dc391Sjmatthew 		if (idx == tx->tx_ring.ring_size)
1469af7e9c1bSjmatthew 			idx = 0;
1470af7e9c1bSjmatthew 
1471af7e9c1bSjmatthew 		/* remaining segments */
1472a7c0060aSjmatthew 		txflags = TX_BD_SHORT_TYPE_TX_BD_SHORT;
1473af7e9c1bSjmatthew 		for (i = 1; i < map->dm_nsegs; i++) {
1474af7e9c1bSjmatthew 			if (i == map->dm_nsegs - 1)
1475af7e9c1bSjmatthew 				txflags |= TX_BD_SHORT_FLAGS_PACKET_END;
1476af7e9c1bSjmatthew 			txring[idx].flags_type = htole16(txflags);
1477a7c0060aSjmatthew 
1478a7c0060aSjmatthew 			txring[idx].len =
1479a7c0060aSjmatthew 			    htole16(bs->bs_map->dm_segs[i].ds_len);
1480765dc391Sjmatthew 			txring[idx].opaque = tx->tx_prod;
1481a7c0060aSjmatthew 			txring[idx].addr =
1482a7c0060aSjmatthew 			    htole64(bs->bs_map->dm_segs[i].ds_addr);
1483a7c0060aSjmatthew 
1484a7c0060aSjmatthew 			idx++;
1485765dc391Sjmatthew 			if (idx == tx->tx_ring.ring_size)
1486a7c0060aSjmatthew 				idx = 0;
1487a7c0060aSjmatthew 		}
1488a7c0060aSjmatthew 
1489765dc391Sjmatthew 		if (++tx->tx_prod >= tx->tx_ring.ring_size)
1490765dc391Sjmatthew 			tx->tx_prod = 0;
1491a7c0060aSjmatthew 	}
1492a7c0060aSjmatthew 
1493058d3950Sjmatthew 	/* unset NO_CMPL on the first bd of the last packet */
1494058d3950Sjmatthew 	if (used != 0) {
1495058d3950Sjmatthew 		txring[laststart].flags_type &=
1496058d3950Sjmatthew 		    ~htole16(TX_BD_SHORT_FLAGS_NO_CMPL);
1497058d3950Sjmatthew 	}
1498058d3950Sjmatthew 
1499765dc391Sjmatthew 	bnxt_write_tx_doorbell(sc, &tx->tx_ring, idx);
1500765dc391Sjmatthew 	tx->tx_ring_prod = idx;
1501a7c0060aSjmatthew }
1502a7c0060aSjmatthew 
1503a7c0060aSjmatthew void
1504a7c0060aSjmatthew bnxt_handle_async_event(struct bnxt_softc *sc, struct cmpl_base *cmpl)
1505a7c0060aSjmatthew {
1506a7c0060aSjmatthew 	struct hwrm_async_event_cmpl *ae = (struct hwrm_async_event_cmpl *)cmpl;
1507a7c0060aSjmatthew 	uint16_t type = le16toh(ae->event_id);
1508a7c0060aSjmatthew 
1509a7c0060aSjmatthew 	switch (type) {
1510a7c0060aSjmatthew 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
1511a7c0060aSjmatthew 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE:
1512a7c0060aSjmatthew 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE:
1513a7c0060aSjmatthew 		bnxt_hwrm_port_phy_qcfg(sc, NULL);
1514a7c0060aSjmatthew 		break;
1515a7c0060aSjmatthew 
1516a7c0060aSjmatthew 	default:
1517a7c0060aSjmatthew 		printf("%s: unexpected async event %x\n", DEVNAME(sc), type);
1518a7c0060aSjmatthew 		break;
1519a7c0060aSjmatthew 	}
1520a7c0060aSjmatthew }
1521a7c0060aSjmatthew 
1522c4f53494Sjmatthew struct cmpl_base *
1523c4f53494Sjmatthew bnxt_cpr_next_cmpl(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr)
1524c4f53494Sjmatthew {
1525c4f53494Sjmatthew 	struct cmpl_base *cmpl;
1526c4f53494Sjmatthew 	uint32_t cons;
1527c4f53494Sjmatthew 	int v_bit;
1528c4f53494Sjmatthew 
1529c4f53494Sjmatthew 	cons = cpr->cons + 1;
1530c4f53494Sjmatthew 	v_bit = cpr->v_bit;
1531c4f53494Sjmatthew 	if (cons == cpr->ring.ring_size) {
1532c4f53494Sjmatthew 		cons = 0;
1533c4f53494Sjmatthew 		v_bit = !v_bit;
1534c4f53494Sjmatthew 	}
1535c4f53494Sjmatthew 	cmpl = &((struct cmpl_base *)cpr->ring.vaddr)[cons];
1536c4f53494Sjmatthew 
1537c4f53494Sjmatthew 	if ((!!(cmpl->info3_v & htole32(CMPL_BASE_V))) != (!!v_bit))
1538c4f53494Sjmatthew 		return (NULL);
1539c4f53494Sjmatthew 
1540c4f53494Sjmatthew 	cpr->cons = cons;
1541c4f53494Sjmatthew 	cpr->v_bit = v_bit;
1542c4f53494Sjmatthew 	return (cmpl);
1543c4f53494Sjmatthew }
1544c4f53494Sjmatthew 
1545c4f53494Sjmatthew void
1546c4f53494Sjmatthew bnxt_cpr_commit(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr)
1547c4f53494Sjmatthew {
1548c4f53494Sjmatthew 	cpr->commit_cons = cpr->cons;
1549c4f53494Sjmatthew 	cpr->commit_v_bit = cpr->v_bit;
1550c4f53494Sjmatthew }
1551c4f53494Sjmatthew 
1552c4f53494Sjmatthew void
1553c4f53494Sjmatthew bnxt_cpr_rollback(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr)
1554c4f53494Sjmatthew {
1555c4f53494Sjmatthew 	cpr->cons = cpr->commit_cons;
1556c4f53494Sjmatthew 	cpr->v_bit = cpr->commit_v_bit;
1557c4f53494Sjmatthew }
1558c4f53494Sjmatthew 
1559a7c0060aSjmatthew int
1560765dc391Sjmatthew bnxt_admin_intr(void *xsc)
1561a7c0060aSjmatthew {
1562a7c0060aSjmatthew 	struct bnxt_softc *sc = (struct bnxt_softc *)xsc;
1563a7c0060aSjmatthew 	struct bnxt_cp_ring *cpr = &sc->sc_cp_ring;
1564c4f53494Sjmatthew 	struct cmpl_base *cmpl;
1565765dc391Sjmatthew 	uint16_t type;
1566765dc391Sjmatthew 
1567765dc391Sjmatthew 	bnxt_write_cp_doorbell(sc, &cpr->ring, 0);
1568765dc391Sjmatthew 	cmpl = bnxt_cpr_next_cmpl(sc, cpr);
1569765dc391Sjmatthew 	while (cmpl != NULL) {
1570765dc391Sjmatthew 		type = le16toh(cmpl->type) & CMPL_BASE_TYPE_MASK;
1571765dc391Sjmatthew 		switch (type) {
1572765dc391Sjmatthew 		case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
1573765dc391Sjmatthew 			bnxt_handle_async_event(sc, cmpl);
1574765dc391Sjmatthew 			break;
1575765dc391Sjmatthew 		default:
1576765dc391Sjmatthew 			printf("%s: unexpected completion type %u\n",
1577765dc391Sjmatthew 			    DEVNAME(sc), type);
1578765dc391Sjmatthew 		}
1579765dc391Sjmatthew 
1580765dc391Sjmatthew 		bnxt_cpr_commit(sc, cpr);
1581765dc391Sjmatthew 		cmpl = bnxt_cpr_next_cmpl(sc, cpr);
1582765dc391Sjmatthew 	}
1583765dc391Sjmatthew 
1584765dc391Sjmatthew 	bnxt_write_cp_doorbell_index(sc, &cpr->ring,
1585765dc391Sjmatthew 	    (cpr->commit_cons+1) % cpr->ring.ring_size, 1);
1586765dc391Sjmatthew 	return (1);
1587765dc391Sjmatthew }
1588765dc391Sjmatthew 
1589765dc391Sjmatthew int
1590765dc391Sjmatthew bnxt_intr(void *xq)
1591765dc391Sjmatthew {
1592765dc391Sjmatthew 	struct bnxt_queue *q = (struct bnxt_queue *)xq;
1593765dc391Sjmatthew 	struct bnxt_softc *sc = q->q_sc;
159418f50744Sbluhm 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1595765dc391Sjmatthew 	struct bnxt_cp_ring *cpr = &q->q_cp;
1596765dc391Sjmatthew 	struct bnxt_rx_queue *rx = &q->q_rx;
1597765dc391Sjmatthew 	struct bnxt_tx_queue *tx = &q->q_tx;
1598765dc391Sjmatthew 	struct cmpl_base *cmpl;
1599a7c0060aSjmatthew 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1600a7c0060aSjmatthew 	uint16_t type;
1601c4f53494Sjmatthew 	int rxfree, txfree, agfree, rv, rollback;
1602a7c0060aSjmatthew 
1603a7c0060aSjmatthew 	bnxt_write_cp_doorbell(sc, &cpr->ring, 0);
1604a7c0060aSjmatthew 	rxfree = 0;
1605a7c0060aSjmatthew 	txfree = 0;
1606c4f53494Sjmatthew 	agfree = 0;
160703373e89Sjmatthew 	rv = -1;
1608c4f53494Sjmatthew 	cmpl = bnxt_cpr_next_cmpl(sc, cpr);
1609c4f53494Sjmatthew 	while (cmpl != NULL) {
1610a7c0060aSjmatthew 		type = le16toh(cmpl->type) & CMPL_BASE_TYPE_MASK;
1611c4f53494Sjmatthew 		rollback = 0;
1612a7c0060aSjmatthew 		switch (type) {
1613a7c0060aSjmatthew 		case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
1614a7c0060aSjmatthew 			bnxt_handle_async_event(sc, cmpl);
1615a7c0060aSjmatthew 			break;
1616a7c0060aSjmatthew 		case CMPL_BASE_TYPE_RX_L2:
161718f50744Sbluhm 			if (ISSET(ifp->if_flags, IFF_RUNNING))
161818f50744Sbluhm 				rollback = bnxt_rx(sc, rx, cpr, &ml, &rxfree,
161918f50744Sbluhm 				    &agfree, cmpl);
1620a7c0060aSjmatthew 			break;
1621a7c0060aSjmatthew 		case CMPL_BASE_TYPE_TX_L2:
162218f50744Sbluhm 			if (ISSET(ifp->if_flags, IFF_RUNNING))
1623765dc391Sjmatthew 				bnxt_txeof(sc, tx, &txfree, cmpl);
1624a7c0060aSjmatthew 			break;
1625a7c0060aSjmatthew 		default:
1626a7c0060aSjmatthew 			printf("%s: unexpected completion type %u\n",
1627a7c0060aSjmatthew 			    DEVNAME(sc), type);
1628a7c0060aSjmatthew 		}
1629a7c0060aSjmatthew 
1630c4f53494Sjmatthew 		if (rollback) {
1631c4f53494Sjmatthew 			bnxt_cpr_rollback(sc, cpr);
1632c4f53494Sjmatthew 			break;
1633c4f53494Sjmatthew 		}
1634c4f53494Sjmatthew 		rv = 1;
1635c4f53494Sjmatthew 		bnxt_cpr_commit(sc, cpr);
1636c4f53494Sjmatthew 		cmpl = bnxt_cpr_next_cmpl(sc, cpr);
1637c4f53494Sjmatthew 	}
1638a7c0060aSjmatthew 
1639a7c0060aSjmatthew 	/*
1640a7c0060aSjmatthew 	 * comments in bnxtreg.h suggest we should be writing cpr->cons here,
1641a7c0060aSjmatthew 	 * but writing cpr->cons + 1 makes it stop interrupting.
1642a7c0060aSjmatthew 	 */
1643a7c0060aSjmatthew 	bnxt_write_cp_doorbell_index(sc, &cpr->ring,
1644c4f53494Sjmatthew 	    (cpr->commit_cons+1) % cpr->ring.ring_size, 1);
1645a7c0060aSjmatthew 
1646a7c0060aSjmatthew 	if (rxfree != 0) {
1647765dc391Sjmatthew 		rx->rx_cons += rxfree;
1648765dc391Sjmatthew 		if (rx->rx_cons >= rx->rx_ring.ring_size)
1649765dc391Sjmatthew 			rx->rx_cons -= rx->rx_ring.ring_size;
1650a7c0060aSjmatthew 
1651765dc391Sjmatthew 		rx->rx_ag_cons += agfree;
1652765dc391Sjmatthew 		if (rx->rx_ag_cons >= rx->rx_ag_ring.ring_size)
1653765dc391Sjmatthew 			rx->rx_ag_cons -= rx->rx_ag_ring.ring_size;
1654c4f53494Sjmatthew 
1655765dc391Sjmatthew 		if_rxr_put(&rx->rxr[0], rxfree);
1656765dc391Sjmatthew 		if_rxr_put(&rx->rxr[1], agfree);
1657a7c0060aSjmatthew 
1658765dc391Sjmatthew 		if (ifiq_input(rx->rx_ifiq, &ml)) {
1659765dc391Sjmatthew 			if_rxr_livelocked(&rx->rxr[0]);
1660765dc391Sjmatthew 			if_rxr_livelocked(&rx->rxr[1]);
1661447a2df6Sdlg 		}
1662447a2df6Sdlg 
1663765dc391Sjmatthew 		bnxt_rx_fill(q);
1664*2783188aSjmatthew 		bnxt_rx_fill_ag(q);
1665765dc391Sjmatthew 		if ((rx->rx_cons == rx->rx_prod) ||
1666765dc391Sjmatthew 		    (rx->rx_ag_cons == rx->rx_ag_prod))
1667765dc391Sjmatthew 			timeout_add(&rx->rx_refill, 0);
1668a7c0060aSjmatthew 	}
1669a7c0060aSjmatthew 	if (txfree != 0) {
1670765dc391Sjmatthew 		if (ifq_is_oactive(tx->tx_ifq))
1671765dc391Sjmatthew 			ifq_restart(tx->tx_ifq);
1672a7c0060aSjmatthew 	}
167303373e89Sjmatthew 	return (rv);
1674a7c0060aSjmatthew }
1675a7c0060aSjmatthew 
1676a7c0060aSjmatthew void
1677a7c0060aSjmatthew bnxt_watchdog(struct ifnet *ifp)
1678a7c0060aSjmatthew {
1679a7c0060aSjmatthew }
1680a7c0060aSjmatthew 
1681a7c0060aSjmatthew void
1682a7c0060aSjmatthew bnxt_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1683a7c0060aSjmatthew {
1684a7c0060aSjmatthew 	struct bnxt_softc *sc = (struct bnxt_softc *)ifp->if_softc;
1685a7c0060aSjmatthew 	bnxt_hwrm_port_phy_qcfg(sc, ifmr);
1686a7c0060aSjmatthew }
1687a7c0060aSjmatthew 
1688d256ca68Sjmatthew uint64_t
1689d256ca68Sjmatthew bnxt_get_media_type(uint64_t speed, int phy_type)
1690d256ca68Sjmatthew {
1691d256ca68Sjmatthew 	switch (phy_type) {
169252c4f284Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_UNKNOWN:
1693d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASECR:
1694d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_L:
1695d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_S:
1696d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_N:
1697d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASECR4:
1698d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASECR4:
1699d256ca68Sjmatthew 		switch (speed) {
1700d256ca68Sjmatthew 		case IF_Gbps(1):
1701d256ca68Sjmatthew 			return IFM_1000_T;
1702d256ca68Sjmatthew 		case IF_Gbps(10):
1703d256ca68Sjmatthew 			return IFM_10G_SFP_CU;
1704d256ca68Sjmatthew 		case IF_Gbps(25):
1705d256ca68Sjmatthew 			return IFM_25G_CR;
1706d256ca68Sjmatthew 		case IF_Gbps(40):
1707d256ca68Sjmatthew 			return IFM_40G_CR4;
1708d256ca68Sjmatthew 		case IF_Gbps(50):
1709d256ca68Sjmatthew 			return IFM_50G_CR2;
1710d256ca68Sjmatthew 		case IF_Gbps(100):
1711d256ca68Sjmatthew 			return IFM_100G_CR4;
1712d256ca68Sjmatthew 		}
1713d256ca68Sjmatthew 		break;
1714d256ca68Sjmatthew 
1715d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASELR:
1716d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASELR4:
1717d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASELR4:
1718d256ca68Sjmatthew 		switch (speed) {
1719d256ca68Sjmatthew 		case IF_Gbps(1):
1720d256ca68Sjmatthew 			return IFM_1000_LX;
1721d256ca68Sjmatthew 		case IF_Gbps(10):
1722d256ca68Sjmatthew 			return IFM_10G_LR;
1723d256ca68Sjmatthew 		case IF_Gbps(25):
1724d256ca68Sjmatthew 			return IFM_25G_LR;
1725d256ca68Sjmatthew 		case IF_Gbps(40):
1726d256ca68Sjmatthew 			return IFM_40G_LR4;
1727d256ca68Sjmatthew 		case IF_Gbps(100):
1728d256ca68Sjmatthew 			return IFM_100G_LR4;
1729d256ca68Sjmatthew 		}
1730d256ca68Sjmatthew 		break;
1731d256ca68Sjmatthew 
1732d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASESR:
1733d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASESR:
1734d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASESR4:
1735d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASESR10:
1736d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_1G_BASESX:
1737d256ca68Sjmatthew 		switch (speed) {
1738d256ca68Sjmatthew 		case IF_Gbps(1):
1739d256ca68Sjmatthew 			return IFM_1000_SX;
1740d256ca68Sjmatthew 		case IF_Gbps(10):
1741d256ca68Sjmatthew 			return IFM_10G_SR;
1742d256ca68Sjmatthew 		case IF_Gbps(25):
1743d256ca68Sjmatthew 			return IFM_25G_SR;
1744d256ca68Sjmatthew 		case IF_Gbps(40):
1745d256ca68Sjmatthew 			return IFM_40G_SR4;
1746d256ca68Sjmatthew 		case IF_Gbps(100):
1747d256ca68Sjmatthew 			return IFM_100G_SR4;
1748d256ca68Sjmatthew 		}
1749d256ca68Sjmatthew 		break;
1750d256ca68Sjmatthew 
1751d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASEER4:
1752d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASEER4:
1753d256ca68Sjmatthew 		switch (speed) {
1754d256ca68Sjmatthew 		case IF_Gbps(10):
1755d256ca68Sjmatthew 			return IFM_10G_ER;
1756d256ca68Sjmatthew 		case IF_Gbps(25):
1757d256ca68Sjmatthew 			return IFM_25G_ER;
1758d256ca68Sjmatthew 		}
1759d256ca68Sjmatthew 		/* missing IFM_40G_ER4, IFM_100G_ER4 */
1760d256ca68Sjmatthew 		break;
1761d256ca68Sjmatthew 
1762d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR4:
1763d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR2:
1764d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR:
1765d256ca68Sjmatthew 		switch (speed) {
1766d256ca68Sjmatthew 		case IF_Gbps(10):
1767d256ca68Sjmatthew 			return IFM_10G_KR;
1768d256ca68Sjmatthew 		case IF_Gbps(20):
1769d256ca68Sjmatthew 			return IFM_20G_KR2;
1770d256ca68Sjmatthew 		case IF_Gbps(25):
1771d256ca68Sjmatthew 			return IFM_25G_KR;
1772d256ca68Sjmatthew 		case IF_Gbps(40):
1773d256ca68Sjmatthew 			return IFM_40G_KR4;
1774d256ca68Sjmatthew 		case IF_Gbps(50):
1775d256ca68Sjmatthew 			return IFM_50G_KR2;
1776d256ca68Sjmatthew 		case IF_Gbps(100):
1777d256ca68Sjmatthew 			return IFM_100G_KR4;
1778d256ca68Sjmatthew 		}
1779d256ca68Sjmatthew 		break;
1780d256ca68Sjmatthew 
1781d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKX:
1782d256ca68Sjmatthew 		switch (speed) {
1783d256ca68Sjmatthew 		case IF_Gbps(1):
1784d256ca68Sjmatthew 			return IFM_1000_KX;
1785d256ca68Sjmatthew 		case IF_Mbps(2500):
1786d256ca68Sjmatthew 			return IFM_2500_KX;
1787d256ca68Sjmatthew 		case IF_Gbps(10):
1788d256ca68Sjmatthew 			return IFM_10G_KX4;
1789d256ca68Sjmatthew 		}
1790d256ca68Sjmatthew 		break;
1791d256ca68Sjmatthew 
1792d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASET:
1793d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASETE:
1794d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_1G_BASET:
1795d256ca68Sjmatthew 		switch (speed) {
1796d256ca68Sjmatthew 		case IF_Mbps(10):
1797d256ca68Sjmatthew 			return IFM_10_T;
1798d256ca68Sjmatthew 		case IF_Mbps(100):
1799d256ca68Sjmatthew 			return IFM_100_TX;
1800d256ca68Sjmatthew 		case IF_Gbps(1):
1801d256ca68Sjmatthew 			return IFM_1000_T;
1802d256ca68Sjmatthew 		case IF_Mbps(2500):
1803d256ca68Sjmatthew 			return IFM_2500_T;
1804d256ca68Sjmatthew 		case IF_Gbps(10):
1805d256ca68Sjmatthew 			return IFM_10G_T;
1806d256ca68Sjmatthew 		}
1807d256ca68Sjmatthew 		break;
1808d256ca68Sjmatthew 
1809d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_SGMIIEXTPHY:
1810d256ca68Sjmatthew 		switch (speed) {
1811d256ca68Sjmatthew 		case IF_Gbps(1):
1812d256ca68Sjmatthew 			return IFM_1000_SGMII;
1813d256ca68Sjmatthew 		}
1814d256ca68Sjmatthew 		break;
1815d256ca68Sjmatthew 
1816d256ca68Sjmatthew 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_ACTIVE_CABLE:
1817d256ca68Sjmatthew 		switch (speed) {
1818d256ca68Sjmatthew 		case IF_Gbps(10):
1819d256ca68Sjmatthew 			return IFM_10G_AOC;
1820d256ca68Sjmatthew 		case IF_Gbps(25):
1821d256ca68Sjmatthew 			return IFM_25G_AOC;
1822d256ca68Sjmatthew 		case IF_Gbps(40):
1823d256ca68Sjmatthew 			return IFM_40G_AOC;
1824d256ca68Sjmatthew 		case IF_Gbps(100):
1825d256ca68Sjmatthew 			return IFM_100G_AOC;
1826d256ca68Sjmatthew 		}
1827d256ca68Sjmatthew 		break;
1828d256ca68Sjmatthew 	}
1829d256ca68Sjmatthew 
1830d256ca68Sjmatthew 	return 0;
1831d256ca68Sjmatthew }
1832d256ca68Sjmatthew 
1833d256ca68Sjmatthew void
1834d256ca68Sjmatthew bnxt_add_media_type(struct bnxt_softc *sc, int supported_speeds, uint64_t speed, uint64_t ifmt)
1835d256ca68Sjmatthew {
1836d256ca68Sjmatthew 	int speed_bit = 0;
1837d256ca68Sjmatthew 	switch (speed) {
1838d256ca68Sjmatthew 	case IF_Gbps(1):
1839d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_1GB;
1840d256ca68Sjmatthew 		break;
1841d256ca68Sjmatthew 	case IF_Gbps(2):
1842d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_2GB;
1843d256ca68Sjmatthew 		break;
1844d256ca68Sjmatthew 	case IF_Mbps(2500):
1845d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_2_5GB;
1846d256ca68Sjmatthew 		break;
1847d256ca68Sjmatthew 	case IF_Gbps(10):
1848d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_10GB;
1849d256ca68Sjmatthew 		break;
1850d256ca68Sjmatthew 	case IF_Gbps(20):
1851d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_20GB;
1852d256ca68Sjmatthew 		break;
1853d256ca68Sjmatthew 	case IF_Gbps(25):
1854d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_25GB;
1855d256ca68Sjmatthew 		break;
1856d256ca68Sjmatthew 	case IF_Gbps(40):
1857d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_40GB;
1858d256ca68Sjmatthew 		break;
1859d256ca68Sjmatthew 	case IF_Gbps(50):
1860d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_50GB;
1861d256ca68Sjmatthew 		break;
1862d256ca68Sjmatthew 	case IF_Gbps(100):
1863d256ca68Sjmatthew 		speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_100GB;
1864d256ca68Sjmatthew 		break;
1865d256ca68Sjmatthew 	}
1866d256ca68Sjmatthew 	if (supported_speeds & speed_bit)
1867d256ca68Sjmatthew 		ifmedia_add(&sc->sc_media, IFM_ETHER | ifmt, 0, NULL);
1868d256ca68Sjmatthew }
1869d256ca68Sjmatthew 
1870d256ca68Sjmatthew int
1871d256ca68Sjmatthew bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc, struct ifmediareq *ifmr)
1872d256ca68Sjmatthew {
1873d256ca68Sjmatthew 	struct ifnet *ifp = &softc->sc_ac.ac_if;
1874d256ca68Sjmatthew 	struct hwrm_port_phy_qcfg_input req = {0};
1875d256ca68Sjmatthew 	struct hwrm_port_phy_qcfg_output *resp =
1876d256ca68Sjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
1877d256ca68Sjmatthew 	int link_state = LINK_STATE_DOWN;
18780f734ffcSjmatthew 	uint64_t speeds[] = {
1879d256ca68Sjmatthew 		IF_Gbps(1), IF_Gbps(2), IF_Mbps(2500), IF_Gbps(10), IF_Gbps(20),
1880d256ca68Sjmatthew 		IF_Gbps(25), IF_Gbps(40), IF_Gbps(50), IF_Gbps(100)
1881d256ca68Sjmatthew 	};
1882d256ca68Sjmatthew 	uint64_t media_type;
188392586e53Sjmatthew 	int duplex;
1884d256ca68Sjmatthew 	int rc = 0;
1885d256ca68Sjmatthew 	int i;
1886d256ca68Sjmatthew 
1887d256ca68Sjmatthew 	BNXT_HWRM_LOCK(softc);
1888d256ca68Sjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_QCFG);
1889d256ca68Sjmatthew 
1890d256ca68Sjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1891d256ca68Sjmatthew 	if (rc) {
1892d256ca68Sjmatthew 		printf("%s: failed to query port phy config\n", DEVNAME(softc));
1893d256ca68Sjmatthew 		goto exit;
1894d256ca68Sjmatthew 	}
1895d256ca68Sjmatthew 
189692586e53Sjmatthew 	if (softc->sc_hwrm_ver > 0x10800)
189792586e53Sjmatthew 		duplex = resp->duplex_state;
189892586e53Sjmatthew 	else
189992586e53Sjmatthew 		duplex = resp->duplex_cfg;
190092586e53Sjmatthew 
1901d256ca68Sjmatthew 	if (resp->link == HWRM_PORT_PHY_QCFG_OUTPUT_LINK_LINK) {
190292586e53Sjmatthew 		if (duplex == HWRM_PORT_PHY_QCFG_OUTPUT_DUPLEX_STATE_HALF)
1903d256ca68Sjmatthew 			link_state = LINK_STATE_HALF_DUPLEX;
1904d256ca68Sjmatthew 		else
1905d256ca68Sjmatthew 			link_state = LINK_STATE_FULL_DUPLEX;
1906d256ca68Sjmatthew 
1907d256ca68Sjmatthew 		switch (resp->link_speed) {
1908d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_10MB:
1909d256ca68Sjmatthew 			ifp->if_baudrate = IF_Mbps(10);
1910d256ca68Sjmatthew 			break;
1911d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_100MB:
1912d256ca68Sjmatthew 			ifp->if_baudrate = IF_Mbps(100);
1913d256ca68Sjmatthew 			break;
1914d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_1GB:
1915d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(1);
1916d256ca68Sjmatthew 			break;
1917d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_2GB:
1918d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(2);
1919d256ca68Sjmatthew 			break;
1920d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_2_5GB:
1921d256ca68Sjmatthew 			ifp->if_baudrate = IF_Mbps(2500);
1922d256ca68Sjmatthew 			break;
1923d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_10GB:
1924d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(10);
1925d256ca68Sjmatthew 			break;
1926d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_20GB:
1927d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(20);
1928d256ca68Sjmatthew 			break;
1929d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_25GB:
1930d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(25);
1931d256ca68Sjmatthew 			break;
1932d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_40GB:
1933d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(40);
1934d256ca68Sjmatthew 			break;
1935d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_50GB:
1936d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(50);
1937d256ca68Sjmatthew 			break;
1938d256ca68Sjmatthew 		case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_100GB:
1939d256ca68Sjmatthew 			ifp->if_baudrate = IF_Gbps(100);
1940d256ca68Sjmatthew 			break;
1941d256ca68Sjmatthew 		}
1942d256ca68Sjmatthew 	}
1943d256ca68Sjmatthew 
1944d256ca68Sjmatthew 	ifmedia_delete_instance(&softc->sc_media, IFM_INST_ANY);
1945d256ca68Sjmatthew 	for (i = 0; i < nitems(speeds); i++) {
1946d256ca68Sjmatthew 		media_type = bnxt_get_media_type(speeds[i], resp->phy_type);
1947d256ca68Sjmatthew 		if (media_type != 0)
1948d256ca68Sjmatthew 			bnxt_add_media_type(softc, resp->support_speeds,
1949d256ca68Sjmatthew 			    speeds[i], media_type);
1950d256ca68Sjmatthew 	}
1951d256ca68Sjmatthew 	ifmedia_add(&softc->sc_media, IFM_ETHER|IFM_AUTO, 0, NULL);
1952d256ca68Sjmatthew 	ifmedia_set(&softc->sc_media, IFM_ETHER|IFM_AUTO);
1953d256ca68Sjmatthew 
1954d256ca68Sjmatthew 	if (ifmr != NULL) {
1955d256ca68Sjmatthew 		ifmr->ifm_status = IFM_AVALID;
1956d256ca68Sjmatthew 		if (LINK_STATE_IS_UP(ifp->if_link_state)) {
1957d256ca68Sjmatthew 			ifmr->ifm_status |= IFM_ACTIVE;
1958d256ca68Sjmatthew 			ifmr->ifm_active = IFM_ETHER | IFM_AUTO;
1959d256ca68Sjmatthew 			if (resp->pause & HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX)
1960d256ca68Sjmatthew 				ifmr->ifm_active |= IFM_ETH_TXPAUSE;
1961d256ca68Sjmatthew 			if (resp->pause & HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)
1962d256ca68Sjmatthew 				ifmr->ifm_active |= IFM_ETH_RXPAUSE;
196392586e53Sjmatthew 			if (duplex == HWRM_PORT_PHY_QCFG_OUTPUT_DUPLEX_STATE_HALF)
1964d256ca68Sjmatthew 				ifmr->ifm_active |= IFM_HDX;
1965d256ca68Sjmatthew 			else
1966d256ca68Sjmatthew 				ifmr->ifm_active |= IFM_FDX;
1967d256ca68Sjmatthew 
1968d256ca68Sjmatthew 			media_type = bnxt_get_media_type(ifp->if_baudrate, resp->phy_type);
1969d256ca68Sjmatthew 			if (media_type != 0)
1970d256ca68Sjmatthew 				ifmr->ifm_active |= media_type;
1971d256ca68Sjmatthew 		}
1972d256ca68Sjmatthew 	}
1973d256ca68Sjmatthew 
1974d256ca68Sjmatthew exit:
1975d256ca68Sjmatthew 	BNXT_HWRM_UNLOCK(softc);
1976d256ca68Sjmatthew 
1977d256ca68Sjmatthew 	if (rc == 0 && (link_state != ifp->if_link_state)) {
1978d256ca68Sjmatthew 		ifp->if_link_state = link_state;
1979d256ca68Sjmatthew 		if_link_state_change(ifp);
1980d256ca68Sjmatthew 	}
1981d256ca68Sjmatthew 
1982d256ca68Sjmatthew 	return rc;
1983d256ca68Sjmatthew }
1984d256ca68Sjmatthew 
1985a7c0060aSjmatthew int
1986a7c0060aSjmatthew bnxt_media_change(struct ifnet *ifp)
1987a7c0060aSjmatthew {
1988d256ca68Sjmatthew 	struct bnxt_softc *sc = (struct bnxt_softc *)ifp->if_softc;
1989d256ca68Sjmatthew 	struct hwrm_port_phy_cfg_input req = {0};
1990d256ca68Sjmatthew 	uint64_t link_speed;
1991d256ca68Sjmatthew 
1992d256ca68Sjmatthew 	if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER)
1993d256ca68Sjmatthew 		return EINVAL;
1994d256ca68Sjmatthew 
1995d256ca68Sjmatthew 	if (sc->sc_flags & BNXT_FLAG_NPAR)
1996d256ca68Sjmatthew 		return ENODEV;
1997d256ca68Sjmatthew 
1998d256ca68Sjmatthew 	bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_PORT_PHY_CFG);
1999d256ca68Sjmatthew 
2000d256ca68Sjmatthew 	switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) {
2001d256ca68Sjmatthew 	case IFM_100G_CR4:
2002d256ca68Sjmatthew 	case IFM_100G_SR4:
2003d256ca68Sjmatthew 	case IFM_100G_KR4:
2004d256ca68Sjmatthew 	case IFM_100G_LR4:
2005d256ca68Sjmatthew 	case IFM_100G_AOC:
2006d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_100GB;
2007d256ca68Sjmatthew 		break;
2008d256ca68Sjmatthew 
2009d256ca68Sjmatthew 	case IFM_50G_CR2:
2010d256ca68Sjmatthew 	case IFM_50G_KR2:
2011d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_50GB;
2012d256ca68Sjmatthew 		break;
2013d256ca68Sjmatthew 
2014d256ca68Sjmatthew 	case IFM_40G_CR4:
2015d256ca68Sjmatthew 	case IFM_40G_SR4:
2016d256ca68Sjmatthew 	case IFM_40G_LR4:
2017d256ca68Sjmatthew 	case IFM_40G_KR4:
2018d256ca68Sjmatthew 	case IFM_40G_AOC:
2019d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_40GB;
2020d256ca68Sjmatthew 		break;
2021d256ca68Sjmatthew 
2022d256ca68Sjmatthew 	case IFM_25G_CR:
2023d256ca68Sjmatthew 	case IFM_25G_KR:
2024d256ca68Sjmatthew 	case IFM_25G_SR:
2025d256ca68Sjmatthew 	case IFM_25G_LR:
2026d256ca68Sjmatthew 	case IFM_25G_ER:
2027d256ca68Sjmatthew 	case IFM_25G_AOC:
2028d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_25GB;
2029d256ca68Sjmatthew 		break;
2030d256ca68Sjmatthew 
2031d256ca68Sjmatthew 	case IFM_10G_LR:
2032d256ca68Sjmatthew 	case IFM_10G_SR:
2033d256ca68Sjmatthew 	case IFM_10G_CX4:
2034d256ca68Sjmatthew 	case IFM_10G_T:
2035d256ca68Sjmatthew 	case IFM_10G_SFP_CU:
2036d256ca68Sjmatthew 	case IFM_10G_LRM:
2037d256ca68Sjmatthew 	case IFM_10G_KX4:
2038d256ca68Sjmatthew 	case IFM_10G_KR:
2039d256ca68Sjmatthew 	case IFM_10G_CR1:
2040d256ca68Sjmatthew 	case IFM_10G_ER:
2041d256ca68Sjmatthew 	case IFM_10G_AOC:
2042d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_10GB;
2043d256ca68Sjmatthew 		break;
2044d256ca68Sjmatthew 
2045d256ca68Sjmatthew 	case IFM_2500_SX:
2046d256ca68Sjmatthew 	case IFM_2500_KX:
2047d256ca68Sjmatthew 	case IFM_2500_T:
2048d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_2_5GB;
2049d256ca68Sjmatthew 		break;
2050d256ca68Sjmatthew 
2051d256ca68Sjmatthew 	case IFM_1000_T:
2052d256ca68Sjmatthew 	case IFM_1000_LX:
2053d256ca68Sjmatthew 	case IFM_1000_SX:
2054d256ca68Sjmatthew 	case IFM_1000_CX:
2055d256ca68Sjmatthew 	case IFM_1000_KX:
2056d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_1GB;
2057d256ca68Sjmatthew 		break;
2058d256ca68Sjmatthew 
2059d256ca68Sjmatthew 	case IFM_100_TX:
2060d256ca68Sjmatthew 		link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_100MB;
2061d256ca68Sjmatthew 		break;
2062d256ca68Sjmatthew 
2063d256ca68Sjmatthew 	default:
2064d256ca68Sjmatthew 		link_speed = 0;
2065d256ca68Sjmatthew 	}
2066d256ca68Sjmatthew 
206792586e53Sjmatthew 	req.enables |= htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_DUPLEX);
206892586e53Sjmatthew 	req.auto_duplex = HWRM_PORT_PHY_CFG_INPUT_AUTO_DUPLEX_BOTH;
2069d256ca68Sjmatthew 	if (link_speed == 0) {
2070d256ca68Sjmatthew 		req.auto_mode |=
2071d256ca68Sjmatthew 		    HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ALL_SPEEDS;
2072d256ca68Sjmatthew 		req.flags |=
2073d256ca68Sjmatthew 		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG);
2074d256ca68Sjmatthew 		req.enables |=
2075d256ca68Sjmatthew 		    htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE);
2076d256ca68Sjmatthew 	} else {
2077d256ca68Sjmatthew 		req.force_link_speed = htole16(link_speed);
2078d256ca68Sjmatthew 		req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE);
2079d256ca68Sjmatthew 	}
2080d256ca68Sjmatthew 	req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY);
2081d256ca68Sjmatthew 
2082d256ca68Sjmatthew 	return hwrm_send_message(sc, &req, sizeof(req));
2083a7c0060aSjmatthew }
2084a7c0060aSjmatthew 
2085c6900e6bSjmatthew int
2086c6900e6bSjmatthew bnxt_media_autonegotiate(struct bnxt_softc *sc)
2087c6900e6bSjmatthew {
2088c6900e6bSjmatthew 	struct hwrm_port_phy_cfg_input req = {0};
2089c6900e6bSjmatthew 
2090c6900e6bSjmatthew 	if (sc->sc_flags & BNXT_FLAG_NPAR)
2091c6900e6bSjmatthew 		return ENODEV;
2092c6900e6bSjmatthew 
2093c6900e6bSjmatthew 	bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_PORT_PHY_CFG);
2094c6900e6bSjmatthew 	req.auto_mode |= HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ALL_SPEEDS;
209592586e53Sjmatthew 	req.auto_duplex = HWRM_PORT_PHY_CFG_INPUT_AUTO_DUPLEX_BOTH;
209692586e53Sjmatthew 	req.enables |= htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE |
209792586e53Sjmatthew 	    HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_DUPLEX);
2098c6900e6bSjmatthew 	req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG);
2099c6900e6bSjmatthew 	req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY);
2100c6900e6bSjmatthew 
2101c6900e6bSjmatthew 	return hwrm_send_message(sc, &req, sizeof(req));
2102c6900e6bSjmatthew }
2103c6900e6bSjmatthew 
2104c6900e6bSjmatthew 
2105a7c0060aSjmatthew void
2106a7c0060aSjmatthew bnxt_mark_cpr_invalid(struct bnxt_cp_ring *cpr)
2107a7c0060aSjmatthew {
2108a7c0060aSjmatthew 	struct cmpl_base *cmp = (void *)cpr->ring.vaddr;
2109a7c0060aSjmatthew 	int i;
2110a7c0060aSjmatthew 
2111a7c0060aSjmatthew 	for (i = 0; i < cpr->ring.ring_size; i++)
2112a7c0060aSjmatthew 		cmp[i].info3_v = !cpr->v_bit;
2113a7c0060aSjmatthew }
2114a7c0060aSjmatthew 
2115a7c0060aSjmatthew void
2116a7c0060aSjmatthew bnxt_write_cp_doorbell(struct bnxt_softc *sc, struct bnxt_ring *ring,
2117a7c0060aSjmatthew     int enable)
2118a7c0060aSjmatthew {
2119a7c0060aSjmatthew 	uint32_t val = CMPL_DOORBELL_KEY_CMPL;
2120a7c0060aSjmatthew 	if (enable == 0)
2121a7c0060aSjmatthew 		val |= CMPL_DOORBELL_MASK;
2122a7c0060aSjmatthew 
2123a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4,
2124a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2125a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, 0, sc->sc_db_s,
2126a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2127a7c0060aSjmatthew 	bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell,
2128a7c0060aSjmatthew 	    htole32(val));
2129a7c0060aSjmatthew }
2130a7c0060aSjmatthew 
2131a7c0060aSjmatthew void
2132a7c0060aSjmatthew bnxt_write_cp_doorbell_index(struct bnxt_softc *sc, struct bnxt_ring *ring,
2133a7c0060aSjmatthew     uint32_t index, int enable)
2134a7c0060aSjmatthew {
2135a7c0060aSjmatthew 	uint32_t val = CMPL_DOORBELL_KEY_CMPL | CMPL_DOORBELL_IDX_VALID |
2136a7c0060aSjmatthew 	    (index & CMPL_DOORBELL_IDX_MASK);
2137a7c0060aSjmatthew 	if (enable == 0)
2138a7c0060aSjmatthew 		val |= CMPL_DOORBELL_MASK;
2139a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4,
2140a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2141a7c0060aSjmatthew 	bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell,
2142a7c0060aSjmatthew 	    htole32(val));
2143a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, 0, sc->sc_db_s,
2144a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2145a7c0060aSjmatthew }
2146a7c0060aSjmatthew 
2147a7c0060aSjmatthew void
2148a7c0060aSjmatthew bnxt_write_rx_doorbell(struct bnxt_softc *sc, struct bnxt_ring *ring, int index)
2149a7c0060aSjmatthew {
2150a7c0060aSjmatthew 	uint32_t val = RX_DOORBELL_KEY_RX | index;
2151a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4,
2152a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2153a7c0060aSjmatthew 	bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell,
2154a7c0060aSjmatthew 	    htole32(val));
2155a7c0060aSjmatthew 
2156a7c0060aSjmatthew 	/* second write isn't necessary on all hardware */
2157a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4,
2158a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2159a7c0060aSjmatthew 	bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell,
2160a7c0060aSjmatthew 	    htole32(val));
2161a7c0060aSjmatthew }
2162a7c0060aSjmatthew 
2163a7c0060aSjmatthew void
2164a7c0060aSjmatthew bnxt_write_tx_doorbell(struct bnxt_softc *sc, struct bnxt_ring *ring, int index)
2165a7c0060aSjmatthew {
2166a7c0060aSjmatthew 	uint32_t val = TX_DOORBELL_KEY_TX | index;
2167a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4,
2168a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2169a7c0060aSjmatthew 	bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell,
2170a7c0060aSjmatthew 	    htole32(val));
2171a7c0060aSjmatthew 
2172a7c0060aSjmatthew 	/* second write isn't necessary on all hardware */
2173a7c0060aSjmatthew 	bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4,
2174a7c0060aSjmatthew 	    BUS_SPACE_BARRIER_WRITE);
2175a7c0060aSjmatthew 	bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell,
2176a7c0060aSjmatthew 	    htole32(val));
2177a7c0060aSjmatthew }
2178a7c0060aSjmatthew 
2179a7c0060aSjmatthew u_int
2180c4f53494Sjmatthew bnxt_rx_fill_slots(struct bnxt_softc *sc, struct bnxt_ring *ring, void *ring_mem,
2181c4f53494Sjmatthew     struct bnxt_slot *slots, uint *prod, int bufsize, uint16_t bdtype,
2182c4f53494Sjmatthew     u_int nslots)
2183a7c0060aSjmatthew {
2184a7c0060aSjmatthew 	struct rx_prod_pkt_bd *rxring;
2185a7c0060aSjmatthew 	struct bnxt_slot *bs;
2186a7c0060aSjmatthew 	struct mbuf *m;
2187a7c0060aSjmatthew 	uint p, fills;
2188a7c0060aSjmatthew 
2189c4f53494Sjmatthew 	rxring = (struct rx_prod_pkt_bd *)ring_mem;
2190c4f53494Sjmatthew 	p = *prod;
2191c4f53494Sjmatthew 	for (fills = 0; fills < nslots; fills++) {
2192c4f53494Sjmatthew 		bs = &slots[p];
2193471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, bufsize);
2194a7c0060aSjmatthew 		if (m == NULL)
2195a7c0060aSjmatthew 			break;
2196a7c0060aSjmatthew 
2197c4f53494Sjmatthew 		m->m_len = m->m_pkthdr.len = bufsize;
2198a7c0060aSjmatthew 		if (bus_dmamap_load_mbuf(sc->sc_dmat, bs->bs_map, m,
2199a7c0060aSjmatthew 		    BUS_DMA_NOWAIT) != 0) {
2200a7c0060aSjmatthew 			m_freem(m);
2201a7c0060aSjmatthew 			break;
2202a7c0060aSjmatthew 		}
2203a7c0060aSjmatthew 		bs->bs_m = m;
2204a7c0060aSjmatthew 
2205c4f53494Sjmatthew 		rxring[p].flags_type = htole16(bdtype);
2206c4f53494Sjmatthew 		rxring[p].len = htole16(bufsize);
2207a7c0060aSjmatthew 		rxring[p].opaque = p;
2208a7c0060aSjmatthew 		rxring[p].addr = htole64(bs->bs_map->dm_segs[0].ds_addr);
2209a7c0060aSjmatthew 
2210c4f53494Sjmatthew 		if (++p >= ring->ring_size)
2211a7c0060aSjmatthew 			p = 0;
2212a7c0060aSjmatthew 	}
2213a7c0060aSjmatthew 
2214a7c0060aSjmatthew 	if (fills != 0)
2215c4f53494Sjmatthew 		bnxt_write_rx_doorbell(sc, ring, p);
2216c4f53494Sjmatthew 	*prod = p;
2217a7c0060aSjmatthew 
2218c4f53494Sjmatthew 	return (nslots - fills);
2219a7c0060aSjmatthew }
2220a7c0060aSjmatthew 
2221a7c0060aSjmatthew int
2222765dc391Sjmatthew bnxt_rx_fill(struct bnxt_queue *q)
2223a7c0060aSjmatthew {
2224765dc391Sjmatthew 	struct bnxt_rx_queue *rx = &q->q_rx;
2225765dc391Sjmatthew 	struct bnxt_softc *sc = q->q_sc;
2226a7c0060aSjmatthew 	u_int slots;
2227c4f53494Sjmatthew 	int rv = 0;
2228a7c0060aSjmatthew 
2229765dc391Sjmatthew 	slots = if_rxr_get(&rx->rxr[0], rx->rx_ring.ring_size);
2230c4f53494Sjmatthew 	if (slots > 0) {
2231765dc391Sjmatthew 		slots = bnxt_rx_fill_slots(sc, &rx->rx_ring,
2232765dc391Sjmatthew 		    BNXT_DMA_KVA(rx->rx_ring_mem), rx->rx_slots,
2233765dc391Sjmatthew 		    &rx->rx_prod, MCLBYTES,
2234c4f53494Sjmatthew 		    RX_PROD_PKT_BD_TYPE_RX_PROD_PKT, slots);
2235765dc391Sjmatthew 		if_rxr_put(&rx->rxr[0], slots);
2236c4f53494Sjmatthew 	} else
2237c4f53494Sjmatthew 		rv = 1;
2238a7c0060aSjmatthew 
2239*2783188aSjmatthew 	return (rv);
2240*2783188aSjmatthew }
2241*2783188aSjmatthew 
2242*2783188aSjmatthew int
2243*2783188aSjmatthew bnxt_rx_fill_ag(struct bnxt_queue *q)
2244*2783188aSjmatthew {
2245*2783188aSjmatthew 	struct bnxt_rx_queue *rx = &q->q_rx;
2246*2783188aSjmatthew 	struct bnxt_softc *sc = q->q_sc;
2247*2783188aSjmatthew 	u_int slots;
2248*2783188aSjmatthew 	int rv = 0;
2249*2783188aSjmatthew 
2250765dc391Sjmatthew 	slots = if_rxr_get(&rx->rxr[1],  rx->rx_ag_ring.ring_size);
2251c4f53494Sjmatthew 	if (slots > 0) {
2252765dc391Sjmatthew 		slots = bnxt_rx_fill_slots(sc, &rx->rx_ag_ring,
2253765dc391Sjmatthew 		    BNXT_DMA_KVA(rx->rx_ring_mem) + PAGE_SIZE,
2254765dc391Sjmatthew 		    rx->rx_ag_slots, &rx->rx_ag_prod,
2255c4f53494Sjmatthew 		    BNXT_AG_BUFFER_SIZE,
2256c4f53494Sjmatthew 		    RX_PROD_AGG_BD_TYPE_RX_PROD_AGG, slots);
2257765dc391Sjmatthew 		if_rxr_put(&rx->rxr[1], slots);
2258c4f53494Sjmatthew 	} else
2259c4f53494Sjmatthew 		rv = 1;
2260a7c0060aSjmatthew 
2261c4f53494Sjmatthew 	return (rv);
2262a7c0060aSjmatthew }
2263a7c0060aSjmatthew 
2264a7c0060aSjmatthew void
2265765dc391Sjmatthew bnxt_refill(void *xq)
2266a7c0060aSjmatthew {
2267765dc391Sjmatthew 	struct bnxt_queue *q = xq;
2268765dc391Sjmatthew 	struct bnxt_rx_queue *rx = &q->q_rx;
2269a7c0060aSjmatthew 
2270*2783188aSjmatthew 	if (rx->rx_cons == rx->rx_prod)
2271765dc391Sjmatthew 		bnxt_rx_fill(q);
2272a7c0060aSjmatthew 
2273*2783188aSjmatthew 	if (rx->rx_ag_cons == rx->rx_ag_prod)
2274*2783188aSjmatthew 		bnxt_rx_fill_ag(q);
2275*2783188aSjmatthew 
2276*2783188aSjmatthew 	if ((rx->rx_cons == rx->rx_prod) ||
2277*2783188aSjmatthew 	    (rx->rx_ag_cons == rx->rx_ag_prod))
2278765dc391Sjmatthew 		timeout_add(&rx->rx_refill, 1);
2279a7c0060aSjmatthew }
2280a7c0060aSjmatthew 
2281c4f53494Sjmatthew int
2282765dc391Sjmatthew bnxt_rx(struct bnxt_softc *sc, struct bnxt_rx_queue *rx,
2283765dc391Sjmatthew     struct bnxt_cp_ring *cpr, struct mbuf_list *ml, int *slots, int *agslots,
2284765dc391Sjmatthew     struct cmpl_base *cmpl)
2285a7c0060aSjmatthew {
2286c4f53494Sjmatthew 	struct mbuf *m, *am;
2287a7c0060aSjmatthew 	struct bnxt_slot *bs;
2288765dc391Sjmatthew 	struct rx_pkt_cmpl *rxlo = (struct rx_pkt_cmpl *)cmpl;
2289c4f53494Sjmatthew 	struct rx_pkt_cmpl_hi *rxhi;
2290c4f53494Sjmatthew 	struct rx_abuf_cmpl *ag;
2291870f5687Sjmatthew 	uint32_t flags;
2292870f5687Sjmatthew 	uint16_t errors;
2293c4f53494Sjmatthew 
2294c4f53494Sjmatthew 	/* second part of the rx completion */
2295c4f53494Sjmatthew 	rxhi = (struct rx_pkt_cmpl_hi *)bnxt_cpr_next_cmpl(sc, cpr);
2296c4f53494Sjmatthew 	if (rxhi == NULL) {
2297c4f53494Sjmatthew 		return (1);
2298c4f53494Sjmatthew 	}
2299c4f53494Sjmatthew 
2300c4f53494Sjmatthew 	/* packets over 2k in size use an aggregation buffer completion too */
2301c4f53494Sjmatthew 	ag = NULL;
2302765dc391Sjmatthew 	if ((rxlo->agg_bufs_v1 >> RX_PKT_CMPL_AGG_BUFS_SFT) != 0) {
2303c4f53494Sjmatthew 		ag = (struct rx_abuf_cmpl *)bnxt_cpr_next_cmpl(sc, cpr);
2304c4f53494Sjmatthew 		if (ag == NULL) {
2305c4f53494Sjmatthew 			return (1);
2306c4f53494Sjmatthew 		}
2307c4f53494Sjmatthew 	}
2308a7c0060aSjmatthew 
2309765dc391Sjmatthew 	bs = &rx->rx_slots[rxlo->opaque];
2310a7c0060aSjmatthew 	bus_dmamap_sync(sc->sc_dmat, bs->bs_map, 0, bs->bs_map->dm_mapsize,
2311a7c0060aSjmatthew 	    BUS_DMASYNC_POSTREAD);
2312a7c0060aSjmatthew 	bus_dmamap_unload(sc->sc_dmat, bs->bs_map);
2313a7c0060aSjmatthew 
2314a7c0060aSjmatthew 	m = bs->bs_m;
2315a7c0060aSjmatthew 	bs->bs_m = NULL;
2316765dc391Sjmatthew 	m->m_pkthdr.len = m->m_len = letoh16(rxlo->len);
2317a7c0060aSjmatthew 	(*slots)++;
2318c4f53494Sjmatthew 
2319870f5687Sjmatthew 	/* checksum flags */
2320870f5687Sjmatthew 	flags = lemtoh32(&rxhi->flags2);
2321870f5687Sjmatthew 	errors = lemtoh16(&rxhi->errors_v2);
2322870f5687Sjmatthew 	if ((flags & RX_PKT_CMPL_FLAGS2_IP_CS_CALC) != 0 &&
2323870f5687Sjmatthew 	    (errors & RX_PKT_CMPL_ERRORS_IP_CS_ERROR) == 0)
2324870f5687Sjmatthew 		m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
2325870f5687Sjmatthew 
2326870f5687Sjmatthew 	if ((flags & RX_PKT_CMPL_FLAGS2_L4_CS_CALC) != 0 &&
2327870f5687Sjmatthew 	    (errors & RX_PKT_CMPL_ERRORS_L4_CS_ERROR) == 0)
2328870f5687Sjmatthew 		m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK |
2329870f5687Sjmatthew 		    M_UDP_CSUM_IN_OK;
2330870f5687Sjmatthew 
2331870f5687Sjmatthew #if NVLAN > 0
2332870f5687Sjmatthew 	if ((flags & RX_PKT_CMPL_FLAGS2_META_FORMAT_MASK) ==
2333870f5687Sjmatthew 	    RX_PKT_CMPL_FLAGS2_META_FORMAT_VLAN) {
2334870f5687Sjmatthew 		m->m_pkthdr.ether_vtag = lemtoh16(&rxhi->metadata);
2335870f5687Sjmatthew 		m->m_flags |= M_VLANTAG;
2336870f5687Sjmatthew 	}
2337870f5687Sjmatthew #endif
2338870f5687Sjmatthew 
2339d160d8f0Sjmatthew 	if (lemtoh16(&rxlo->flags_type) & RX_PKT_CMPL_FLAGS_RSS_VALID) {
2340d160d8f0Sjmatthew 		m->m_pkthdr.ph_flowid = lemtoh32(&rxlo->rss_hash);
2341d160d8f0Sjmatthew 		m->m_pkthdr.csum_flags |= M_FLOWID;
2342d160d8f0Sjmatthew 	}
2343d160d8f0Sjmatthew 
2344c4f53494Sjmatthew 	if (ag != NULL) {
2345765dc391Sjmatthew 		bs = &rx->rx_ag_slots[ag->opaque];
2346c4f53494Sjmatthew 		bus_dmamap_sync(sc->sc_dmat, bs->bs_map, 0,
2347c4f53494Sjmatthew 		    bs->bs_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
2348c4f53494Sjmatthew 		bus_dmamap_unload(sc->sc_dmat, bs->bs_map);
2349c4f53494Sjmatthew 
2350c4f53494Sjmatthew 		am = bs->bs_m;
2351c4f53494Sjmatthew 		bs->bs_m = NULL;
2352c4f53494Sjmatthew 		am->m_len = letoh16(ag->len);
2353c4f53494Sjmatthew 		m->m_next = am;
2354c4f53494Sjmatthew 		m->m_pkthdr.len += am->m_len;
2355c4f53494Sjmatthew 		(*agslots)++;
2356a7c0060aSjmatthew 	}
2357a7c0060aSjmatthew 
2358c4f53494Sjmatthew 	ml_enqueue(ml, m);
2359c4f53494Sjmatthew 	return (0);
2360c4f53494Sjmatthew }
2361c4f53494Sjmatthew 
2362c4f53494Sjmatthew void
2363765dc391Sjmatthew bnxt_txeof(struct bnxt_softc *sc, struct bnxt_tx_queue *tx, int *txfree,
2364765dc391Sjmatthew     struct cmpl_base *cmpl)
2365a7c0060aSjmatthew {
2366a7c0060aSjmatthew 	struct tx_cmpl *txcmpl = (struct tx_cmpl *)cmpl;
2367a7c0060aSjmatthew 	struct bnxt_slot *bs;
2368a7c0060aSjmatthew 	bus_dmamap_t map;
2369c4f53494Sjmatthew 	u_int idx, segs, last;
2370a7c0060aSjmatthew 
2371765dc391Sjmatthew 	idx = tx->tx_ring_cons;
2372765dc391Sjmatthew 	last = tx->tx_cons;
2373058d3950Sjmatthew 	do {
2374765dc391Sjmatthew 		bs = &tx->tx_slots[tx->tx_cons];
2375a7c0060aSjmatthew 		map = bs->bs_map;
2376a7c0060aSjmatthew 
2377af7e9c1bSjmatthew 		segs = BNXT_TX_SLOTS(bs);
2378a7c0060aSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
2379a7c0060aSjmatthew 		    BUS_DMASYNC_POSTWRITE);
2380a7c0060aSjmatthew 		bus_dmamap_unload(sc->sc_dmat, map);
2381a7c0060aSjmatthew 		m_freem(bs->bs_m);
2382a7c0060aSjmatthew 		bs->bs_m = NULL;
2383a7c0060aSjmatthew 
2384058d3950Sjmatthew 		idx += segs;
2385c4f53494Sjmatthew 		(*txfree) += segs;
2386765dc391Sjmatthew 		if (idx >= tx->tx_ring.ring_size)
2387765dc391Sjmatthew 			idx -= tx->tx_ring.ring_size;
2388a7c0060aSjmatthew 
2389765dc391Sjmatthew 		last = tx->tx_cons;
2390765dc391Sjmatthew 		if (++tx->tx_cons >= tx->tx_ring.ring_size)
2391765dc391Sjmatthew 			tx->tx_cons = 0;
2392a7c0060aSjmatthew 
2393058d3950Sjmatthew 	} while (last != txcmpl->opaque);
2394765dc391Sjmatthew 	tx->tx_ring_cons = idx;
2395a7c0060aSjmatthew }
2396a7c0060aSjmatthew 
2397a7c0060aSjmatthew /* bnxt_hwrm.c */
2398a7c0060aSjmatthew 
23990c45b53cSjmatthew int
2400a7c0060aSjmatthew bnxt_hwrm_err_map(uint16_t err)
2401a7c0060aSjmatthew {
2402a7c0060aSjmatthew 	int rc;
2403a7c0060aSjmatthew 
2404a7c0060aSjmatthew 	switch (err) {
2405a7c0060aSjmatthew 	case HWRM_ERR_CODE_SUCCESS:
2406a7c0060aSjmatthew 		return 0;
2407a7c0060aSjmatthew 	case HWRM_ERR_CODE_INVALID_PARAMS:
2408a7c0060aSjmatthew 	case HWRM_ERR_CODE_INVALID_FLAGS:
2409a7c0060aSjmatthew 	case HWRM_ERR_CODE_INVALID_ENABLES:
2410a7c0060aSjmatthew 		return EINVAL;
2411a7c0060aSjmatthew 	case HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED:
2412a7c0060aSjmatthew 		return EACCES;
2413a7c0060aSjmatthew 	case HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR:
2414a7c0060aSjmatthew 		return ENOMEM;
2415a7c0060aSjmatthew 	case HWRM_ERR_CODE_CMD_NOT_SUPPORTED:
2416a7c0060aSjmatthew 		return ENOSYS;
2417a7c0060aSjmatthew 	case HWRM_ERR_CODE_FAIL:
2418a7c0060aSjmatthew 		return EIO;
2419a7c0060aSjmatthew 	case HWRM_ERR_CODE_HWRM_ERROR:
2420a7c0060aSjmatthew 	case HWRM_ERR_CODE_UNKNOWN_ERR:
2421a7c0060aSjmatthew 	default:
2422a7c0060aSjmatthew 		return EIO;
2423a7c0060aSjmatthew 	}
2424a7c0060aSjmatthew 
2425a7c0060aSjmatthew 	return rc;
2426a7c0060aSjmatthew }
2427a7c0060aSjmatthew 
24280c45b53cSjmatthew void
2429a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *softc, void *request,
2430a7c0060aSjmatthew     uint16_t req_type)
2431a7c0060aSjmatthew {
2432a7c0060aSjmatthew 	struct input *req = request;
2433a7c0060aSjmatthew 
2434a7c0060aSjmatthew 	req->req_type = htole16(req_type);
2435a7c0060aSjmatthew 	req->cmpl_ring = 0xffff;
2436a7c0060aSjmatthew 	req->target_id = 0xffff;
2437a7c0060aSjmatthew 	req->resp_addr = htole64(BNXT_DMA_DVA(softc->sc_cmd_resp));
2438a7c0060aSjmatthew }
2439a7c0060aSjmatthew 
24400c45b53cSjmatthew int
2441a7c0060aSjmatthew _hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
2442a7c0060aSjmatthew {
2443a7c0060aSjmatthew 	struct input *req = msg;
2444a7c0060aSjmatthew 	struct hwrm_err_output *resp = BNXT_DMA_KVA(softc->sc_cmd_resp);
2445a7c0060aSjmatthew 	uint32_t *data = msg;
2446a7c0060aSjmatthew 	int i;
2447a7c0060aSjmatthew 	uint8_t *valid;
2448a7c0060aSjmatthew 	uint16_t err;
2449a7c0060aSjmatthew 	uint16_t max_req_len = HWRM_MAX_REQ_LEN;
2450a7c0060aSjmatthew 	struct hwrm_short_input short_input = {0};
2451a7c0060aSjmatthew 
2452a7c0060aSjmatthew 	/* TODO: DMASYNC in here. */
2453a7c0060aSjmatthew 	req->seq_id = htole16(softc->sc_cmd_seq++);
2454a7c0060aSjmatthew 	memset(resp, 0, PAGE_SIZE);
2455a7c0060aSjmatthew 
2456a7c0060aSjmatthew 	if (softc->sc_flags & BNXT_FLAG_SHORT_CMD) {
2457a7c0060aSjmatthew 		void *short_cmd_req = BNXT_DMA_KVA(softc->sc_cmd_resp);
2458a7c0060aSjmatthew 
2459a7c0060aSjmatthew 		memcpy(short_cmd_req, req, msg_len);
2460a7c0060aSjmatthew 		memset((uint8_t *) short_cmd_req + msg_len, 0,
2461a7c0060aSjmatthew 		    softc->sc_max_req_len - msg_len);
2462a7c0060aSjmatthew 
2463a7c0060aSjmatthew 		short_input.req_type = req->req_type;
2464a7c0060aSjmatthew 		short_input.signature =
2465a7c0060aSjmatthew 		    htole16(HWRM_SHORT_INPUT_SIGNATURE_SHORT_CMD);
2466a7c0060aSjmatthew 		short_input.size = htole16(msg_len);
2467a7c0060aSjmatthew 		short_input.req_addr =
2468a7c0060aSjmatthew 		    htole64(BNXT_DMA_DVA(softc->sc_cmd_resp));
2469a7c0060aSjmatthew 
2470a7c0060aSjmatthew 		data = (uint32_t *)&short_input;
2471a7c0060aSjmatthew 		msg_len = sizeof(short_input);
2472a7c0060aSjmatthew 
2473a7c0060aSjmatthew 		/* Sync memory write before updating doorbell */
2474a7c0060aSjmatthew 		membar_sync();
2475a7c0060aSjmatthew 
2476a7c0060aSjmatthew 		max_req_len = BNXT_HWRM_SHORT_REQ_LEN;
2477a7c0060aSjmatthew 	}
2478a7c0060aSjmatthew 
2479a7c0060aSjmatthew 	/* Write request msg to hwrm channel */
2480a7c0060aSjmatthew 	for (i = 0; i < msg_len; i += 4) {
2481a7c0060aSjmatthew 		bus_space_write_4(softc->sc_hwrm_t,
2482a7c0060aSjmatthew 				  softc->sc_hwrm_h,
2483a7c0060aSjmatthew 				  i, *data);
2484a7c0060aSjmatthew 		data++;
2485a7c0060aSjmatthew 	}
2486a7c0060aSjmatthew 
2487a7c0060aSjmatthew 	/* Clear to the end of the request buffer */
2488a7c0060aSjmatthew 	for (i = msg_len; i < max_req_len; i += 4)
2489a7c0060aSjmatthew 		bus_space_write_4(softc->sc_hwrm_t, softc->sc_hwrm_h,
2490a7c0060aSjmatthew 		    i, 0);
2491a7c0060aSjmatthew 
2492a7c0060aSjmatthew 	/* Ring channel doorbell */
2493a7c0060aSjmatthew 	bus_space_write_4(softc->sc_hwrm_t, softc->sc_hwrm_h, 0x100,
2494a7c0060aSjmatthew 	    htole32(1));
2495a7c0060aSjmatthew 
2496a7c0060aSjmatthew 	/* Check if response len is updated */
2497a7c0060aSjmatthew 	for (i = 0; i < softc->sc_cmd_timeo; i++) {
2498a7c0060aSjmatthew 		if (resp->resp_len && resp->resp_len <= 4096)
2499a7c0060aSjmatthew 			break;
2500a7c0060aSjmatthew 		DELAY(1000);
2501a7c0060aSjmatthew 	}
2502a7c0060aSjmatthew 	if (i >= softc->sc_cmd_timeo) {
2503a7c0060aSjmatthew 		printf("%s: timeout sending %s: (timeout: %u) seq: %d\n",
2504a7c0060aSjmatthew 		    DEVNAME(softc), GET_HWRM_REQ_TYPE(req->req_type),
2505a7c0060aSjmatthew 		    softc->sc_cmd_timeo,
2506a7c0060aSjmatthew 		    le16toh(req->seq_id));
2507a7c0060aSjmatthew 		return ETIMEDOUT;
2508a7c0060aSjmatthew 	}
2509a7c0060aSjmatthew 	/* Last byte of resp contains the valid key */
2510a7c0060aSjmatthew 	valid = (uint8_t *)resp + resp->resp_len - 1;
2511a7c0060aSjmatthew 	for (i = 0; i < softc->sc_cmd_timeo; i++) {
2512a7c0060aSjmatthew 		if (*valid == HWRM_RESP_VALID_KEY)
2513a7c0060aSjmatthew 			break;
2514a7c0060aSjmatthew 		DELAY(1000);
2515a7c0060aSjmatthew 	}
2516a7c0060aSjmatthew 	if (i >= softc->sc_cmd_timeo) {
2517a7c0060aSjmatthew 		printf("%s: timeout sending %s: "
2518a7c0060aSjmatthew 		    "(timeout: %u) msg {0x%x 0x%x} len:%d v: %d\n",
2519a7c0060aSjmatthew 		    DEVNAME(softc), GET_HWRM_REQ_TYPE(req->req_type),
2520a7c0060aSjmatthew 		    softc->sc_cmd_timeo, le16toh(req->req_type),
2521a7c0060aSjmatthew 		    le16toh(req->seq_id), msg_len,
2522a7c0060aSjmatthew 		    *valid);
2523a7c0060aSjmatthew 		return ETIMEDOUT;
2524a7c0060aSjmatthew 	}
2525a7c0060aSjmatthew 
2526a7c0060aSjmatthew 	err = le16toh(resp->error_code);
2527a7c0060aSjmatthew 	if (err) {
2528a7c0060aSjmatthew 		/* HWRM_ERR_CODE_FAIL is a "normal" error, don't log */
2529a7c0060aSjmatthew 		if (err != HWRM_ERR_CODE_FAIL) {
2530a7c0060aSjmatthew 			printf("%s: %s command returned %s error.\n",
2531a7c0060aSjmatthew 			    DEVNAME(softc),
2532a7c0060aSjmatthew 			    GET_HWRM_REQ_TYPE(req->req_type),
2533a7c0060aSjmatthew 			    GET_HWRM_ERROR_CODE(err));
2534a7c0060aSjmatthew 		}
2535a7c0060aSjmatthew 		return bnxt_hwrm_err_map(err);
2536a7c0060aSjmatthew 	}
2537a7c0060aSjmatthew 
2538a7c0060aSjmatthew 	return 0;
2539a7c0060aSjmatthew }
2540a7c0060aSjmatthew 
2541a7c0060aSjmatthew 
25420c45b53cSjmatthew int
2543a7c0060aSjmatthew hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
2544a7c0060aSjmatthew {
2545a7c0060aSjmatthew 	int rc;
2546a7c0060aSjmatthew 
2547a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2548a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, msg, msg_len);
2549a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2550a7c0060aSjmatthew 	return rc;
2551a7c0060aSjmatthew }
2552a7c0060aSjmatthew 
2553a7c0060aSjmatthew 
2554a7c0060aSjmatthew int
2555a7c0060aSjmatthew bnxt_hwrm_queue_qportcfg(struct bnxt_softc *softc)
2556a7c0060aSjmatthew {
2557a7c0060aSjmatthew 	struct hwrm_queue_qportcfg_input req = {0};
2558a7c0060aSjmatthew 	struct hwrm_queue_qportcfg_output *resp =
2559a7c0060aSjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
2560d460f6dcSjmatthew 	int	rc = 0;
2561a7c0060aSjmatthew 
2562a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_QPORTCFG);
2563a7c0060aSjmatthew 
2564a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2565a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2566a7c0060aSjmatthew 	if (rc)
2567a7c0060aSjmatthew 		goto qportcfg_exit;
2568a7c0060aSjmatthew 
2569a7c0060aSjmatthew 	if (!resp->max_configurable_queues) {
2570a7c0060aSjmatthew 		rc = -EINVAL;
2571a7c0060aSjmatthew 		goto qportcfg_exit;
2572a7c0060aSjmatthew 	}
2573a7c0060aSjmatthew 
2574d460f6dcSjmatthew 	softc->sc_tx_queue_id = resp->queue_id0;
2575a7c0060aSjmatthew 
2576a7c0060aSjmatthew qportcfg_exit:
2577a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2578d256ca68Sjmatthew 	return rc;
2579a7c0060aSjmatthew }
2580a7c0060aSjmatthew 
2581a7c0060aSjmatthew int
2582a7c0060aSjmatthew bnxt_hwrm_ver_get(struct bnxt_softc *softc)
2583a7c0060aSjmatthew {
2584a7c0060aSjmatthew 	struct hwrm_ver_get_input	req = {0};
2585a7c0060aSjmatthew 	struct hwrm_ver_get_output	*resp =
2586a7c0060aSjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
2587a7c0060aSjmatthew 	int				rc;
2588a7c0060aSjmatthew #if 0
2589a7c0060aSjmatthew 	const char nastr[] = "<not installed>";
2590a7c0060aSjmatthew 	const char naver[] = "<N/A>";
2591a7c0060aSjmatthew #endif
2592a7c0060aSjmatthew 	uint32_t dev_caps_cfg;
2593a7c0060aSjmatthew 
2594a7c0060aSjmatthew 	softc->sc_max_req_len = HWRM_MAX_REQ_LEN;
2595a7c0060aSjmatthew 	softc->sc_cmd_timeo = 1000;
2596a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VER_GET);
2597a7c0060aSjmatthew 
2598a7c0060aSjmatthew 	req.hwrm_intf_maj = HWRM_VERSION_MAJOR;
2599a7c0060aSjmatthew 	req.hwrm_intf_min = HWRM_VERSION_MINOR;
2600a7c0060aSjmatthew 	req.hwrm_intf_upd = HWRM_VERSION_UPDATE;
2601a7c0060aSjmatthew 
2602a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2603a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2604a7c0060aSjmatthew 	if (rc)
2605a7c0060aSjmatthew 		goto fail;
2606a7c0060aSjmatthew 
2607a7c0060aSjmatthew 	printf(": fw ver %d.%d.%d, ", resp->hwrm_fw_maj, resp->hwrm_fw_min,
2608a7c0060aSjmatthew 	    resp->hwrm_fw_bld);
260992586e53Sjmatthew 
261092586e53Sjmatthew 	softc->sc_hwrm_ver = (resp->hwrm_intf_maj << 16) |
261192586e53Sjmatthew 	    (resp->hwrm_intf_min << 8) | resp->hwrm_intf_upd;
2612a7c0060aSjmatthew #if 0
2613a7c0060aSjmatthew 	snprintf(softc->ver_info->hwrm_if_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
2614a7c0060aSjmatthew 	    resp->hwrm_intf_maj, resp->hwrm_intf_min, resp->hwrm_intf_upd);
2615a7c0060aSjmatthew 	softc->ver_info->hwrm_if_major = resp->hwrm_intf_maj;
2616a7c0060aSjmatthew 	softc->ver_info->hwrm_if_minor = resp->hwrm_intf_min;
2617a7c0060aSjmatthew 	softc->ver_info->hwrm_if_update = resp->hwrm_intf_upd;
2618a7c0060aSjmatthew 	snprintf(softc->ver_info->hwrm_fw_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
2619a7c0060aSjmatthew 	    resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld);
2620a7c0060aSjmatthew 	strlcpy(softc->ver_info->driver_hwrm_if_ver, HWRM_VERSION_STR,
2621a7c0060aSjmatthew 	    BNXT_VERSTR_SIZE);
2622a7c0060aSjmatthew 	strlcpy(softc->ver_info->hwrm_fw_name, resp->hwrm_fw_name,
2623a7c0060aSjmatthew 	    BNXT_NAME_SIZE);
2624a7c0060aSjmatthew 
2625a7c0060aSjmatthew 	if (resp->mgmt_fw_maj == 0 && resp->mgmt_fw_min == 0 &&
2626a7c0060aSjmatthew 	    resp->mgmt_fw_bld == 0) {
2627a7c0060aSjmatthew 		strlcpy(softc->ver_info->mgmt_fw_ver, naver, BNXT_VERSTR_SIZE);
2628a7c0060aSjmatthew 		strlcpy(softc->ver_info->mgmt_fw_name, nastr, BNXT_NAME_SIZE);
2629a7c0060aSjmatthew 	}
2630a7c0060aSjmatthew 	else {
2631a7c0060aSjmatthew 		snprintf(softc->ver_info->mgmt_fw_ver, BNXT_VERSTR_SIZE,
2632a7c0060aSjmatthew 		    "%d.%d.%d", resp->mgmt_fw_maj, resp->mgmt_fw_min,
2633a7c0060aSjmatthew 		    resp->mgmt_fw_bld);
2634a7c0060aSjmatthew 		strlcpy(softc->ver_info->mgmt_fw_name, resp->mgmt_fw_name,
2635a7c0060aSjmatthew 		    BNXT_NAME_SIZE);
2636a7c0060aSjmatthew 	}
2637a7c0060aSjmatthew 	if (resp->netctrl_fw_maj == 0 && resp->netctrl_fw_min == 0 &&
2638a7c0060aSjmatthew 	    resp->netctrl_fw_bld == 0) {
2639a7c0060aSjmatthew 		strlcpy(softc->ver_info->netctrl_fw_ver, naver,
2640a7c0060aSjmatthew 		    BNXT_VERSTR_SIZE);
2641a7c0060aSjmatthew 		strlcpy(softc->ver_info->netctrl_fw_name, nastr,
2642a7c0060aSjmatthew 		    BNXT_NAME_SIZE);
2643a7c0060aSjmatthew 	}
2644a7c0060aSjmatthew 	else {
2645a7c0060aSjmatthew 		snprintf(softc->ver_info->netctrl_fw_ver, BNXT_VERSTR_SIZE,
2646a7c0060aSjmatthew 		    "%d.%d.%d", resp->netctrl_fw_maj, resp->netctrl_fw_min,
2647a7c0060aSjmatthew 		    resp->netctrl_fw_bld);
2648a7c0060aSjmatthew 		strlcpy(softc->ver_info->netctrl_fw_name, resp->netctrl_fw_name,
2649a7c0060aSjmatthew 		    BNXT_NAME_SIZE);
2650a7c0060aSjmatthew 	}
2651a7c0060aSjmatthew 	if (resp->roce_fw_maj == 0 && resp->roce_fw_min == 0 &&
2652a7c0060aSjmatthew 	    resp->roce_fw_bld == 0) {
2653a7c0060aSjmatthew 		strlcpy(softc->ver_info->roce_fw_ver, naver, BNXT_VERSTR_SIZE);
2654a7c0060aSjmatthew 		strlcpy(softc->ver_info->roce_fw_name, nastr, BNXT_NAME_SIZE);
2655a7c0060aSjmatthew 	}
2656a7c0060aSjmatthew 	else {
2657a7c0060aSjmatthew 		snprintf(softc->ver_info->roce_fw_ver, BNXT_VERSTR_SIZE,
2658a7c0060aSjmatthew 		    "%d.%d.%d", resp->roce_fw_maj, resp->roce_fw_min,
2659a7c0060aSjmatthew 		    resp->roce_fw_bld);
2660a7c0060aSjmatthew 		strlcpy(softc->ver_info->roce_fw_name, resp->roce_fw_name,
2661a7c0060aSjmatthew 		    BNXT_NAME_SIZE);
2662a7c0060aSjmatthew 	}
2663a7c0060aSjmatthew 	softc->ver_info->chip_num = le16toh(resp->chip_num);
2664a7c0060aSjmatthew 	softc->ver_info->chip_rev = resp->chip_rev;
2665a7c0060aSjmatthew 	softc->ver_info->chip_metal = resp->chip_metal;
2666a7c0060aSjmatthew 	softc->ver_info->chip_bond_id = resp->chip_bond_id;
2667a7c0060aSjmatthew 	softc->ver_info->chip_type = resp->chip_platform_type;
2668a7c0060aSjmatthew #endif
2669a7c0060aSjmatthew 
2670a7c0060aSjmatthew 	if (resp->max_req_win_len)
2671a7c0060aSjmatthew 		softc->sc_max_req_len = le16toh(resp->max_req_win_len);
2672a7c0060aSjmatthew 	if (resp->def_req_timeout)
2673a7c0060aSjmatthew 		softc->sc_cmd_timeo = le16toh(resp->def_req_timeout);
2674a7c0060aSjmatthew 
2675a7c0060aSjmatthew 	dev_caps_cfg = le32toh(resp->dev_caps_cfg);
2676a7c0060aSjmatthew 	if ((dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED) &&
2677a7c0060aSjmatthew 	    (dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_REQUIRED))
2678a7c0060aSjmatthew 		softc->sc_flags |= BNXT_FLAG_SHORT_CMD;
2679a7c0060aSjmatthew 
2680a7c0060aSjmatthew fail:
2681a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2682a7c0060aSjmatthew 	return rc;
2683a7c0060aSjmatthew }
2684a7c0060aSjmatthew 
2685a7c0060aSjmatthew 
2686a7c0060aSjmatthew int
2687a7c0060aSjmatthew bnxt_hwrm_func_drv_rgtr(struct bnxt_softc *softc)
2688a7c0060aSjmatthew {
2689a7c0060aSjmatthew 	struct hwrm_func_drv_rgtr_input req = {0};
2690a7c0060aSjmatthew 
2691a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
2692a7c0060aSjmatthew 
2693a7c0060aSjmatthew 	req.enables = htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_VER |
2694a7c0060aSjmatthew 	    HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_OS_TYPE);
2695a7c0060aSjmatthew 	req.os_type = htole16(HWRM_FUNC_DRV_RGTR_INPUT_OS_TYPE_FREEBSD);
2696a7c0060aSjmatthew 
2697a7c0060aSjmatthew 	req.ver_maj = 6;
2698a7c0060aSjmatthew 	req.ver_min = 4;
2699a7c0060aSjmatthew 	req.ver_upd = 0;
2700a7c0060aSjmatthew 
2701a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
2702a7c0060aSjmatthew }
2703a7c0060aSjmatthew 
2704a7c0060aSjmatthew #if 0
2705a7c0060aSjmatthew 
2706a7c0060aSjmatthew int
2707a7c0060aSjmatthew bnxt_hwrm_func_drv_unrgtr(struct bnxt_softc *softc, bool shutdown)
2708a7c0060aSjmatthew {
2709a7c0060aSjmatthew 	struct hwrm_func_drv_unrgtr_input req = {0};
2710a7c0060aSjmatthew 
2711a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_UNRGTR);
2712a7c0060aSjmatthew 	if (shutdown == true)
2713a7c0060aSjmatthew 		req.flags |=
2714a7c0060aSjmatthew 		    HWRM_FUNC_DRV_UNRGTR_INPUT_FLAGS_PREPARE_FOR_SHUTDOWN;
2715a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
2716a7c0060aSjmatthew }
2717a7c0060aSjmatthew 
2718a7c0060aSjmatthew #endif
2719a7c0060aSjmatthew 
2720a7c0060aSjmatthew int
2721a7c0060aSjmatthew bnxt_hwrm_func_qcaps(struct bnxt_softc *softc)
2722a7c0060aSjmatthew {
2723a7c0060aSjmatthew 	int rc = 0;
2724a7c0060aSjmatthew 	struct hwrm_func_qcaps_input req = {0};
2725a7c0060aSjmatthew 	struct hwrm_func_qcaps_output *resp =
2726a7c0060aSjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
2727a7c0060aSjmatthew 	/* struct bnxt_func_info *func = &softc->func; */
2728a7c0060aSjmatthew 
2729a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCAPS);
2730a7c0060aSjmatthew 	req.fid = htole16(0xffff);
2731a7c0060aSjmatthew 
2732a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2733a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2734a7c0060aSjmatthew 	if (rc)
2735a7c0060aSjmatthew 		goto fail;
2736a7c0060aSjmatthew 
2737a7c0060aSjmatthew 	if (resp->flags &
2738a7c0060aSjmatthew 	    htole32(HWRM_FUNC_QCAPS_OUTPUT_FLAGS_WOL_MAGICPKT_SUPPORTED))
2739a7c0060aSjmatthew 		softc->sc_flags |= BNXT_FLAG_WOL_CAP;
2740a7c0060aSjmatthew 
2741a7c0060aSjmatthew 	memcpy(softc->sc_ac.ac_enaddr, resp->mac_address, 6);
2742a7c0060aSjmatthew 	/*
2743a7c0060aSjmatthew 	func->fw_fid = le16toh(resp->fid);
2744a7c0060aSjmatthew 	memcpy(func->mac_addr, resp->mac_address, ETHER_ADDR_LEN);
2745a7c0060aSjmatthew 	func->max_rsscos_ctxs = le16toh(resp->max_rsscos_ctx);
2746a7c0060aSjmatthew 	func->max_cp_rings = le16toh(resp->max_cmpl_rings);
2747a7c0060aSjmatthew 	func->max_tx_rings = le16toh(resp->max_tx_rings);
2748a7c0060aSjmatthew 	func->max_rx_rings = le16toh(resp->max_rx_rings);
2749a7c0060aSjmatthew 	func->max_hw_ring_grps = le32toh(resp->max_hw_ring_grps);
2750a7c0060aSjmatthew 	if (!func->max_hw_ring_grps)
2751a7c0060aSjmatthew 		func->max_hw_ring_grps = func->max_tx_rings;
2752a7c0060aSjmatthew 	func->max_l2_ctxs = le16toh(resp->max_l2_ctxs);
2753a7c0060aSjmatthew 	func->max_vnics = le16toh(resp->max_vnics);
2754a7c0060aSjmatthew 	func->max_stat_ctxs = le16toh(resp->max_stat_ctx);
2755a7c0060aSjmatthew 	if (BNXT_PF(softc)) {
2756a7c0060aSjmatthew 		struct bnxt_pf_info *pf = &softc->pf;
2757a7c0060aSjmatthew 
2758a7c0060aSjmatthew 		pf->port_id = le16toh(resp->port_id);
2759a7c0060aSjmatthew 		pf->first_vf_id = le16toh(resp->first_vf_id);
2760a7c0060aSjmatthew 		pf->max_vfs = le16toh(resp->max_vfs);
2761a7c0060aSjmatthew 		pf->max_encap_records = le32toh(resp->max_encap_records);
2762a7c0060aSjmatthew 		pf->max_decap_records = le32toh(resp->max_decap_records);
2763a7c0060aSjmatthew 		pf->max_tx_em_flows = le32toh(resp->max_tx_em_flows);
2764a7c0060aSjmatthew 		pf->max_tx_wm_flows = le32toh(resp->max_tx_wm_flows);
2765a7c0060aSjmatthew 		pf->max_rx_em_flows = le32toh(resp->max_rx_em_flows);
2766a7c0060aSjmatthew 		pf->max_rx_wm_flows = le32toh(resp->max_rx_wm_flows);
2767a7c0060aSjmatthew 	}
2768a7c0060aSjmatthew 	if (!_is_valid_ether_addr(func->mac_addr)) {
2769a7c0060aSjmatthew 		device_printf(softc->dev, "Invalid ethernet address, generating random locally administered address\n");
2770a7c0060aSjmatthew 		get_random_ether_addr(func->mac_addr);
2771a7c0060aSjmatthew 	}
2772a7c0060aSjmatthew 	*/
2773a7c0060aSjmatthew 
2774a7c0060aSjmatthew fail:
2775a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2776a7c0060aSjmatthew 	return rc;
2777a7c0060aSjmatthew }
2778a7c0060aSjmatthew 
2779a7c0060aSjmatthew 
2780a7c0060aSjmatthew int
2781a7c0060aSjmatthew bnxt_hwrm_func_qcfg(struct bnxt_softc *softc)
2782a7c0060aSjmatthew {
2783a7c0060aSjmatthew         struct hwrm_func_qcfg_input req = {0};
2784a7c0060aSjmatthew         /* struct hwrm_func_qcfg_output *resp =
2785a7c0060aSjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
2786a7c0060aSjmatthew 	struct bnxt_func_qcfg *fn_qcfg = &softc->fn_qcfg; */
2787a7c0060aSjmatthew         int rc;
2788a7c0060aSjmatthew 
2789a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG);
2790a7c0060aSjmatthew         req.fid = htole16(0xffff);
2791a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2792a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2793a7c0060aSjmatthew         if (rc)
2794a7c0060aSjmatthew 		goto fail;
2795a7c0060aSjmatthew 
2796a7c0060aSjmatthew 	/*
2797a7c0060aSjmatthew 	fn_qcfg->alloc_completion_rings = le16toh(resp->alloc_cmpl_rings);
2798a7c0060aSjmatthew 	fn_qcfg->alloc_tx_rings = le16toh(resp->alloc_tx_rings);
2799a7c0060aSjmatthew 	fn_qcfg->alloc_rx_rings = le16toh(resp->alloc_rx_rings);
2800a7c0060aSjmatthew 	fn_qcfg->alloc_vnics = le16toh(resp->alloc_vnics);
2801a7c0060aSjmatthew 	*/
2802a7c0060aSjmatthew fail:
2803a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2804a7c0060aSjmatthew         return rc;
2805a7c0060aSjmatthew }
2806a7c0060aSjmatthew 
2807a7c0060aSjmatthew 
2808a7c0060aSjmatthew int
2809a7c0060aSjmatthew bnxt_hwrm_func_reset(struct bnxt_softc *softc)
2810a7c0060aSjmatthew {
2811a7c0060aSjmatthew 	struct hwrm_func_reset_input req = {0};
2812a7c0060aSjmatthew 
2813a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_RESET);
2814a7c0060aSjmatthew 	req.enables = 0;
2815a7c0060aSjmatthew 
2816a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
2817a7c0060aSjmatthew }
2818a7c0060aSjmatthew 
2819a7c0060aSjmatthew int
2820c4f53494Sjmatthew bnxt_hwrm_vnic_cfg_placement(struct bnxt_softc *softc,
2821c4f53494Sjmatthew     struct bnxt_vnic_info *vnic)
2822c4f53494Sjmatthew {
2823c4f53494Sjmatthew 	struct hwrm_vnic_plcmodes_cfg_input req = {0};
2824c4f53494Sjmatthew 
2825c4f53494Sjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_PLCMODES_CFG);
2826c4f53494Sjmatthew 
2827c4f53494Sjmatthew 	req.flags = htole32(
2828c4f53494Sjmatthew 	    HWRM_VNIC_PLCMODES_CFG_INPUT_FLAGS_JUMBO_PLACEMENT);
2829c4f53494Sjmatthew 	req.enables = htole32(
2830c4f53494Sjmatthew 	    HWRM_VNIC_PLCMODES_CFG_INPUT_ENABLES_JUMBO_THRESH_VALID);
2831c4f53494Sjmatthew 	req.vnic_id = htole16(vnic->id);
2832c4f53494Sjmatthew 	req.jumbo_thresh = htole16(MCLBYTES);
2833c4f53494Sjmatthew 
2834c4f53494Sjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
2835c4f53494Sjmatthew }
2836c4f53494Sjmatthew 
2837c4f53494Sjmatthew int
2838a7c0060aSjmatthew bnxt_hwrm_vnic_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
2839a7c0060aSjmatthew {
2840a7c0060aSjmatthew 	struct hwrm_vnic_cfg_input req = {0};
2841a7c0060aSjmatthew 
2842a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_CFG);
2843a7c0060aSjmatthew 
2844a7c0060aSjmatthew 	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
2845a7c0060aSjmatthew 		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_DEFAULT);
2846a7c0060aSjmatthew 	if (vnic->flags & BNXT_VNIC_FLAG_BD_STALL)
2847a7c0060aSjmatthew 		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_BD_STALL_MODE);
2848a7c0060aSjmatthew 	if (vnic->flags & BNXT_VNIC_FLAG_VLAN_STRIP)
2849a7c0060aSjmatthew 		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_VLAN_STRIP_MODE);
2850a7c0060aSjmatthew 	req.enables = htole32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP |
2851a7c0060aSjmatthew 	    HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE |
2852a7c0060aSjmatthew 	    HWRM_VNIC_CFG_INPUT_ENABLES_MRU);
2853a7c0060aSjmatthew 	req.vnic_id = htole16(vnic->id);
2854a7c0060aSjmatthew 	req.dflt_ring_grp = htole16(vnic->def_ring_grp);
2855a7c0060aSjmatthew 	req.rss_rule = htole16(vnic->rss_id);
2856a7c0060aSjmatthew 	req.cos_rule = htole16(vnic->cos_rule);
2857a7c0060aSjmatthew 	req.lb_rule = htole16(vnic->lb_rule);
2858a7c0060aSjmatthew 	req.mru = htole16(vnic->mru);
2859a7c0060aSjmatthew 
2860a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
2861a7c0060aSjmatthew }
2862a7c0060aSjmatthew 
2863a7c0060aSjmatthew int
2864a7c0060aSjmatthew bnxt_hwrm_vnic_alloc(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
2865a7c0060aSjmatthew {
2866a7c0060aSjmatthew 	struct hwrm_vnic_alloc_input req = {0};
2867a7c0060aSjmatthew 	struct hwrm_vnic_alloc_output *resp =
2868a7c0060aSjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
2869a7c0060aSjmatthew 	int rc;
2870a7c0060aSjmatthew 
2871a7c0060aSjmatthew 	if (vnic->id != (uint16_t)HWRM_NA_SIGNATURE) {
2872a7c0060aSjmatthew 		printf("%s: attempt to re-allocate vnic %04x\n",
2873a7c0060aSjmatthew 		    DEVNAME(softc), vnic->id);
2874a7c0060aSjmatthew 		return EINVAL;
2875a7c0060aSjmatthew 	}
2876a7c0060aSjmatthew 
2877a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_ALLOC);
2878a7c0060aSjmatthew 
2879a7c0060aSjmatthew 	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
2880a7c0060aSjmatthew 		req.flags = htole32(HWRM_VNIC_ALLOC_INPUT_FLAGS_DEFAULT);
2881a7c0060aSjmatthew 
2882a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2883a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2884a7c0060aSjmatthew 	if (rc)
2885a7c0060aSjmatthew 		goto fail;
2886a7c0060aSjmatthew 
2887a7c0060aSjmatthew 	vnic->id = le32toh(resp->vnic_id);
2888a7c0060aSjmatthew 
2889a7c0060aSjmatthew fail:
2890a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2891d256ca68Sjmatthew 	return rc;
2892a7c0060aSjmatthew }
2893a7c0060aSjmatthew 
2894a7c0060aSjmatthew int
2895a7c0060aSjmatthew bnxt_hwrm_vnic_free(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
2896a7c0060aSjmatthew {
2897a7c0060aSjmatthew 	struct hwrm_vnic_free_input req = {0};
2898a7c0060aSjmatthew 	int rc;
2899a7c0060aSjmatthew 
2900a7c0060aSjmatthew 	if (vnic->id == (uint16_t)HWRM_NA_SIGNATURE) {
2901a7c0060aSjmatthew 		printf("%s: attempt to deallocate vnic %04x\n",
2902a7c0060aSjmatthew 		    DEVNAME(softc), vnic->id);
2903a7c0060aSjmatthew 		return (EINVAL);
2904a7c0060aSjmatthew 	}
2905a7c0060aSjmatthew 
2906a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_FREE);
2907a7c0060aSjmatthew 	req.vnic_id = htole16(vnic->id);
2908a7c0060aSjmatthew 
2909a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2910a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2911a7c0060aSjmatthew 	if (rc == 0)
2912a7c0060aSjmatthew 		vnic->id = (uint16_t)HWRM_NA_SIGNATURE;
2913a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2914a7c0060aSjmatthew 
2915a7c0060aSjmatthew 	return (rc);
2916a7c0060aSjmatthew }
2917a7c0060aSjmatthew 
2918a7c0060aSjmatthew int
2919a7c0060aSjmatthew bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *softc, uint16_t *ctx_id)
2920a7c0060aSjmatthew {
2921a7c0060aSjmatthew 	struct hwrm_vnic_rss_cos_lb_ctx_alloc_input req = {0};
2922a7c0060aSjmatthew 	struct hwrm_vnic_rss_cos_lb_ctx_alloc_output *resp =
2923a7c0060aSjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
2924a7c0060aSjmatthew 	int rc;
2925a7c0060aSjmatthew 
2926a7c0060aSjmatthew 	if (*ctx_id != (uint16_t)HWRM_NA_SIGNATURE) {
2927a7c0060aSjmatthew 		printf("%s: attempt to re-allocate vnic ctx %04x\n",
2928a7c0060aSjmatthew 		    DEVNAME(softc), *ctx_id);
2929a7c0060aSjmatthew 		return EINVAL;
2930a7c0060aSjmatthew 	}
2931a7c0060aSjmatthew 
2932a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_ALLOC);
2933a7c0060aSjmatthew 
2934a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2935a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2936a7c0060aSjmatthew 	if (rc)
2937a7c0060aSjmatthew 		goto fail;
2938a7c0060aSjmatthew 
2939a7c0060aSjmatthew 	*ctx_id = letoh16(resp->rss_cos_lb_ctx_id);
2940a7c0060aSjmatthew 
2941a7c0060aSjmatthew fail:
2942a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2943a7c0060aSjmatthew 	return (rc);
2944a7c0060aSjmatthew }
2945a7c0060aSjmatthew 
2946a7c0060aSjmatthew int
2947a7c0060aSjmatthew bnxt_hwrm_vnic_ctx_free(struct bnxt_softc *softc, uint16_t *ctx_id)
2948a7c0060aSjmatthew {
2949a7c0060aSjmatthew 	struct hwrm_vnic_rss_cos_lb_ctx_free_input req = {0};
2950a7c0060aSjmatthew 	int rc;
2951a7c0060aSjmatthew 
2952a7c0060aSjmatthew 	if (*ctx_id == (uint16_t)HWRM_NA_SIGNATURE) {
2953a7c0060aSjmatthew 		printf("%s: attempt to deallocate vnic ctx %04x\n",
2954a7c0060aSjmatthew 		    DEVNAME(softc), *ctx_id);
2955a7c0060aSjmatthew 		return (EINVAL);
2956a7c0060aSjmatthew 	}
2957a7c0060aSjmatthew 
2958a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_FREE);
2959a7c0060aSjmatthew 	req.rss_cos_lb_ctx_id = htole32(*ctx_id);
2960a7c0060aSjmatthew 
2961a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2962a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2963a7c0060aSjmatthew 	if (rc == 0)
2964a7c0060aSjmatthew 		*ctx_id = (uint16_t)HWRM_NA_SIGNATURE;
2965a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2966a7c0060aSjmatthew 	return (rc);
2967a7c0060aSjmatthew }
2968a7c0060aSjmatthew 
2969a7c0060aSjmatthew int
2970a7c0060aSjmatthew bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *softc, struct bnxt_grp_info *grp)
2971a7c0060aSjmatthew {
2972a7c0060aSjmatthew 	struct hwrm_ring_grp_alloc_input req = {0};
2973a7c0060aSjmatthew 	struct hwrm_ring_grp_alloc_output *resp;
2974a7c0060aSjmatthew 	int rc = 0;
2975a7c0060aSjmatthew 
2976a7c0060aSjmatthew 	if (grp->grp_id != HWRM_NA_SIGNATURE) {
2977a7c0060aSjmatthew 		printf("%s: attempt to re-allocate ring group %04x\n",
2978a7c0060aSjmatthew 		    DEVNAME(softc), grp->grp_id);
2979a7c0060aSjmatthew 		return EINVAL;
2980a7c0060aSjmatthew 	}
2981a7c0060aSjmatthew 
2982a7c0060aSjmatthew 	resp = BNXT_DMA_KVA(softc->sc_cmd_resp);
2983a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_ALLOC);
2984a7c0060aSjmatthew 	req.cr = htole16(grp->cp_ring_id);
2985a7c0060aSjmatthew 	req.rr = htole16(grp->rx_ring_id);
2986a7c0060aSjmatthew 	req.ar = htole16(grp->ag_ring_id);
2987a7c0060aSjmatthew 	req.sc = htole16(grp->stats_ctx);
2988a7c0060aSjmatthew 
2989a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
2990a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
2991a7c0060aSjmatthew 	if (rc)
2992a7c0060aSjmatthew 		goto fail;
2993a7c0060aSjmatthew 
2994a7c0060aSjmatthew 	grp->grp_id = letoh32(resp->ring_group_id);
2995a7c0060aSjmatthew 
2996a7c0060aSjmatthew fail:
2997a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
2998a7c0060aSjmatthew 	return rc;
2999a7c0060aSjmatthew }
3000a7c0060aSjmatthew 
3001a7c0060aSjmatthew int
3002a7c0060aSjmatthew bnxt_hwrm_ring_grp_free(struct bnxt_softc *softc, struct bnxt_grp_info *grp)
3003a7c0060aSjmatthew {
3004a7c0060aSjmatthew 	struct hwrm_ring_grp_free_input req = {0};
3005a7c0060aSjmatthew 	int rc = 0;
3006a7c0060aSjmatthew 
3007a7c0060aSjmatthew 	if (grp->grp_id == HWRM_NA_SIGNATURE) {
3008a7c0060aSjmatthew 		printf("%s: attempt to free ring group %04x\n",
3009a7c0060aSjmatthew 		    DEVNAME(softc), grp->grp_id);
3010a7c0060aSjmatthew 		return EINVAL;
3011a7c0060aSjmatthew 	}
3012a7c0060aSjmatthew 
3013a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_FREE);
3014a7c0060aSjmatthew 	req.ring_group_id = htole32(grp->grp_id);
3015a7c0060aSjmatthew 
3016a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3017a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3018a7c0060aSjmatthew 	if (rc == 0)
3019a7c0060aSjmatthew 		grp->grp_id = HWRM_NA_SIGNATURE;
3020a7c0060aSjmatthew 
3021a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3022a7c0060aSjmatthew 	return (rc);
3023a7c0060aSjmatthew }
3024a7c0060aSjmatthew 
3025a7c0060aSjmatthew /*
3026a7c0060aSjmatthew  * Ring allocation message to the firmware
3027a7c0060aSjmatthew  */
3028a7c0060aSjmatthew int
3029a7c0060aSjmatthew bnxt_hwrm_ring_alloc(struct bnxt_softc *softc, uint8_t type,
3030a7c0060aSjmatthew     struct bnxt_ring *ring, uint16_t cmpl_ring_id, uint32_t stat_ctx_id,
3031a7c0060aSjmatthew     int irq)
3032a7c0060aSjmatthew {
3033a7c0060aSjmatthew 	struct hwrm_ring_alloc_input req = {0};
3034a7c0060aSjmatthew 	struct hwrm_ring_alloc_output *resp;
3035a7c0060aSjmatthew 	int rc;
3036a7c0060aSjmatthew 
3037a7c0060aSjmatthew 	if (ring->phys_id != (uint16_t)HWRM_NA_SIGNATURE) {
3038a7c0060aSjmatthew 		printf("%s: attempt to re-allocate ring %04x\n",
3039a7c0060aSjmatthew 		    DEVNAME(softc), ring->phys_id);
3040a7c0060aSjmatthew 		return EINVAL;
3041a7c0060aSjmatthew 	}
3042a7c0060aSjmatthew 
3043a7c0060aSjmatthew 	resp = BNXT_DMA_KVA(softc->sc_cmd_resp);
3044a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_ALLOC);
3045a7c0060aSjmatthew 	req.enables = htole32(0);
3046a7c0060aSjmatthew 	req.fbo = htole32(0);
3047a7c0060aSjmatthew 
3048a7c0060aSjmatthew 	if (stat_ctx_id != HWRM_NA_SIGNATURE) {
3049a7c0060aSjmatthew 		req.enables |= htole32(
3050a7c0060aSjmatthew 		    HWRM_RING_ALLOC_INPUT_ENABLES_STAT_CTX_ID_VALID);
3051a7c0060aSjmatthew 		req.stat_ctx_id = htole32(stat_ctx_id);
3052a7c0060aSjmatthew 	}
3053a7c0060aSjmatthew 	req.ring_type = type;
3054a7c0060aSjmatthew 	req.page_tbl_addr = htole64(ring->paddr);
3055a7c0060aSjmatthew 	req.length = htole32(ring->ring_size);
3056a7c0060aSjmatthew 	req.logical_id = htole16(ring->id);
3057a7c0060aSjmatthew 	req.cmpl_ring_id = htole16(cmpl_ring_id);
3058d460f6dcSjmatthew 	req.queue_id = htole16(softc->sc_tx_queue_id);
305961ed761cSsf 	req.int_mode = (softc->sc_flags & BNXT_FLAG_MSIX) ?
306061ed761cSsf 	    HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX :
306161ed761cSsf 	    HWRM_RING_ALLOC_INPUT_INT_MODE_LEGACY;
3062a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3063a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3064a7c0060aSjmatthew 	if (rc)
3065a7c0060aSjmatthew 		goto fail;
3066a7c0060aSjmatthew 
3067a7c0060aSjmatthew 	ring->phys_id = le16toh(resp->ring_id);
3068a7c0060aSjmatthew 
3069a7c0060aSjmatthew fail:
3070a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3071a7c0060aSjmatthew 	return rc;
3072a7c0060aSjmatthew }
3073a7c0060aSjmatthew 
3074a7c0060aSjmatthew int
3075a7c0060aSjmatthew bnxt_hwrm_ring_free(struct bnxt_softc *softc, uint8_t type, struct bnxt_ring *ring)
3076a7c0060aSjmatthew {
3077a7c0060aSjmatthew 	struct hwrm_ring_free_input req = {0};
3078a7c0060aSjmatthew 	int rc;
3079a7c0060aSjmatthew 
3080a7c0060aSjmatthew 	if (ring->phys_id == (uint16_t)HWRM_NA_SIGNATURE) {
3081a7c0060aSjmatthew 		printf("%s: attempt to deallocate ring %04x\n",
3082a7c0060aSjmatthew 		    DEVNAME(softc), ring->phys_id);
3083a7c0060aSjmatthew 		return (EINVAL);
3084a7c0060aSjmatthew 	}
3085a7c0060aSjmatthew 
3086a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_FREE);
3087a7c0060aSjmatthew 	req.ring_type = type;
3088a7c0060aSjmatthew 	req.ring_id = htole16(ring->phys_id);
3089a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3090a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3091a7c0060aSjmatthew 	if (rc)
3092a7c0060aSjmatthew 		goto fail;
3093a7c0060aSjmatthew 
3094a7c0060aSjmatthew 	ring->phys_id = (uint16_t)HWRM_NA_SIGNATURE;
3095a7c0060aSjmatthew fail:
3096a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3097a7c0060aSjmatthew 	return (rc);
3098a7c0060aSjmatthew }
3099a7c0060aSjmatthew 
3100a7c0060aSjmatthew 
3101a7c0060aSjmatthew int
3102a7c0060aSjmatthew bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr,
3103a7c0060aSjmatthew     uint64_t paddr)
3104a7c0060aSjmatthew {
3105a7c0060aSjmatthew 	struct hwrm_stat_ctx_alloc_input req = {0};
3106a7c0060aSjmatthew 	struct hwrm_stat_ctx_alloc_output *resp;
3107a7c0060aSjmatthew 	int rc = 0;
3108a7c0060aSjmatthew 
3109a7c0060aSjmatthew 	if (cpr->stats_ctx_id != HWRM_NA_SIGNATURE) {
3110a7c0060aSjmatthew 		printf("%s: attempt to re-allocate stats ctx %08x\n",
3111a7c0060aSjmatthew 		    DEVNAME(softc), cpr->stats_ctx_id);
3112a7c0060aSjmatthew 		return EINVAL;
3113a7c0060aSjmatthew 	}
3114a7c0060aSjmatthew 
3115a7c0060aSjmatthew 	resp = BNXT_DMA_KVA(softc->sc_cmd_resp);
3116a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_ALLOC);
3117a7c0060aSjmatthew 
3118a7c0060aSjmatthew 	req.update_period_ms = htole32(1000);
3119a7c0060aSjmatthew 	req.stats_dma_addr = htole64(paddr);
3120a7c0060aSjmatthew 
3121a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3122a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3123a7c0060aSjmatthew 	if (rc)
3124a7c0060aSjmatthew 		goto fail;
3125a7c0060aSjmatthew 
3126a7c0060aSjmatthew 	cpr->stats_ctx_id = le32toh(resp->stat_ctx_id);
3127a7c0060aSjmatthew 
3128a7c0060aSjmatthew fail:
3129a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3130a7c0060aSjmatthew 
3131a7c0060aSjmatthew 	return rc;
3132a7c0060aSjmatthew }
3133a7c0060aSjmatthew 
3134a7c0060aSjmatthew int
3135a7c0060aSjmatthew bnxt_hwrm_stat_ctx_free(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr)
3136a7c0060aSjmatthew {
3137a7c0060aSjmatthew 	struct hwrm_stat_ctx_free_input req = {0};
3138a7c0060aSjmatthew 	int rc = 0;
3139a7c0060aSjmatthew 
3140a7c0060aSjmatthew 	if (cpr->stats_ctx_id == HWRM_NA_SIGNATURE) {
3141a7c0060aSjmatthew 		printf("%s: attempt to free stats ctx %08x\n",
3142a7c0060aSjmatthew 		    DEVNAME(softc), cpr->stats_ctx_id);
3143a7c0060aSjmatthew 		return EINVAL;
3144a7c0060aSjmatthew 	}
3145a7c0060aSjmatthew 
3146a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_FREE);
3147a7c0060aSjmatthew 	req.stat_ctx_id = htole32(cpr->stats_ctx_id);
3148a7c0060aSjmatthew 
3149a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3150a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3151a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3152a7c0060aSjmatthew 
3153a7c0060aSjmatthew 	if (rc == 0)
3154a7c0060aSjmatthew 		cpr->stats_ctx_id = HWRM_NA_SIGNATURE;
3155a7c0060aSjmatthew 
3156a7c0060aSjmatthew 	return (rc);
3157a7c0060aSjmatthew }
3158a7c0060aSjmatthew 
3159a7c0060aSjmatthew #if 0
3160a7c0060aSjmatthew 
3161a7c0060aSjmatthew int
3162a7c0060aSjmatthew bnxt_hwrm_port_qstats(struct bnxt_softc *softc)
3163a7c0060aSjmatthew {
3164a7c0060aSjmatthew 	struct hwrm_port_qstats_input req = {0};
3165a7c0060aSjmatthew 	int rc = 0;
3166a7c0060aSjmatthew 
3167a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_QSTATS);
3168a7c0060aSjmatthew 
3169a7c0060aSjmatthew 	req.port_id = htole16(softc->pf.port_id);
3170a7c0060aSjmatthew 	req.rx_stat_host_addr = htole64(softc->hw_rx_port_stats.idi_paddr);
3171a7c0060aSjmatthew 	req.tx_stat_host_addr = htole64(softc->hw_tx_port_stats.idi_paddr);
3172a7c0060aSjmatthew 
3173a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3174a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3175a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3176a7c0060aSjmatthew 
3177a7c0060aSjmatthew 	return rc;
3178a7c0060aSjmatthew }
3179a7c0060aSjmatthew 
3180a7c0060aSjmatthew #endif
3181a7c0060aSjmatthew 
3182a7c0060aSjmatthew int
3183a7c0060aSjmatthew bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *softc,
3184b12ece3dSjmatthew     uint32_t vnic_id, uint32_t rx_mask, uint64_t mc_addr, uint32_t mc_count)
3185a7c0060aSjmatthew {
3186a7c0060aSjmatthew 	struct hwrm_cfa_l2_set_rx_mask_input req = {0};
3187a7c0060aSjmatthew 
3188a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_SET_RX_MASK);
3189a7c0060aSjmatthew 
3190b12ece3dSjmatthew 	req.vnic_id = htole32(vnic_id);
3191b12ece3dSjmatthew 	req.mask = htole32(rx_mask);
3192b12ece3dSjmatthew 	req.mc_tbl_addr = htole64(mc_addr);
3193b12ece3dSjmatthew 	req.num_mc_entries = htole32(mc_count);
3194a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
3195a7c0060aSjmatthew }
3196a7c0060aSjmatthew 
3197a7c0060aSjmatthew int
3198a7c0060aSjmatthew bnxt_hwrm_set_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
3199a7c0060aSjmatthew {
3200a7c0060aSjmatthew 	struct hwrm_cfa_l2_filter_alloc_input	req = {0};
3201a7c0060aSjmatthew 	struct hwrm_cfa_l2_filter_alloc_output	*resp;
3202a7c0060aSjmatthew 	uint32_t enables = 0;
3203a7c0060aSjmatthew 	int rc = 0;
3204a7c0060aSjmatthew 
3205a7c0060aSjmatthew 	if (vnic->filter_id != -1) {
3206a7c0060aSjmatthew 		printf("%s: attempt to re-allocate l2 ctx filter\n",
3207a7c0060aSjmatthew 		    DEVNAME(softc));
3208a7c0060aSjmatthew 		return EINVAL;
3209a7c0060aSjmatthew 	}
3210a7c0060aSjmatthew 
3211a7c0060aSjmatthew 	resp = BNXT_DMA_KVA(softc->sc_cmd_resp);
3212a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_ALLOC);
3213a7c0060aSjmatthew 
3214615a26c0Sjmatthew 	req.flags = htole32(HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX
3215615a26c0Sjmatthew 	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_OUTERMOST);
3216a7c0060aSjmatthew 	enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR
3217a7c0060aSjmatthew 	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK
3218a7c0060aSjmatthew 	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_DST_ID;
3219a7c0060aSjmatthew 	req.enables = htole32(enables);
3220a7c0060aSjmatthew 	req.dst_id = htole16(vnic->id);
3221a7c0060aSjmatthew 	memcpy(req.l2_addr, softc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
3222a7c0060aSjmatthew 	memset(&req.l2_addr_mask, 0xff, sizeof(req.l2_addr_mask));
3223a7c0060aSjmatthew 
3224a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3225a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3226a7c0060aSjmatthew 	if (rc)
3227a7c0060aSjmatthew 		goto fail;
3228a7c0060aSjmatthew 
3229a7c0060aSjmatthew 	vnic->filter_id = le64toh(resp->l2_filter_id);
3230a7c0060aSjmatthew 	vnic->flow_id = le64toh(resp->flow_id);
3231a7c0060aSjmatthew 
3232a7c0060aSjmatthew fail:
3233a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3234a7c0060aSjmatthew 	return (rc);
3235a7c0060aSjmatthew }
3236a7c0060aSjmatthew 
3237a7c0060aSjmatthew int
3238a7c0060aSjmatthew bnxt_hwrm_free_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
3239a7c0060aSjmatthew {
3240a7c0060aSjmatthew 	struct hwrm_cfa_l2_filter_free_input req = {0};
3241a7c0060aSjmatthew 	int rc = 0;
3242a7c0060aSjmatthew 
3243a7c0060aSjmatthew 	if (vnic->filter_id == -1) {
3244a7c0060aSjmatthew 		printf("%s: attempt to deallocate filter %llx\n",
3245a7c0060aSjmatthew 		     DEVNAME(softc), vnic->filter_id);
3246a7c0060aSjmatthew 		return (EINVAL);
3247a7c0060aSjmatthew 	}
3248a7c0060aSjmatthew 
3249a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_FREE);
3250a7c0060aSjmatthew 	req.l2_filter_id = htole64(vnic->filter_id);
3251a7c0060aSjmatthew 
3252a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3253a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3254a7c0060aSjmatthew 	if (rc == 0)
3255a7c0060aSjmatthew 		vnic->filter_id = -1;
3256a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3257a7c0060aSjmatthew 
3258a7c0060aSjmatthew 	return (rc);
3259a7c0060aSjmatthew }
3260a7c0060aSjmatthew 
3261a7c0060aSjmatthew 
3262a7c0060aSjmatthew int
3263d160d8f0Sjmatthew bnxt_hwrm_vnic_rss_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic,
3264d160d8f0Sjmatthew     uint32_t hash_type, daddr_t rss_table, daddr_t rss_key)
3265a7c0060aSjmatthew {
3266a7c0060aSjmatthew 	struct hwrm_vnic_rss_cfg_input	req = {0};
3267a7c0060aSjmatthew 
3268a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_CFG);
3269a7c0060aSjmatthew 
3270a7c0060aSjmatthew 	req.hash_type = htole32(hash_type);
3271d160d8f0Sjmatthew 	req.ring_grp_tbl_addr = htole64(rss_table);
3272d160d8f0Sjmatthew 	req.hash_key_tbl_addr = htole64(rss_key);
3273a7c0060aSjmatthew 	req.rss_ctx_idx = htole16(vnic->rss_id);
3274a7c0060aSjmatthew 
3275a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
3276a7c0060aSjmatthew }
3277a7c0060aSjmatthew 
3278a7c0060aSjmatthew int
3279765dc391Sjmatthew bnxt_cfg_async_cr(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr)
3280a7c0060aSjmatthew {
3281a7c0060aSjmatthew 	int rc = 0;
3282a7c0060aSjmatthew 
3283a7c0060aSjmatthew 	if (1 /* BNXT_PF(softc) */) {
3284a7c0060aSjmatthew 		struct hwrm_func_cfg_input req = {0};
3285a7c0060aSjmatthew 
3286a7c0060aSjmatthew 		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
3287a7c0060aSjmatthew 
3288a7c0060aSjmatthew 		req.fid = htole16(0xffff);
3289a7c0060aSjmatthew 		req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
3290765dc391Sjmatthew 		req.async_event_cr = htole16(cpr->ring.phys_id);
3291a7c0060aSjmatthew 
3292a7c0060aSjmatthew 		rc = hwrm_send_message(softc, &req, sizeof(req));
3293a7c0060aSjmatthew 	} else {
3294a7c0060aSjmatthew 		struct hwrm_func_vf_cfg_input req = {0};
3295a7c0060aSjmatthew 
3296a7c0060aSjmatthew 		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_CFG);
3297a7c0060aSjmatthew 
3298a7c0060aSjmatthew 		req.enables = htole32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
3299765dc391Sjmatthew 		req.async_event_cr = htole16(cpr->ring.phys_id);
3300a7c0060aSjmatthew 
3301a7c0060aSjmatthew 		rc = hwrm_send_message(softc, &req, sizeof(req));
3302a7c0060aSjmatthew 	}
3303a7c0060aSjmatthew 	return rc;
3304a7c0060aSjmatthew }
3305a7c0060aSjmatthew 
3306a7c0060aSjmatthew #if 0
3307a7c0060aSjmatthew 
3308a7c0060aSjmatthew void
3309a7c0060aSjmatthew bnxt_validate_hw_lro_settings(struct bnxt_softc *softc)
3310a7c0060aSjmatthew {
3311a7c0060aSjmatthew 	softc->hw_lro.enable = min(softc->hw_lro.enable, 1);
3312a7c0060aSjmatthew 
3313a7c0060aSjmatthew         softc->hw_lro.is_mode_gro = min(softc->hw_lro.is_mode_gro, 1);
3314a7c0060aSjmatthew 
3315a7c0060aSjmatthew 	softc->hw_lro.max_agg_segs = min(softc->hw_lro.max_agg_segs,
3316a7c0060aSjmatthew 		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGG_SEGS_MAX);
3317a7c0060aSjmatthew 
3318a7c0060aSjmatthew 	softc->hw_lro.max_aggs = min(softc->hw_lro.max_aggs,
3319a7c0060aSjmatthew 		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGGS_MAX);
3320a7c0060aSjmatthew 
3321a7c0060aSjmatthew 	softc->hw_lro.min_agg_len = min(softc->hw_lro.min_agg_len, BNXT_MAX_MTU);
3322a7c0060aSjmatthew }
3323a7c0060aSjmatthew 
3324a7c0060aSjmatthew int
3325a7c0060aSjmatthew bnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc)
3326a7c0060aSjmatthew {
3327a7c0060aSjmatthew 	struct hwrm_vnic_tpa_cfg_input req = {0};
3328a7c0060aSjmatthew 	uint32_t flags;
3329a7c0060aSjmatthew 
3330a7c0060aSjmatthew 	if (softc->vnic_info.id == (uint16_t) HWRM_NA_SIGNATURE) {
3331a7c0060aSjmatthew 		return 0;
3332a7c0060aSjmatthew 	}
3333a7c0060aSjmatthew 
3334a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_TPA_CFG);
3335a7c0060aSjmatthew 
3336a7c0060aSjmatthew 	if (softc->hw_lro.enable) {
3337a7c0060aSjmatthew 		flags = HWRM_VNIC_TPA_CFG_INPUT_FLAGS_TPA |
3338a7c0060aSjmatthew 			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_ENCAP_TPA |
3339a7c0060aSjmatthew 			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_ECN |
3340a7c0060aSjmatthew 			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_SAME_GRE_SEQ;
3341a7c0060aSjmatthew 
3342a7c0060aSjmatthew         	if (softc->hw_lro.is_mode_gro)
3343a7c0060aSjmatthew 			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_GRO;
3344a7c0060aSjmatthew 		else
3345a7c0060aSjmatthew 			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_RSC_WND_UPDATE;
3346a7c0060aSjmatthew 
3347a7c0060aSjmatthew 		req.flags = htole32(flags);
3348a7c0060aSjmatthew 
3349a7c0060aSjmatthew 		req.enables = htole32(HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGG_SEGS |
3350a7c0060aSjmatthew 				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGGS |
3351a7c0060aSjmatthew 				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MIN_AGG_LEN);
3352a7c0060aSjmatthew 
3353a7c0060aSjmatthew 		req.max_agg_segs = htole16(softc->hw_lro.max_agg_segs);
3354a7c0060aSjmatthew 		req.max_aggs = htole16(softc->hw_lro.max_aggs);
3355a7c0060aSjmatthew 		req.min_agg_len = htole32(softc->hw_lro.min_agg_len);
3356a7c0060aSjmatthew 	}
3357a7c0060aSjmatthew 
3358a7c0060aSjmatthew 	req.vnic_id = htole16(softc->vnic_info.id);
3359a7c0060aSjmatthew 
3360a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
3361a7c0060aSjmatthew }
3362a7c0060aSjmatthew 
3363a7c0060aSjmatthew 
3364a7c0060aSjmatthew int
3365a7c0060aSjmatthew bnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor,
3366a7c0060aSjmatthew     uint8_t *selfreset)
3367a7c0060aSjmatthew {
3368a7c0060aSjmatthew 	struct hwrm_fw_reset_input req = {0};
3369a7c0060aSjmatthew 	struct hwrm_fw_reset_output *resp =
3370a7c0060aSjmatthew 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
3371a7c0060aSjmatthew 	int rc;
3372a7c0060aSjmatthew 
3373a7c0060aSjmatthew 	MPASS(selfreset);
3374a7c0060aSjmatthew 
3375a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_RESET);
3376a7c0060aSjmatthew 	req.embedded_proc_type = processor;
3377a7c0060aSjmatthew 	req.selfrst_status = *selfreset;
3378a7c0060aSjmatthew 
3379a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3380a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3381a7c0060aSjmatthew 	if (rc)
3382a7c0060aSjmatthew 		goto exit;
3383a7c0060aSjmatthew 	*selfreset = resp->selfrst_status;
3384a7c0060aSjmatthew 
3385a7c0060aSjmatthew exit:
3386a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3387a7c0060aSjmatthew 	return rc;
3388a7c0060aSjmatthew }
3389a7c0060aSjmatthew 
3390a7c0060aSjmatthew int
3391a7c0060aSjmatthew bnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type, uint8_t *selfreset)
3392a7c0060aSjmatthew {
3393a7c0060aSjmatthew 	struct hwrm_fw_qstatus_input req = {0};
3394a7c0060aSjmatthew 	struct hwrm_fw_qstatus_output *resp =
3395a7c0060aSjmatthew 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
3396a7c0060aSjmatthew 	int rc;
3397a7c0060aSjmatthew 
3398a7c0060aSjmatthew 	MPASS(selfreset);
3399a7c0060aSjmatthew 
3400a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_QSTATUS);
3401a7c0060aSjmatthew 	req.embedded_proc_type = type;
3402a7c0060aSjmatthew 
3403a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3404a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3405a7c0060aSjmatthew 	if (rc)
3406a7c0060aSjmatthew 		goto exit;
3407a7c0060aSjmatthew 	*selfreset = resp->selfrst_status;
3408a7c0060aSjmatthew 
3409a7c0060aSjmatthew exit:
3410a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3411a7c0060aSjmatthew 	return rc;
3412a7c0060aSjmatthew }
3413a7c0060aSjmatthew 
3414a7c0060aSjmatthew #endif
3415a7c0060aSjmatthew 
3416a7c0060aSjmatthew int
3417a7c0060aSjmatthew bnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *softc, uint16_t *mfg_id,
3418a7c0060aSjmatthew     uint16_t *device_id, uint32_t *sector_size, uint32_t *nvram_size,
3419a7c0060aSjmatthew     uint32_t *reserved_size, uint32_t *available_size)
3420a7c0060aSjmatthew {
3421a7c0060aSjmatthew 	struct hwrm_nvm_get_dev_info_input req = {0};
3422a7c0060aSjmatthew 	struct hwrm_nvm_get_dev_info_output *resp =
3423a7c0060aSjmatthew 	    BNXT_DMA_KVA(softc->sc_cmd_resp);
3424a7c0060aSjmatthew 	int rc;
3425a7c0060aSjmatthew 	uint32_t old_timeo;
3426a7c0060aSjmatthew 
3427a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DEV_INFO);
3428a7c0060aSjmatthew 
3429a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3430a7c0060aSjmatthew 	old_timeo = softc->sc_cmd_timeo;
3431a7c0060aSjmatthew 	softc->sc_cmd_timeo = BNXT_NVM_TIMEO;
3432a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3433a7c0060aSjmatthew 	softc->sc_cmd_timeo = old_timeo;
3434a7c0060aSjmatthew 	if (rc)
3435a7c0060aSjmatthew 		goto exit;
3436a7c0060aSjmatthew 
3437a7c0060aSjmatthew 	if (mfg_id)
3438a7c0060aSjmatthew 		*mfg_id = le16toh(resp->manufacturer_id);
3439a7c0060aSjmatthew 	if (device_id)
3440a7c0060aSjmatthew 		*device_id = le16toh(resp->device_id);
3441a7c0060aSjmatthew 	if (sector_size)
3442a7c0060aSjmatthew 		*sector_size = le32toh(resp->sector_size);
3443a7c0060aSjmatthew 	if (nvram_size)
3444a7c0060aSjmatthew 		*nvram_size = le32toh(resp->nvram_size);
3445a7c0060aSjmatthew 	if (reserved_size)
3446a7c0060aSjmatthew 		*reserved_size = le32toh(resp->reserved_size);
3447a7c0060aSjmatthew 	if (available_size)
3448a7c0060aSjmatthew 		*available_size = le32toh(resp->available_size);
3449a7c0060aSjmatthew 
3450a7c0060aSjmatthew exit:
3451a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3452a7c0060aSjmatthew 	return rc;
3453a7c0060aSjmatthew }
3454a7c0060aSjmatthew 
3455a7c0060aSjmatthew #if 0
3456a7c0060aSjmatthew 
3457a7c0060aSjmatthew int
3458a7c0060aSjmatthew bnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year, uint8_t *month,
3459a7c0060aSjmatthew     uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second,
3460a7c0060aSjmatthew     uint16_t *millisecond, uint16_t *zone)
3461a7c0060aSjmatthew {
3462a7c0060aSjmatthew 	struct hwrm_fw_get_time_input req = {0};
3463a7c0060aSjmatthew 	struct hwrm_fw_get_time_output *resp =
3464a7c0060aSjmatthew 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
3465a7c0060aSjmatthew 	int rc;
3466a7c0060aSjmatthew 
3467a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_GET_TIME);
3468a7c0060aSjmatthew 
3469a7c0060aSjmatthew 	BNXT_HWRM_LOCK(softc);
3470a7c0060aSjmatthew 	rc = _hwrm_send_message(softc, &req, sizeof(req));
3471a7c0060aSjmatthew 	if (rc)
3472a7c0060aSjmatthew 		goto exit;
3473a7c0060aSjmatthew 
3474a7c0060aSjmatthew 	if (year)
3475a7c0060aSjmatthew 		*year = le16toh(resp->year);
3476a7c0060aSjmatthew 	if (month)
3477a7c0060aSjmatthew 		*month = resp->month;
3478a7c0060aSjmatthew 	if (day)
3479a7c0060aSjmatthew 		*day = resp->day;
3480a7c0060aSjmatthew 	if (hour)
3481a7c0060aSjmatthew 		*hour = resp->hour;
3482a7c0060aSjmatthew 	if (minute)
3483a7c0060aSjmatthew 		*minute = resp->minute;
3484a7c0060aSjmatthew 	if (second)
3485a7c0060aSjmatthew 		*second = resp->second;
3486a7c0060aSjmatthew 	if (millisecond)
3487a7c0060aSjmatthew 		*millisecond = le16toh(resp->millisecond);
3488a7c0060aSjmatthew 	if (zone)
3489a7c0060aSjmatthew 		*zone = le16toh(resp->zone);
3490a7c0060aSjmatthew 
3491a7c0060aSjmatthew exit:
3492a7c0060aSjmatthew 	BNXT_HWRM_UNLOCK(softc);
3493a7c0060aSjmatthew 	return rc;
3494a7c0060aSjmatthew }
3495a7c0060aSjmatthew 
3496a7c0060aSjmatthew int
3497a7c0060aSjmatthew bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year, uint8_t month,
3498a7c0060aSjmatthew     uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
3499a7c0060aSjmatthew     uint16_t millisecond, uint16_t zone)
3500a7c0060aSjmatthew {
3501a7c0060aSjmatthew 	struct hwrm_fw_set_time_input req = {0};
3502a7c0060aSjmatthew 
3503a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_SET_TIME);
3504a7c0060aSjmatthew 
3505a7c0060aSjmatthew 	req.year = htole16(year);
3506a7c0060aSjmatthew 	req.month = month;
3507a7c0060aSjmatthew 	req.day = day;
3508a7c0060aSjmatthew 	req.hour = hour;
3509a7c0060aSjmatthew 	req.minute = minute;
3510a7c0060aSjmatthew 	req.second = second;
3511a7c0060aSjmatthew 	req.millisecond = htole16(millisecond);
3512a7c0060aSjmatthew 	req.zone = htole16(zone);
3513a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
3514a7c0060aSjmatthew }
3515a7c0060aSjmatthew 
3516a7c0060aSjmatthew #endif
3517a7c0060aSjmatthew 
3518a7c0060aSjmatthew void
3519a7c0060aSjmatthew _bnxt_hwrm_set_async_event_bit(struct hwrm_func_drv_rgtr_input *req, int bit)
3520a7c0060aSjmatthew {
3521a7c0060aSjmatthew 	req->async_event_fwd[bit/32] |= (1 << (bit % 32));
3522a7c0060aSjmatthew }
3523a7c0060aSjmatthew 
3524da5607f6Sjsg int
3525da5607f6Sjsg bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *softc)
3526a7c0060aSjmatthew {
3527a7c0060aSjmatthew 	struct hwrm_func_drv_rgtr_input req = {0};
3528a7c0060aSjmatthew 	int events[] = {
3529a7c0060aSjmatthew 		HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE,
3530a7c0060aSjmatthew 		HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD,
3531a7c0060aSjmatthew 		HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED,
3532a7c0060aSjmatthew 		HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE,
3533a7c0060aSjmatthew 		HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE
3534a7c0060aSjmatthew 	};
3535a7c0060aSjmatthew 	int i;
3536a7c0060aSjmatthew 
3537a7c0060aSjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
3538a7c0060aSjmatthew 
3539a7c0060aSjmatthew 	req.enables =
3540a7c0060aSjmatthew 		htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_ASYNC_EVENT_FWD);
3541a7c0060aSjmatthew 
3542a7c0060aSjmatthew 	for (i = 0; i < nitems(events); i++)
3543a7c0060aSjmatthew 		_bnxt_hwrm_set_async_event_bit(&req, events[i]);
3544a7c0060aSjmatthew 
3545a7c0060aSjmatthew 	return hwrm_send_message(softc, &req, sizeof(req));
3546a7c0060aSjmatthew }
354740247284Sjmatthew 
354840247284Sjmatthew int
354940247284Sjmatthew bnxt_get_sffpage(struct bnxt_softc *softc, struct if_sffpage *sff)
355040247284Sjmatthew {
355140247284Sjmatthew 	struct hwrm_port_phy_i2c_read_input req;
355240247284Sjmatthew 	struct hwrm_port_phy_i2c_read_output *out;
355340247284Sjmatthew 	int offset;
355440247284Sjmatthew 
355540247284Sjmatthew 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_I2C_READ);
355640247284Sjmatthew 	req.i2c_slave_addr = sff->sff_addr;
355740247284Sjmatthew 	req.page_number = htole16(sff->sff_page);
355840247284Sjmatthew 
355940247284Sjmatthew 	for (offset = 0; offset < 256; offset += sizeof(out->data)) {
356040247284Sjmatthew 		req.page_offset = htole16(offset);
356140247284Sjmatthew 		req.data_length = sizeof(out->data);
356240247284Sjmatthew 		req.enables = htole32(HWRM_PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET);
356340247284Sjmatthew 
356440247284Sjmatthew 		if (hwrm_send_message(softc, &req, sizeof(req))) {
356540247284Sjmatthew 			printf("%s: failed to read i2c data\n", DEVNAME(softc));
356640247284Sjmatthew 			return 1;
356740247284Sjmatthew 		}
356840247284Sjmatthew 
356940247284Sjmatthew 		out = (struct hwrm_port_phy_i2c_read_output *)
357040247284Sjmatthew 		    BNXT_DMA_KVA(softc->sc_cmd_resp);
357140247284Sjmatthew 		memcpy(sff->sff_data + offset, out->data, sizeof(out->data));
357240247284Sjmatthew 	}
357340247284Sjmatthew 
357440247284Sjmatthew 	return 0;
357540247284Sjmatthew }
3576