1*0f9891f1Sjsg /* $OpenBSD: if_oce.c,v 1.109 2024/05/24 06:02:56 jsg Exp $ */
23027f3a5Smikeb
33027f3a5Smikeb /*
43027f3a5Smikeb * Copyright (c) 2012 Mike Belopuhov
53027f3a5Smikeb *
63027f3a5Smikeb * Permission to use, copy, modify, and distribute this software for any
73027f3a5Smikeb * purpose with or without fee is hereby granted, provided that the above
83027f3a5Smikeb * copyright notice and this permission notice appear in all copies.
93027f3a5Smikeb *
103027f3a5Smikeb * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113027f3a5Smikeb * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123027f3a5Smikeb * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133027f3a5Smikeb * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143027f3a5Smikeb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153027f3a5Smikeb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163027f3a5Smikeb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173027f3a5Smikeb */
183027f3a5Smikeb
193027f3a5Smikeb /*-
203027f3a5Smikeb * Copyright (C) 2012 Emulex
213027f3a5Smikeb * All rights reserved.
223027f3a5Smikeb *
233027f3a5Smikeb * Redistribution and use in source and binary forms, with or without
243027f3a5Smikeb * modification, are permitted provided that the following conditions are met:
253027f3a5Smikeb *
263027f3a5Smikeb * 1. Redistributions of source code must retain the above copyright notice,
273027f3a5Smikeb * this list of conditions and the following disclaimer.
283027f3a5Smikeb *
293027f3a5Smikeb * 2. Redistributions in binary form must reproduce the above copyright
303027f3a5Smikeb * notice, this list of conditions and the following disclaimer in the
313027f3a5Smikeb * documentation and/or other materials provided with the distribution.
323027f3a5Smikeb *
333027f3a5Smikeb * 3. Neither the name of the Emulex Corporation nor the names of its
343027f3a5Smikeb * contributors may be used to endorse or promote products derived from
353027f3a5Smikeb * this software without specific prior written permission.
363027f3a5Smikeb *
373027f3a5Smikeb * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
383027f3a5Smikeb * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
393027f3a5Smikeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
403027f3a5Smikeb * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
413027f3a5Smikeb * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
423027f3a5Smikeb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
433027f3a5Smikeb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
443027f3a5Smikeb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
453027f3a5Smikeb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
463027f3a5Smikeb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
473027f3a5Smikeb * POSSIBILITY OF SUCH DAMAGE.
483027f3a5Smikeb *
493027f3a5Smikeb * Contact Information:
503027f3a5Smikeb * freebsd-drivers@emulex.com
513027f3a5Smikeb *
523027f3a5Smikeb * Emulex
533027f3a5Smikeb * 3333 Susan Street
543027f3a5Smikeb * Costa Mesa, CA 92626
553027f3a5Smikeb */
563027f3a5Smikeb
573027f3a5Smikeb #include "bpfilter.h"
583027f3a5Smikeb #include "vlan.h"
593027f3a5Smikeb
603027f3a5Smikeb #include <sys/param.h>
613027f3a5Smikeb #include <sys/systm.h>
623027f3a5Smikeb #include <sys/sockio.h>
633027f3a5Smikeb #include <sys/mbuf.h>
643027f3a5Smikeb #include <sys/malloc.h>
653027f3a5Smikeb #include <sys/device.h>
663027f3a5Smikeb #include <sys/socket.h>
67753c43a0Smikeb #include <sys/queue.h>
683027f3a5Smikeb #include <sys/timeout.h>
693027f3a5Smikeb #include <sys/pool.h>
703027f3a5Smikeb
713027f3a5Smikeb #include <net/if.h>
723027f3a5Smikeb #include <net/if_media.h>
733027f3a5Smikeb
743027f3a5Smikeb #include <netinet/in.h>
753027f3a5Smikeb #include <netinet/if_ether.h>
763027f3a5Smikeb
773027f3a5Smikeb #if NBPFILTER > 0
783027f3a5Smikeb #include <net/bpf.h>
793027f3a5Smikeb #endif
803027f3a5Smikeb
813027f3a5Smikeb #include <dev/pci/pcireg.h>
823027f3a5Smikeb #include <dev/pci/pcivar.h>
833027f3a5Smikeb #include <dev/pci/pcidevs.h>
843027f3a5Smikeb
85b2b84680Smikeb #include <dev/pci/if_ocereg.h>
86fc40f6ceSmikeb
87fc40f6ceSmikeb #ifndef TRUE
88fc40f6ceSmikeb #define TRUE 1
89fc40f6ceSmikeb #endif
90fc40f6ceSmikeb #ifndef FALSE
91fc40f6ceSmikeb #define FALSE 0
92fc40f6ceSmikeb #endif
93fc40f6ceSmikeb
94fc40f6ceSmikeb #define OCE_MBX_TIMEOUT 5
95fc40f6ceSmikeb
96d5413815Smikeb #define OCE_MAX_PAYLOAD 65536
97d5413815Smikeb
98fc40f6ceSmikeb #define OCE_TX_RING_SIZE 512
99fc40f6ceSmikeb #define OCE_RX_RING_SIZE 1024
100fc40f6ceSmikeb
101fc40f6ceSmikeb /* This should be powers of 2. Like 2,4,8 & 16 */
102fc40f6ceSmikeb #define OCE_MAX_RSS 4 /* TODO: 8 */
103fc40f6ceSmikeb #define OCE_MAX_RQ OCE_MAX_RSS + 1 /* one default queue */
104fc40f6ceSmikeb #define OCE_MAX_WQ 8
105fc40f6ceSmikeb
106fc40f6ceSmikeb #define OCE_MAX_EQ 32
107fc40f6ceSmikeb #define OCE_MAX_CQ OCE_MAX_RQ + OCE_MAX_WQ + 1 /* one MCC queue */
108fc40f6ceSmikeb #define OCE_MAX_CQ_EQ 8 /* Max CQ that can attached to an EQ */
109fc40f6ceSmikeb
110fc40f6ceSmikeb #define OCE_DEFAULT_EQD 80
111fc40f6ceSmikeb
112fc40f6ceSmikeb #define OCE_MIN_MTU 256
113fc40f6ceSmikeb #define OCE_MAX_MTU 9000
114fc40f6ceSmikeb
115fc40f6ceSmikeb #define OCE_MAX_RQ_COMPL 64
116fc40f6ceSmikeb #define OCE_MAX_RQ_POSTS 255
117fc40f6ceSmikeb #define OCE_RX_BUF_SIZE 2048
118fc40f6ceSmikeb
119fc40f6ceSmikeb #define OCE_MAX_TX_ELEMENTS 29
120fc40f6ceSmikeb #define OCE_MAX_TX_DESC 1024
121fc40f6ceSmikeb #define OCE_MAX_TX_SIZE 65535
122fc40f6ceSmikeb
123fc40f6ceSmikeb #define OCE_MEM_KVA(_m) ((void *)((_m)->vaddr))
124d5413815Smikeb #define OCE_MEM_DVA(_m) ((_m)->paddr)
125fc40f6ceSmikeb
126fc40f6ceSmikeb #define OCE_WQ_FOREACH(sc, wq, i) \
127fc40f6ceSmikeb for (i = 0, wq = sc->sc_wq[0]; i < sc->sc_nwq; i++, wq = sc->sc_wq[i])
128fc40f6ceSmikeb #define OCE_RQ_FOREACH(sc, rq, i) \
129fc40f6ceSmikeb for (i = 0, rq = sc->sc_rq[0]; i < sc->sc_nrq; i++, rq = sc->sc_rq[i])
130fc40f6ceSmikeb #define OCE_EQ_FOREACH(sc, eq, i) \
131fc40f6ceSmikeb for (i = 0, eq = sc->sc_eq[0]; i < sc->sc_neq; i++, eq = sc->sc_eq[i])
132fc40f6ceSmikeb #define OCE_CQ_FOREACH(sc, cq, i) \
133fc40f6ceSmikeb for (i = 0, cq = sc->sc_cq[0]; i < sc->sc_ncq; i++, cq = sc->sc_cq[i])
134fc40f6ceSmikeb #define OCE_RING_FOREACH(_r, _v, _c) \
135fc40f6ceSmikeb for ((_v) = oce_ring_first(_r); _c; (_v) = oce_ring_next(_r))
136fc40f6ceSmikeb
137fc40f6ceSmikeb static inline int
ilog2(unsigned int v)138fc40f6ceSmikeb ilog2(unsigned int v)
139fc40f6ceSmikeb {
140fc40f6ceSmikeb int r = 0;
141fc40f6ceSmikeb
142fc40f6ceSmikeb while (v >>= 1)
143fc40f6ceSmikeb r++;
144fc40f6ceSmikeb return (r);
145fc40f6ceSmikeb }
146fc40f6ceSmikeb
147fc40f6ceSmikeb struct oce_pkt {
148fc40f6ceSmikeb struct mbuf * mbuf;
149fc40f6ceSmikeb bus_dmamap_t map;
150fc40f6ceSmikeb int nsegs;
151fc40f6ceSmikeb SIMPLEQ_ENTRY(oce_pkt) entry;
152fc40f6ceSmikeb };
153fc40f6ceSmikeb SIMPLEQ_HEAD(oce_pkt_list, oce_pkt);
154fc40f6ceSmikeb
155fc40f6ceSmikeb struct oce_dma_mem {
156fc40f6ceSmikeb bus_dma_tag_t tag;
157fc40f6ceSmikeb bus_dmamap_t map;
158fc40f6ceSmikeb bus_dma_segment_t segs;
159fc40f6ceSmikeb int nsegs;
160fc40f6ceSmikeb bus_size_t size;
161fc40f6ceSmikeb caddr_t vaddr;
162fc40f6ceSmikeb bus_addr_t paddr;
163fc40f6ceSmikeb };
164fc40f6ceSmikeb
165fc40f6ceSmikeb struct oce_ring {
166fc40f6ceSmikeb int index;
167fc40f6ceSmikeb int nitems;
168fc40f6ceSmikeb int nused;
169fc40f6ceSmikeb int isize;
170fc40f6ceSmikeb struct oce_dma_mem dma;
171fc40f6ceSmikeb };
172fc40f6ceSmikeb
173fc40f6ceSmikeb struct oce_softc;
174fc40f6ceSmikeb
175fc40f6ceSmikeb enum cq_len {
176fc40f6ceSmikeb CQ_LEN_256 = 256,
177fc40f6ceSmikeb CQ_LEN_512 = 512,
178fc40f6ceSmikeb CQ_LEN_1024 = 1024
179fc40f6ceSmikeb };
180fc40f6ceSmikeb
181fc40f6ceSmikeb enum eq_len {
182fc40f6ceSmikeb EQ_LEN_256 = 256,
183fc40f6ceSmikeb EQ_LEN_512 = 512,
184fc40f6ceSmikeb EQ_LEN_1024 = 1024,
185fc40f6ceSmikeb EQ_LEN_2048 = 2048,
186fc40f6ceSmikeb EQ_LEN_4096 = 4096
187fc40f6ceSmikeb };
188fc40f6ceSmikeb
189fc40f6ceSmikeb enum eqe_size {
190fc40f6ceSmikeb EQE_SIZE_4 = 4,
191fc40f6ceSmikeb EQE_SIZE_16 = 16
192fc40f6ceSmikeb };
193fc40f6ceSmikeb
194fc40f6ceSmikeb enum qtype {
195fc40f6ceSmikeb QTYPE_EQ,
196fc40f6ceSmikeb QTYPE_MQ,
197fc40f6ceSmikeb QTYPE_WQ,
198fc40f6ceSmikeb QTYPE_RQ,
199fc40f6ceSmikeb QTYPE_CQ,
200fc40f6ceSmikeb QTYPE_RSS
201fc40f6ceSmikeb };
202fc40f6ceSmikeb
203fc40f6ceSmikeb struct oce_eq {
204fc40f6ceSmikeb struct oce_softc * sc;
205fc40f6ceSmikeb struct oce_ring * ring;
206fc40f6ceSmikeb enum qtype type;
207fc40f6ceSmikeb int id;
208fc40f6ceSmikeb
209fc40f6ceSmikeb struct oce_cq * cq[OCE_MAX_CQ_EQ];
210fc40f6ceSmikeb int cq_valid;
211fc40f6ceSmikeb
212fc40f6ceSmikeb int nitems;
213fc40f6ceSmikeb int isize;
214fc40f6ceSmikeb int delay;
215fc40f6ceSmikeb };
216fc40f6ceSmikeb
217fc40f6ceSmikeb struct oce_cq {
218fc40f6ceSmikeb struct oce_softc * sc;
219fc40f6ceSmikeb struct oce_ring * ring;
220fc40f6ceSmikeb enum qtype type;
221fc40f6ceSmikeb int id;
222fc40f6ceSmikeb
223fc40f6ceSmikeb struct oce_eq * eq;
224fc40f6ceSmikeb
225fc40f6ceSmikeb void (*cq_intr)(void *);
226fc40f6ceSmikeb void * cb_arg;
227fc40f6ceSmikeb
228fc40f6ceSmikeb int nitems;
229fc40f6ceSmikeb int nodelay;
230fc40f6ceSmikeb int eventable;
231fc40f6ceSmikeb int ncoalesce;
232fc40f6ceSmikeb };
233fc40f6ceSmikeb
234fc40f6ceSmikeb struct oce_mq {
235fc40f6ceSmikeb struct oce_softc * sc;
236fc40f6ceSmikeb struct oce_ring * ring;
237fc40f6ceSmikeb enum qtype type;
238fc40f6ceSmikeb int id;
239fc40f6ceSmikeb
240fc40f6ceSmikeb struct oce_cq * cq;
241fc40f6ceSmikeb
242fc40f6ceSmikeb int nitems;
243fc40f6ceSmikeb };
244fc40f6ceSmikeb
245fc40f6ceSmikeb struct oce_wq {
246fc40f6ceSmikeb struct oce_softc * sc;
247fc40f6ceSmikeb struct oce_ring * ring;
248fc40f6ceSmikeb enum qtype type;
249fc40f6ceSmikeb int id;
250fc40f6ceSmikeb
251fc40f6ceSmikeb struct oce_cq * cq;
252fc40f6ceSmikeb
253fc40f6ceSmikeb struct oce_pkt_list pkt_list;
254fc40f6ceSmikeb struct oce_pkt_list pkt_free;
255fc40f6ceSmikeb
256fc40f6ceSmikeb int nitems;
257fc40f6ceSmikeb };
258fc40f6ceSmikeb
259fc40f6ceSmikeb struct oce_rq {
260fc40f6ceSmikeb struct oce_softc * sc;
261fc40f6ceSmikeb struct oce_ring * ring;
262fc40f6ceSmikeb enum qtype type;
263fc40f6ceSmikeb int id;
264fc40f6ceSmikeb
265fc40f6ceSmikeb struct oce_cq * cq;
266fc40f6ceSmikeb
2677102ef8dSdlg struct if_rxring rxring;
268fc40f6ceSmikeb struct oce_pkt_list pkt_list;
269fc40f6ceSmikeb struct oce_pkt_list pkt_free;
270fc40f6ceSmikeb
271fc40f6ceSmikeb uint32_t rss_cpuid;
272fc40f6ceSmikeb
273fc40f6ceSmikeb #ifdef OCE_LRO
274fc40f6ceSmikeb struct lro_ctrl lro;
275fc40f6ceSmikeb int lro_pkts_queued;
276fc40f6ceSmikeb #endif
277fc40f6ceSmikeb
278fc40f6ceSmikeb int nitems;
279fc40f6ceSmikeb int fragsize;
280fc40f6ceSmikeb int mtu;
281fc40f6ceSmikeb int rss;
282fc40f6ceSmikeb };
283fc40f6ceSmikeb
284fc40f6ceSmikeb struct oce_softc {
285fc40f6ceSmikeb struct device sc_dev;
286fc40f6ceSmikeb
287fc40f6ceSmikeb uint sc_flags;
288fc40f6ceSmikeb #define OCE_F_BE2 0x00000001
289fc40f6ceSmikeb #define OCE_F_BE3 0x00000002
290fc40f6ceSmikeb #define OCE_F_XE201 0x00000008
291fc40f6ceSmikeb #define OCE_F_BE3_NATIVE 0x00000100
292fc40f6ceSmikeb #define OCE_F_RESET_RQD 0x00001000
293fc40f6ceSmikeb #define OCE_F_MBOX_ENDIAN_RQD 0x00002000
294fc40f6ceSmikeb
295fc40f6ceSmikeb bus_dma_tag_t sc_dmat;
296fc40f6ceSmikeb
297fc40f6ceSmikeb bus_space_tag_t sc_cfg_iot;
298fc40f6ceSmikeb bus_space_handle_t sc_cfg_ioh;
299fc40f6ceSmikeb bus_size_t sc_cfg_size;
300fc40f6ceSmikeb
301fc40f6ceSmikeb bus_space_tag_t sc_csr_iot;
302fc40f6ceSmikeb bus_space_handle_t sc_csr_ioh;
303fc40f6ceSmikeb bus_size_t sc_csr_size;
304fc40f6ceSmikeb
305fc40f6ceSmikeb bus_space_tag_t sc_db_iot;
306fc40f6ceSmikeb bus_space_handle_t sc_db_ioh;
307fc40f6ceSmikeb bus_size_t sc_db_size;
308fc40f6ceSmikeb
309fc40f6ceSmikeb void * sc_ih;
310fc40f6ceSmikeb
311fc40f6ceSmikeb struct arpcom sc_ac;
312fc40f6ceSmikeb struct ifmedia sc_media;
313fc40f6ceSmikeb ushort sc_link_up;
314fc40f6ceSmikeb ushort sc_link_speed;
315f2a0e423Sstsp uint64_t sc_fc;
316fc40f6ceSmikeb
317fc40f6ceSmikeb struct oce_dma_mem sc_mbx;
318d5413815Smikeb struct oce_dma_mem sc_pld;
319fc40f6ceSmikeb
320fc40f6ceSmikeb uint sc_port;
321fc40f6ceSmikeb uint sc_fmode;
322fc40f6ceSmikeb
323fc40f6ceSmikeb struct oce_wq * sc_wq[OCE_MAX_WQ]; /* TX work queues */
324fc40f6ceSmikeb struct oce_rq * sc_rq[OCE_MAX_RQ]; /* RX work queues */
325fc40f6ceSmikeb struct oce_cq * sc_cq[OCE_MAX_CQ]; /* Completion queues */
326fc40f6ceSmikeb struct oce_eq * sc_eq[OCE_MAX_EQ]; /* Event queues */
327fc40f6ceSmikeb struct oce_mq * sc_mq; /* Mailbox queue */
328fc40f6ceSmikeb
329fc40f6ceSmikeb ushort sc_neq;
330fc40f6ceSmikeb ushort sc_ncq;
331fc40f6ceSmikeb ushort sc_nrq;
332fc40f6ceSmikeb ushort sc_nwq;
333fc40f6ceSmikeb ushort sc_nintr;
334fc40f6ceSmikeb
335fc40f6ceSmikeb ushort sc_tx_ring_size;
336fc40f6ceSmikeb ushort sc_rx_ring_size;
337fc40f6ceSmikeb ushort sc_rss_enable;
338fc40f6ceSmikeb
339fc40f6ceSmikeb uint32_t sc_if_id; /* interface ID */
340fc40f6ceSmikeb uint32_t sc_pmac_id; /* PMAC id */
341fc40f6ceSmikeb char sc_macaddr[ETHER_ADDR_LEN];
342fc40f6ceSmikeb
343fc40f6ceSmikeb uint32_t sc_pvid;
344fc40f6ceSmikeb
345fc40f6ceSmikeb uint64_t sc_rx_errors;
346fc40f6ceSmikeb uint64_t sc_tx_errors;
347fc40f6ceSmikeb
348fc40f6ceSmikeb struct timeout sc_tick;
349fc40f6ceSmikeb struct timeout sc_rxrefill;
35005201e9aSmikeb
35105201e9aSmikeb void * sc_statcmd;
352fc40f6ceSmikeb };
353fc40f6ceSmikeb
354fc40f6ceSmikeb #define IS_BE(sc) ISSET((sc)->sc_flags, OCE_F_BE2 | OCE_F_BE3)
355fc40f6ceSmikeb #define IS_XE201(sc) ISSET((sc)->sc_flags, OCE_F_XE201)
356fc40f6ceSmikeb
357fc40f6ceSmikeb #define ADDR_HI(x) ((uint32_t)((uint64_t)(x) >> 32))
358fc40f6ceSmikeb #define ADDR_LO(x) ((uint32_t)((uint64_t)(x) & 0xffffffff))
359fc40f6ceSmikeb
360fc40f6ceSmikeb #define IF_LRO_ENABLED(ifp) ISSET((ifp)->if_capabilities, IFCAP_LRO)
3613027f3a5Smikeb
36236dc4c47Smikeb int oce_match(struct device *, void *, void *);
36332735beaSmikeb void oce_attach(struct device *, struct device *, void *);
36432735beaSmikeb int oce_pci_alloc(struct oce_softc *, struct pci_attach_args *);
365ef89f9e6Smpi void oce_attachhook(struct device *);
36632735beaSmikeb void oce_attach_ifp(struct oce_softc *);
36732735beaSmikeb int oce_ioctl(struct ifnet *, u_long, caddr_t);
368aae3f036Smikeb int oce_rxrinfo(struct oce_softc *, struct if_rxrinfo *);
36932735beaSmikeb void oce_iff(struct oce_softc *);
37032735beaSmikeb void oce_link_status(struct oce_softc *);
37132735beaSmikeb void oce_media_status(struct ifnet *, struct ifmediareq *);
37232735beaSmikeb int oce_media_change(struct ifnet *);
37332735beaSmikeb void oce_tick(void *);
37432735beaSmikeb void oce_init(void *);
37532735beaSmikeb void oce_stop(struct oce_softc *);
37632735beaSmikeb void oce_watchdog(struct ifnet *);
37732735beaSmikeb void oce_start(struct ifnet *);
37832735beaSmikeb int oce_encap(struct oce_softc *, struct mbuf **, int wqidx);
37933279783Smikeb #ifdef OCE_TSO
38033279783Smikeb struct mbuf *
38132735beaSmikeb oce_tso(struct oce_softc *, struct mbuf **);
38233279783Smikeb #endif
38332735beaSmikeb int oce_intr(void *);
38432735beaSmikeb void oce_intr_wq(void *);
38532735beaSmikeb void oce_txeof(struct oce_wq *);
38632735beaSmikeb void oce_intr_rq(void *);
38732735beaSmikeb void oce_rxeof(struct oce_rq *, struct oce_nic_rx_cqe *);
38832735beaSmikeb void oce_rxeoc(struct oce_rq *, struct oce_nic_rx_cqe *);
38932735beaSmikeb int oce_vtp_valid(struct oce_softc *, struct oce_nic_rx_cqe *);
39032735beaSmikeb int oce_port_valid(struct oce_softc *, struct oce_nic_rx_cqe *);
3913027f3a5Smikeb #ifdef OCE_LRO
39232735beaSmikeb void oce_flush_lro(struct oce_rq *);
39332735beaSmikeb int oce_init_lro(struct oce_softc *);
39432735beaSmikeb void oce_free_lro(struct oce_softc *);
3953027f3a5Smikeb #endif
39632735beaSmikeb int oce_get_buf(struct oce_rq *);
39732735beaSmikeb int oce_alloc_rx_bufs(struct oce_rq *);
39832735beaSmikeb void oce_refill_rx(void *);
39932735beaSmikeb void oce_free_posted_rxbuf(struct oce_rq *);
40032735beaSmikeb void oce_intr_mq(void *);
40132735beaSmikeb void oce_link_event(struct oce_softc *,
40232735beaSmikeb struct oce_async_cqe_link_state *);
4033027f3a5Smikeb
40432735beaSmikeb int oce_init_queues(struct oce_softc *);
40532735beaSmikeb void oce_release_queues(struct oce_softc *);
40633279783Smikeb struct oce_wq *oce_create_wq(struct oce_softc *, struct oce_eq *);
40733279783Smikeb void oce_drain_wq(struct oce_wq *);
40833279783Smikeb void oce_destroy_wq(struct oce_wq *);
40933279783Smikeb struct oce_rq *
41033279783Smikeb oce_create_rq(struct oce_softc *, struct oce_eq *, int rss);
41133279783Smikeb void oce_drain_rq(struct oce_rq *);
41233279783Smikeb void oce_destroy_rq(struct oce_rq *);
41333279783Smikeb struct oce_eq *
41433279783Smikeb oce_create_eq(struct oce_softc *);
41533279783Smikeb static inline void
41633279783Smikeb oce_arm_eq(struct oce_eq *, int neqe, int rearm, int clearint);
41733279783Smikeb void oce_drain_eq(struct oce_eq *);
41833279783Smikeb void oce_destroy_eq(struct oce_eq *);
41933279783Smikeb struct oce_mq *
42033279783Smikeb oce_create_mq(struct oce_softc *, struct oce_eq *);
42133279783Smikeb void oce_drain_mq(struct oce_mq *);
42233279783Smikeb void oce_destroy_mq(struct oce_mq *);
42333279783Smikeb struct oce_cq *
42433279783Smikeb oce_create_cq(struct oce_softc *, struct oce_eq *, int nitems,
42533279783Smikeb int isize, int eventable, int nodelay, int ncoalesce);
42633279783Smikeb static inline void
42733279783Smikeb oce_arm_cq(struct oce_cq *, int ncqe, int rearm);
42833279783Smikeb void oce_destroy_cq(struct oce_cq *);
429a7c4bff9Smikeb
43033279783Smikeb int oce_dma_alloc(struct oce_softc *, bus_size_t, struct oce_dma_mem *);
43133279783Smikeb void oce_dma_free(struct oce_softc *, struct oce_dma_mem *);
432fc40f6ceSmikeb #define oce_dma_sync(d, f) \
433fc40f6ceSmikeb bus_dmamap_sync((d)->tag, (d)->map, 0, (d)->map->dm_mapsize, f)
4347d5bbea0Smikeb
43533279783Smikeb struct oce_ring *
43633279783Smikeb oce_create_ring(struct oce_softc *, int nitems, int isize, int maxseg);
43733279783Smikeb void oce_destroy_ring(struct oce_softc *, struct oce_ring *);
43833279783Smikeb int oce_load_ring(struct oce_softc *, struct oce_ring *,
4399ec9e807Smikeb struct oce_pa *, int max_segs);
44033279783Smikeb static inline void *
44133279783Smikeb oce_ring_get(struct oce_ring *);
44233279783Smikeb static inline void *
44333279783Smikeb oce_ring_first(struct oce_ring *);
44433279783Smikeb static inline void *
44533279783Smikeb oce_ring_next(struct oce_ring *);
44633279783Smikeb struct oce_pkt *
44733279783Smikeb oce_pkt_alloc(struct oce_softc *, size_t size, int nsegs,
44824f2625fSmikeb int maxsegsz);
44933279783Smikeb void oce_pkt_free(struct oce_softc *, struct oce_pkt *);
45033279783Smikeb static inline struct oce_pkt *
45133279783Smikeb oce_pkt_get(struct oce_pkt_list *);
45233279783Smikeb static inline void
45333279783Smikeb oce_pkt_put(struct oce_pkt_list *, struct oce_pkt *);
454753c43a0Smikeb
45533279783Smikeb int oce_init_fw(struct oce_softc *);
45633279783Smikeb int oce_mbox_init(struct oce_softc *);
45733279783Smikeb int oce_mbox_dispatch(struct oce_softc *);
45833279783Smikeb int oce_cmd(struct oce_softc *, int subsys, int opcode, int version,
459b2b84680Smikeb void *payload, int length);
46033279783Smikeb void oce_first_mcc(struct oce_softc *);
461b2b84680Smikeb
46233279783Smikeb int oce_get_fw_config(struct oce_softc *);
46333279783Smikeb int oce_check_native_mode(struct oce_softc *);
46433279783Smikeb int oce_create_iface(struct oce_softc *, uint8_t *macaddr);
46533279783Smikeb int oce_config_vlan(struct oce_softc *, struct normal_vlan *vtags,
4664078f66aSmikeb int nvtags, int untagged, int promisc);
467f2a0e423Sstsp int oce_set_flow_control(struct oce_softc *, uint64_t);
46833279783Smikeb int oce_config_rss(struct oce_softc *, int enable);
46933279783Smikeb int oce_update_mcast(struct oce_softc *, uint8_t multi[][ETHER_ADDR_LEN],
47033279783Smikeb int naddr);
47133279783Smikeb int oce_set_promisc(struct oce_softc *, int enable);
47233279783Smikeb int oce_get_link_status(struct oce_softc *);
473b2b84680Smikeb
47433279783Smikeb void oce_macaddr_set(struct oce_softc *);
47533279783Smikeb int oce_macaddr_get(struct oce_softc *, uint8_t *macaddr);
47633279783Smikeb int oce_macaddr_add(struct oce_softc *, uint8_t *macaddr, uint32_t *pmac);
47733279783Smikeb int oce_macaddr_del(struct oce_softc *, uint32_t pmac);
478b2b84680Smikeb
47933279783Smikeb int oce_new_rq(struct oce_softc *, struct oce_rq *);
48033279783Smikeb int oce_new_wq(struct oce_softc *, struct oce_wq *);
48133279783Smikeb int oce_new_mq(struct oce_softc *, struct oce_mq *);
48233279783Smikeb int oce_new_eq(struct oce_softc *, struct oce_eq *);
48333279783Smikeb int oce_new_cq(struct oce_softc *, struct oce_cq *);
484b2b84680Smikeb
48505201e9aSmikeb int oce_init_stats(struct oce_softc *);
48605201e9aSmikeb int oce_update_stats(struct oce_softc *);
48733279783Smikeb int oce_stats_be2(struct oce_softc *, uint64_t *, uint64_t *);
48833279783Smikeb int oce_stats_be3(struct oce_softc *, uint64_t *, uint64_t *);
48933279783Smikeb int oce_stats_xe(struct oce_softc *, uint64_t *, uint64_t *);
490b2b84680Smikeb
491753c43a0Smikeb struct pool *oce_pkt_pool;
492753c43a0Smikeb
4933027f3a5Smikeb struct cfdriver oce_cd = {
4943027f3a5Smikeb NULL, "oce", DV_IFNET
4953027f3a5Smikeb };
4963027f3a5Smikeb
4978d2c75e4Smpi const struct cfattach oce_ca = {
49836dc4c47Smikeb sizeof(struct oce_softc), oce_match, oce_attach, NULL, NULL
4993027f3a5Smikeb };
5003027f3a5Smikeb
5013027f3a5Smikeb const struct pci_matchid oce_devices[] = {
5023027f3a5Smikeb { PCI_VENDOR_SERVERENGINES, PCI_PRODUCT_SERVERENGINES_BE2 },
5033027f3a5Smikeb { PCI_VENDOR_SERVERENGINES, PCI_PRODUCT_SERVERENGINES_BE3 },
5043027f3a5Smikeb { PCI_VENDOR_SERVERENGINES, PCI_PRODUCT_SERVERENGINES_OCBE2 },
5053027f3a5Smikeb { PCI_VENDOR_SERVERENGINES, PCI_PRODUCT_SERVERENGINES_OCBE3 },
5063027f3a5Smikeb { PCI_VENDOR_EMULEX, PCI_PRODUCT_EMULEX_XE201 },
5073027f3a5Smikeb };
5083027f3a5Smikeb
5093027f3a5Smikeb int
oce_match(struct device * parent,void * match,void * aux)51036dc4c47Smikeb oce_match(struct device *parent, void *match, void *aux)
5113027f3a5Smikeb {
5123027f3a5Smikeb return (pci_matchbyid(aux, oce_devices, nitems(oce_devices)));
5133027f3a5Smikeb }
5143027f3a5Smikeb
5153027f3a5Smikeb void
oce_attach(struct device * parent,struct device * self,void * aux)5163027f3a5Smikeb oce_attach(struct device *parent, struct device *self, void *aux)
5173027f3a5Smikeb {
5183027f3a5Smikeb struct pci_attach_args *pa = (struct pci_attach_args *)aux;
5193027f3a5Smikeb struct oce_softc *sc = (struct oce_softc *)self;
520fc40f6ceSmikeb const char *intrstr = NULL;
521fc40f6ceSmikeb pci_intr_handle_t ih;
5223027f3a5Smikeb
523176128bcSmikeb switch (PCI_PRODUCT(pa->pa_id)) {
5243027f3a5Smikeb case PCI_PRODUCT_SERVERENGINES_BE2:
5253027f3a5Smikeb case PCI_PRODUCT_SERVERENGINES_OCBE2:
526fc40f6ceSmikeb SET(sc->sc_flags, OCE_F_BE2);
5273027f3a5Smikeb break;
5283027f3a5Smikeb case PCI_PRODUCT_SERVERENGINES_BE3:
5293027f3a5Smikeb case PCI_PRODUCT_SERVERENGINES_OCBE3:
530fc40f6ceSmikeb SET(sc->sc_flags, OCE_F_BE3);
5313027f3a5Smikeb break;
5323027f3a5Smikeb case PCI_PRODUCT_EMULEX_XE201:
533fc40f6ceSmikeb SET(sc->sc_flags, OCE_F_XE201);
5343027f3a5Smikeb break;
5353027f3a5Smikeb }
5363027f3a5Smikeb
537fc40f6ceSmikeb sc->sc_dmat = pa->pa_dmat;
538753c43a0Smikeb if (oce_pci_alloc(sc, pa))
5393027f3a5Smikeb return;
5403027f3a5Smikeb
541fc40f6ceSmikeb sc->sc_tx_ring_size = OCE_TX_RING_SIZE;
542fc40f6ceSmikeb sc->sc_rx_ring_size = OCE_RX_RING_SIZE;
5433027f3a5Smikeb
544176128bcSmikeb /* create the bootstrap mailbox */
545fc40f6ceSmikeb if (oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->sc_mbx)) {
546176128bcSmikeb printf(": failed to allocate mailbox memory\n");
5473027f3a5Smikeb return;
548176128bcSmikeb }
549d5413815Smikeb if (oce_dma_alloc(sc, OCE_MAX_PAYLOAD, &sc->sc_pld)) {
550d5413815Smikeb printf(": failed to allocate payload memory\n");
551d5413815Smikeb goto fail_1;
552d5413815Smikeb }
553176128bcSmikeb
554176128bcSmikeb if (oce_init_fw(sc))
555d5413815Smikeb goto fail_2;
556176128bcSmikeb
557176128bcSmikeb if (oce_mbox_init(sc)) {
558176128bcSmikeb printf(": failed to initialize mailbox\n");
559d5413815Smikeb goto fail_2;
560176128bcSmikeb }
561176128bcSmikeb
562b8b7fdccSmikeb if (oce_get_fw_config(sc)) {
563b8b7fdccSmikeb printf(": failed to get firmware configuration\n");
564d5413815Smikeb goto fail_2;
565b8b7fdccSmikeb }
566b8b7fdccSmikeb
567fc40f6ceSmikeb if (ISSET(sc->sc_flags, OCE_F_BE3)) {
568176128bcSmikeb if (oce_check_native_mode(sc))
569d5413815Smikeb goto fail_2;
570c0000edeSmikeb }
571176128bcSmikeb
572fc40f6ceSmikeb if (oce_macaddr_get(sc, sc->sc_macaddr)) {
573176128bcSmikeb printf(": failed to fetch MAC address\n");
574d5413815Smikeb goto fail_2;
575176128bcSmikeb }
5768f478c19Schris memcpy(sc->sc_ac.ac_enaddr, sc->sc_macaddr, ETHER_ADDR_LEN);
5773027f3a5Smikeb
578753c43a0Smikeb if (oce_pkt_pool == NULL) {
579753c43a0Smikeb oce_pkt_pool = malloc(sizeof(struct pool), M_DEVBUF, M_NOWAIT);
580753c43a0Smikeb if (oce_pkt_pool == NULL) {
581753c43a0Smikeb printf(": unable to allocate descriptor pool\n");
582d5413815Smikeb goto fail_2;
583753c43a0Smikeb }
5841378bae2Sdlg pool_init(oce_pkt_pool, sizeof(struct oce_pkt), 0, IPL_NET,
5851378bae2Sdlg 0, "ocepkts", NULL);
586753c43a0Smikeb }
5873027f3a5Smikeb
588fc40f6ceSmikeb /* We allocate a single interrupt resource */
589fc40f6ceSmikeb sc->sc_nintr = 1;
590fc40f6ceSmikeb if (pci_intr_map_msi(pa, &ih) != 0 &&
591fc40f6ceSmikeb pci_intr_map(pa, &ih) != 0) {
592fc40f6ceSmikeb printf(": couldn't map interrupt\n");
593d5413815Smikeb goto fail_2;
594fc40f6ceSmikeb }
595fc40f6ceSmikeb
596fc40f6ceSmikeb intrstr = pci_intr_string(pa->pa_pc, ih);
597b14e12a1Smikeb sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, oce_intr, sc,
598b14e12a1Smikeb sc->sc_dev.dv_xname);
599fc40f6ceSmikeb if (sc->sc_ih == NULL) {
600fc40f6ceSmikeb printf(": couldn't establish interrupt\n");
601fc40f6ceSmikeb if (intrstr != NULL)
602fc40f6ceSmikeb printf(" at %s", intrstr);
603fc40f6ceSmikeb printf("\n");
604d5413815Smikeb goto fail_2;
605fc40f6ceSmikeb }
606fc40f6ceSmikeb printf(": %s", intrstr);
6073027f3a5Smikeb
60805201e9aSmikeb if (oce_init_stats(sc))
60905201e9aSmikeb goto fail_3;
61005201e9aSmikeb
611176128bcSmikeb if (oce_init_queues(sc))
612d5413815Smikeb goto fail_3;
6133027f3a5Smikeb
614c0000edeSmikeb oce_attach_ifp(sc);
6153027f3a5Smikeb
6163027f3a5Smikeb #ifdef OCE_LRO
617176128bcSmikeb if (oce_init_lro(sc))
618d5413815Smikeb goto fail_4;
6193027f3a5Smikeb #endif
6203027f3a5Smikeb
621fc40f6ceSmikeb timeout_set(&sc->sc_tick, oce_tick, sc);
622fc40f6ceSmikeb timeout_set(&sc->sc_rxrefill, oce_refill_rx, sc);
6233027f3a5Smikeb
624ef89f9e6Smpi config_mountroot(self, oce_attachhook);
6253027f3a5Smikeb
626fc40f6ceSmikeb printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
6273027f3a5Smikeb
6283027f3a5Smikeb return;
6293027f3a5Smikeb
6303027f3a5Smikeb #ifdef OCE_LRO
631d5413815Smikeb fail_4:
632753c43a0Smikeb oce_free_lro(sc);
633fc40f6ceSmikeb ether_ifdetach(&sc->sc_ac.ac_if);
634fc40f6ceSmikeb if_detach(&sc->sc_ac.ac_if);
635dcc67c68Smikeb oce_release_queues(sc);
636c0000edeSmikeb #endif
637d5413815Smikeb fail_3:
638fc40f6ceSmikeb pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
639d5413815Smikeb fail_2:
640d5413815Smikeb oce_dma_free(sc, &sc->sc_pld);
641176128bcSmikeb fail_1:
642fc40f6ceSmikeb oce_dma_free(sc, &sc->sc_mbx);
6433027f3a5Smikeb }
6443027f3a5Smikeb
64517c965bbSmikeb int
oce_pci_alloc(struct oce_softc * sc,struct pci_attach_args * pa)64617c965bbSmikeb oce_pci_alloc(struct oce_softc *sc, struct pci_attach_args *pa)
64717c965bbSmikeb {
64817c965bbSmikeb pcireg_t memtype, reg;
64917c965bbSmikeb
65017c965bbSmikeb /* setup the device config region */
65117c965bbSmikeb if (ISSET(sc->sc_flags, OCE_F_BE2))
65217c965bbSmikeb reg = OCE_BAR_CFG_BE2;
65317c965bbSmikeb else
65417c965bbSmikeb reg = OCE_BAR_CFG;
65517c965bbSmikeb
65617c965bbSmikeb memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg);
65717c965bbSmikeb if (pci_mapreg_map(pa, reg, memtype, 0, &sc->sc_cfg_iot,
65817c965bbSmikeb &sc->sc_cfg_ioh, NULL, &sc->sc_cfg_size,
65917c965bbSmikeb IS_BE(sc) ? 0 : 32768)) {
66017c965bbSmikeb printf(": can't find cfg mem space\n");
66117c965bbSmikeb return (ENXIO);
66217c965bbSmikeb }
66317c965bbSmikeb
66417c965bbSmikeb /*
66517c965bbSmikeb * Read the SLI_INTF register and determine whether we
66617c965bbSmikeb * can use this port and its features
66717c965bbSmikeb */
66817c965bbSmikeb reg = pci_conf_read(pa->pa_pc, pa->pa_tag, OCE_INTF_REG_OFFSET);
66917c965bbSmikeb if (OCE_SLI_SIGNATURE(reg) != OCE_INTF_VALID_SIG) {
67017c965bbSmikeb printf(": invalid signature\n");
67117c965bbSmikeb goto fail_1;
67217c965bbSmikeb }
67317c965bbSmikeb if (OCE_SLI_REVISION(reg) != OCE_INTF_SLI_REV4) {
67417c965bbSmikeb printf(": unsupported SLI revision\n");
67517c965bbSmikeb goto fail_1;
67617c965bbSmikeb }
67717c965bbSmikeb if (OCE_SLI_IFTYPE(reg) == OCE_INTF_IF_TYPE_1)
67817c965bbSmikeb SET(sc->sc_flags, OCE_F_MBOX_ENDIAN_RQD);
67917c965bbSmikeb if (OCE_SLI_HINT1(reg) == OCE_INTF_FUNC_RESET_REQD)
68017c965bbSmikeb SET(sc->sc_flags, OCE_F_RESET_RQD);
68117c965bbSmikeb
68217c965bbSmikeb /* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
68317c965bbSmikeb if (IS_BE(sc)) {
68417c965bbSmikeb /* set up CSR region */
68517c965bbSmikeb reg = OCE_BAR_CSR;
68617c965bbSmikeb memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg);
68717c965bbSmikeb if (pci_mapreg_map(pa, reg, memtype, 0, &sc->sc_csr_iot,
68817c965bbSmikeb &sc->sc_csr_ioh, NULL, &sc->sc_csr_size, 0)) {
68917c965bbSmikeb printf(": can't find csr mem space\n");
69017c965bbSmikeb goto fail_1;
69117c965bbSmikeb }
69217c965bbSmikeb
69317c965bbSmikeb /* set up DB doorbell region */
69417c965bbSmikeb reg = OCE_BAR_DB;
69517c965bbSmikeb memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg);
69617c965bbSmikeb if (pci_mapreg_map(pa, reg, memtype, 0, &sc->sc_db_iot,
69717c965bbSmikeb &sc->sc_db_ioh, NULL, &sc->sc_db_size, 0)) {
69817c965bbSmikeb printf(": can't find csr mem space\n");
69917c965bbSmikeb goto fail_2;
70017c965bbSmikeb }
70117c965bbSmikeb } else {
70217c965bbSmikeb sc->sc_csr_iot = sc->sc_db_iot = sc->sc_cfg_iot;
70317c965bbSmikeb sc->sc_csr_ioh = sc->sc_db_ioh = sc->sc_cfg_ioh;
70417c965bbSmikeb }
70517c965bbSmikeb
70617c965bbSmikeb return (0);
70717c965bbSmikeb
70817c965bbSmikeb fail_2:
70917c965bbSmikeb bus_space_unmap(sc->sc_csr_iot, sc->sc_csr_ioh, sc->sc_csr_size);
71017c965bbSmikeb fail_1:
71117c965bbSmikeb bus_space_unmap(sc->sc_cfg_iot, sc->sc_cfg_ioh, sc->sc_cfg_size);
71217c965bbSmikeb return (ENXIO);
71317c965bbSmikeb }
71417c965bbSmikeb
71517c965bbSmikeb static inline uint32_t
oce_read_cfg(struct oce_softc * sc,bus_size_t off)71617c965bbSmikeb oce_read_cfg(struct oce_softc *sc, bus_size_t off)
71717c965bbSmikeb {
71817c965bbSmikeb bus_space_barrier(sc->sc_cfg_iot, sc->sc_cfg_ioh, off, 4,
71917c965bbSmikeb BUS_SPACE_BARRIER_READ);
72017c965bbSmikeb return (bus_space_read_4(sc->sc_cfg_iot, sc->sc_cfg_ioh, off));
72117c965bbSmikeb }
72217c965bbSmikeb
72317c965bbSmikeb static inline uint32_t
oce_read_csr(struct oce_softc * sc,bus_size_t off)72417c965bbSmikeb oce_read_csr(struct oce_softc *sc, bus_size_t off)
72517c965bbSmikeb {
72617c965bbSmikeb bus_space_barrier(sc->sc_csr_iot, sc->sc_csr_ioh, off, 4,
72717c965bbSmikeb BUS_SPACE_BARRIER_READ);
72817c965bbSmikeb return (bus_space_read_4(sc->sc_csr_iot, sc->sc_csr_ioh, off));
72917c965bbSmikeb }
73017c965bbSmikeb
73117c965bbSmikeb static inline uint32_t
oce_read_db(struct oce_softc * sc,bus_size_t off)73217c965bbSmikeb oce_read_db(struct oce_softc *sc, bus_size_t off)
73317c965bbSmikeb {
73417c965bbSmikeb bus_space_barrier(sc->sc_db_iot, sc->sc_db_ioh, off, 4,
73517c965bbSmikeb BUS_SPACE_BARRIER_READ);
73617c965bbSmikeb return (bus_space_read_4(sc->sc_db_iot, sc->sc_db_ioh, off));
73717c965bbSmikeb }
73817c965bbSmikeb
73917c965bbSmikeb static inline void
oce_write_cfg(struct oce_softc * sc,bus_size_t off,uint32_t val)74017c965bbSmikeb oce_write_cfg(struct oce_softc *sc, bus_size_t off, uint32_t val)
74117c965bbSmikeb {
74217c965bbSmikeb bus_space_write_4(sc->sc_cfg_iot, sc->sc_cfg_ioh, off, val);
74317c965bbSmikeb bus_space_barrier(sc->sc_cfg_iot, sc->sc_cfg_ioh, off, 4,
74417c965bbSmikeb BUS_SPACE_BARRIER_WRITE);
74517c965bbSmikeb }
74617c965bbSmikeb
74717c965bbSmikeb static inline void
oce_write_csr(struct oce_softc * sc,bus_size_t off,uint32_t val)74817c965bbSmikeb oce_write_csr(struct oce_softc *sc, bus_size_t off, uint32_t val)
74917c965bbSmikeb {
75017c965bbSmikeb bus_space_write_4(sc->sc_csr_iot, sc->sc_csr_ioh, off, val);
75117c965bbSmikeb bus_space_barrier(sc->sc_csr_iot, sc->sc_csr_ioh, off, 4,
75217c965bbSmikeb BUS_SPACE_BARRIER_WRITE);
75317c965bbSmikeb }
75417c965bbSmikeb
75517c965bbSmikeb static inline void
oce_write_db(struct oce_softc * sc,bus_size_t off,uint32_t val)75617c965bbSmikeb oce_write_db(struct oce_softc *sc, bus_size_t off, uint32_t val)
75717c965bbSmikeb {
75817c965bbSmikeb bus_space_write_4(sc->sc_db_iot, sc->sc_db_ioh, off, val);
75917c965bbSmikeb bus_space_barrier(sc->sc_db_iot, sc->sc_db_ioh, off, 4,
76017c965bbSmikeb BUS_SPACE_BARRIER_WRITE);
76117c965bbSmikeb }
76217c965bbSmikeb
76317c965bbSmikeb static inline void
oce_intr_enable(struct oce_softc * sc)76417c965bbSmikeb oce_intr_enable(struct oce_softc *sc)
76517c965bbSmikeb {
76617c965bbSmikeb uint32_t reg;
76717c965bbSmikeb
76817c965bbSmikeb reg = oce_read_cfg(sc, PCI_INTR_CTRL);
76917c965bbSmikeb oce_write_cfg(sc, PCI_INTR_CTRL, reg | HOSTINTR_MASK);
77017c965bbSmikeb }
77117c965bbSmikeb
77217c965bbSmikeb static inline void
oce_intr_disable(struct oce_softc * sc)77317c965bbSmikeb oce_intr_disable(struct oce_softc *sc)
77417c965bbSmikeb {
77517c965bbSmikeb uint32_t reg;
77617c965bbSmikeb
77717c965bbSmikeb reg = oce_read_cfg(sc, PCI_INTR_CTRL);
77817c965bbSmikeb oce_write_cfg(sc, PCI_INTR_CTRL, reg & ~HOSTINTR_MASK);
77917c965bbSmikeb }
78017c965bbSmikeb
7813027f3a5Smikeb void
oce_attachhook(struct device * self)782ef89f9e6Smpi oce_attachhook(struct device *self)
7833027f3a5Smikeb {
784ef89f9e6Smpi struct oce_softc *sc = (struct oce_softc *)self;
7853027f3a5Smikeb
786dcc67c68Smikeb oce_get_link_status(sc);
7873027f3a5Smikeb
788fc40f6ceSmikeb oce_arm_cq(sc->sc_mq->cq, 0, TRUE);
7893027f3a5Smikeb
7903027f3a5Smikeb /*
7913027f3a5Smikeb * We need to get MCC async events. So enable intrs and arm
7923027f3a5Smikeb * first EQ, Other EQs will be armed after interface is UP
7933027f3a5Smikeb */
794176128bcSmikeb oce_intr_enable(sc);
795fc40f6ceSmikeb oce_arm_eq(sc->sc_eq[0], 0, TRUE, FALSE);
7963027f3a5Smikeb
7977834a31aSmikeb /*
7987834a31aSmikeb * Send first mcc cmd and after that we get gracious
7997834a31aSmikeb * MCC notifications from FW
8003027f3a5Smikeb */
8018ffe6100Smikeb oce_first_mcc(sc);
8023027f3a5Smikeb }
8033027f3a5Smikeb
804c0000edeSmikeb void
oce_attach_ifp(struct oce_softc * sc)805176128bcSmikeb oce_attach_ifp(struct oce_softc *sc)
806176128bcSmikeb {
807fc40f6ceSmikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
808176128bcSmikeb
809fc40f6ceSmikeb ifmedia_init(&sc->sc_media, IFM_IMASK, oce_media_change,
810fc40f6ceSmikeb oce_media_status);
811fc40f6ceSmikeb ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
812fc40f6ceSmikeb ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
813176128bcSmikeb
814fc40f6ceSmikeb strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
815176128bcSmikeb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
816176128bcSmikeb ifp->if_ioctl = oce_ioctl;
817176128bcSmikeb ifp->if_start = oce_start;
818176128bcSmikeb ifp->if_watchdog = oce_watchdog;
819176128bcSmikeb ifp->if_hardmtu = OCE_MAX_MTU;
820176128bcSmikeb ifp->if_softc = sc;
821cf96265bSbluhm ifq_init_maxlen(&ifp->if_snd, sc->sc_tx_ring_size - 1);
822176128bcSmikeb
82310beafc8Smikeb ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 |
82410beafc8Smikeb IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
825176128bcSmikeb
826176128bcSmikeb #if NVLAN > 0
827176128bcSmikeb ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
828176128bcSmikeb #endif
829176128bcSmikeb
830176128bcSmikeb #ifdef OCE_TSO
831176128bcSmikeb ifp->if_capabilities |= IFCAP_TSO;
832176128bcSmikeb ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
833176128bcSmikeb #endif
834176128bcSmikeb #ifdef OCE_LRO
835176128bcSmikeb ifp->if_capabilities |= IFCAP_LRO;
836176128bcSmikeb #endif
837176128bcSmikeb
838176128bcSmikeb if_attach(ifp);
839176128bcSmikeb ether_ifattach(ifp);
840176128bcSmikeb }
841176128bcSmikeb
842176128bcSmikeb int
oce_ioctl(struct ifnet * ifp,u_long command,caddr_t data)8433027f3a5Smikeb oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
8443027f3a5Smikeb {
8453027f3a5Smikeb struct oce_softc *sc = ifp->if_softc;
8463027f3a5Smikeb struct ifreq *ifr = (struct ifreq *)data;
8473027f3a5Smikeb int s, error = 0;
8483027f3a5Smikeb
8493027f3a5Smikeb s = splnet();
8503027f3a5Smikeb
8513027f3a5Smikeb switch (command) {
8523027f3a5Smikeb case SIOCSIFADDR:
8533027f3a5Smikeb ifp->if_flags |= IFF_UP;
8543027f3a5Smikeb if (!(ifp->if_flags & IFF_RUNNING))
8553027f3a5Smikeb oce_init(sc);
8563027f3a5Smikeb break;
8573027f3a5Smikeb case SIOCSIFFLAGS:
8583027f3a5Smikeb if (ifp->if_flags & IFF_UP) {
8593027f3a5Smikeb if (ifp->if_flags & IFF_RUNNING)
8603027f3a5Smikeb error = ENETRESET;
8613027f3a5Smikeb else
8623027f3a5Smikeb oce_init(sc);
8633027f3a5Smikeb } else {
8643027f3a5Smikeb if (ifp->if_flags & IFF_RUNNING)
8653027f3a5Smikeb oce_stop(sc);
8663027f3a5Smikeb }
8673027f3a5Smikeb break;
868738e9f3eSmikeb case SIOCGIFMEDIA:
869738e9f3eSmikeb case SIOCSIFMEDIA:
870fc40f6ceSmikeb error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
871738e9f3eSmikeb break;
872aae3f036Smikeb case SIOCGIFRXR:
873aae3f036Smikeb error = oce_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
874aae3f036Smikeb break;
8753027f3a5Smikeb default:
876fc40f6ceSmikeb error = ether_ioctl(ifp, &sc->sc_ac, command, data);
8773027f3a5Smikeb break;
8783027f3a5Smikeb }
8793027f3a5Smikeb
8803027f3a5Smikeb if (error == ENETRESET) {
8813027f3a5Smikeb if (ifp->if_flags & IFF_RUNNING)
8823027f3a5Smikeb oce_iff(sc);
8833027f3a5Smikeb error = 0;
8843027f3a5Smikeb }
8853027f3a5Smikeb
8863027f3a5Smikeb splx(s);
8873027f3a5Smikeb
888fc40f6ceSmikeb return (error);
8893027f3a5Smikeb }
8903027f3a5Smikeb
891aae3f036Smikeb int
oce_rxrinfo(struct oce_softc * sc,struct if_rxrinfo * ifri)892aae3f036Smikeb oce_rxrinfo(struct oce_softc *sc, struct if_rxrinfo *ifri)
893aae3f036Smikeb {
894aae3f036Smikeb struct if_rxring_info *ifr, ifr1;
895aae3f036Smikeb struct oce_rq *rq;
896aae3f036Smikeb int error, i;
897aae3f036Smikeb u_int n = 0;
898aae3f036Smikeb
899aae3f036Smikeb if (sc->sc_nrq > 1) {
90058721d3bSbluhm ifr = mallocarray(sc->sc_nrq, sizeof(*ifr), M_DEVBUF,
90158721d3bSbluhm M_WAITOK | M_ZERO);
902aae3f036Smikeb } else
903aae3f036Smikeb ifr = &ifr1;
904aae3f036Smikeb
905aae3f036Smikeb OCE_RQ_FOREACH(sc, rq, i) {
906aae3f036Smikeb ifr[n].ifr_size = MCLBYTES;
907aae3f036Smikeb snprintf(ifr[n].ifr_name, sizeof(ifr[n].ifr_name), "/%d", i);
908aae3f036Smikeb ifr[n].ifr_info = rq->rxring;
909aae3f036Smikeb n++;
910aae3f036Smikeb }
911aae3f036Smikeb
912aae3f036Smikeb error = if_rxr_info_ioctl(ifri, sc->sc_nrq, ifr);
913aae3f036Smikeb
914aae3f036Smikeb if (sc->sc_nrq > 1)
915aae3f036Smikeb free(ifr, M_DEVBUF, sc->sc_nrq * sizeof(*ifr));
916aae3f036Smikeb return (error);
917aae3f036Smikeb }
918aae3f036Smikeb
919aae3f036Smikeb
9203027f3a5Smikeb void
oce_iff(struct oce_softc * sc)9213027f3a5Smikeb oce_iff(struct oce_softc *sc)
9223027f3a5Smikeb {
923c0000edeSmikeb uint8_t multi[OCE_MAX_MC_FILTER_SIZE][ETHER_ADDR_LEN];
924fc40f6ceSmikeb struct arpcom *ac = &sc->sc_ac;
925f2d1e744Smikeb struct ifnet *ifp = &ac->ac_if;
92657bbcbb8Smikeb struct ether_multi *enm;
92757bbcbb8Smikeb struct ether_multistep step;
92857bbcbb8Smikeb int naddr = 0, promisc = 0;
9293027f3a5Smikeb
9303027f3a5Smikeb ifp->if_flags &= ~IFF_ALLMULTI;
9313027f3a5Smikeb
9323beb3f17Smikeb if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0 ||
9336628ec02Sbrad ac->ac_multicnt >= OCE_MAX_MC_FILTER_SIZE) {
9347e3b6a2aSmikeb ifp->if_flags |= IFF_ALLMULTI;
9353beb3f17Smikeb promisc = 1;
93657bbcbb8Smikeb } else {
937fc40f6ceSmikeb ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
93857bbcbb8Smikeb while (enm != NULL) {
9398f478c19Schris memcpy(multi[naddr++], enm->enm_addrlo, ETHER_ADDR_LEN);
94057bbcbb8Smikeb ETHER_NEXT_MULTI(step, enm);
94157bbcbb8Smikeb }
94257bbcbb8Smikeb oce_update_mcast(sc, multi, naddr);
94357bbcbb8Smikeb }
9443beb3f17Smikeb
94557bbcbb8Smikeb oce_set_promisc(sc, promisc);
9463027f3a5Smikeb }
9473027f3a5Smikeb
948176128bcSmikeb void
oce_link_status(struct oce_softc * sc)949bfd0edabSmikeb oce_link_status(struct oce_softc *sc)
9503027f3a5Smikeb {
951fc40f6ceSmikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
952bfd0edabSmikeb int link_state = LINK_STATE_DOWN;
9533027f3a5Smikeb
95460099e71Smikeb ifp->if_baudrate = 0;
955626a1e86Smikeb if (sc->sc_link_up) {
956626a1e86Smikeb link_state = LINK_STATE_FULL_DUPLEX;
957626a1e86Smikeb
958fc40f6ceSmikeb switch (sc->sc_link_speed) {
959bfd0edabSmikeb case 1:
960bfd0edabSmikeb ifp->if_baudrate = IF_Mbps(10);
9613027f3a5Smikeb break;
962bfd0edabSmikeb case 2:
963bfd0edabSmikeb ifp->if_baudrate = IF_Mbps(100);
9643027f3a5Smikeb break;
965bfd0edabSmikeb case 3:
966bfd0edabSmikeb ifp->if_baudrate = IF_Gbps(1);
9673027f3a5Smikeb break;
968bfd0edabSmikeb case 4:
969bfd0edabSmikeb ifp->if_baudrate = IF_Gbps(10);
9703027f3a5Smikeb break;
9713027f3a5Smikeb }
97260099e71Smikeb }
973626a1e86Smikeb if (ifp->if_link_state != link_state) {
974bfd0edabSmikeb ifp->if_link_state = link_state;
9753027f3a5Smikeb if_link_state_change(ifp);
9763027f3a5Smikeb }
977626a1e86Smikeb }
9783027f3a5Smikeb
9793027f3a5Smikeb void
oce_media_status(struct ifnet * ifp,struct ifmediareq * ifmr)9803027f3a5Smikeb oce_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
9813027f3a5Smikeb {
982466c422dSmikeb struct oce_softc *sc = ifp->if_softc;
9833027f3a5Smikeb
9843027f3a5Smikeb ifmr->ifm_status = IFM_AVALID;
9853027f3a5Smikeb ifmr->ifm_active = IFM_ETHER;
9863027f3a5Smikeb
9873027f3a5Smikeb if (oce_get_link_status(sc) == 0)
988bfd0edabSmikeb oce_link_status(sc);
9893027f3a5Smikeb
990fc40f6ceSmikeb if (!sc->sc_link_up) {
9913027f3a5Smikeb ifmr->ifm_active |= IFM_NONE;
9923027f3a5Smikeb return;
9933027f3a5Smikeb }
9943027f3a5Smikeb
9953027f3a5Smikeb ifmr->ifm_status |= IFM_ACTIVE;
9963027f3a5Smikeb
997fc40f6ceSmikeb switch (sc->sc_link_speed) {
9983027f3a5Smikeb case 1: /* 10 Mbps */
9993027f3a5Smikeb ifmr->ifm_active |= IFM_10_T | IFM_FDX;
10003027f3a5Smikeb break;
10013027f3a5Smikeb case 2: /* 100 Mbps */
10023027f3a5Smikeb ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
10033027f3a5Smikeb break;
10043027f3a5Smikeb case 3: /* 1 Gbps */
10053027f3a5Smikeb ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
10063027f3a5Smikeb break;
10073027f3a5Smikeb case 4: /* 10 Gbps */
10083027f3a5Smikeb ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
10093027f3a5Smikeb break;
10103027f3a5Smikeb }
10113027f3a5Smikeb
1012fc40f6ceSmikeb if (sc->sc_fc & IFM_ETH_RXPAUSE)
10133027f3a5Smikeb ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
1014fc40f6ceSmikeb if (sc->sc_fc & IFM_ETH_TXPAUSE)
101585582348Smikeb ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
10163027f3a5Smikeb }
10173027f3a5Smikeb
10183027f3a5Smikeb int
oce_media_change(struct ifnet * ifp)10193027f3a5Smikeb oce_media_change(struct ifnet *ifp)
10203027f3a5Smikeb {
1021c0000edeSmikeb return (0);
10223027f3a5Smikeb }
10233027f3a5Smikeb
102433279783Smikeb void
oce_tick(void * arg)102533279783Smikeb oce_tick(void *arg)
102633279783Smikeb {
102733279783Smikeb struct oce_softc *sc = arg;
102833279783Smikeb int s;
102933279783Smikeb
103033279783Smikeb s = splnet();
103133279783Smikeb
103233279783Smikeb if (oce_update_stats(sc) == 0)
103333279783Smikeb timeout_add_sec(&sc->sc_tick, 1);
103433279783Smikeb
103533279783Smikeb splx(s);
103633279783Smikeb }
103733279783Smikeb
103833279783Smikeb void
oce_init(void * arg)103933279783Smikeb oce_init(void *arg)
104033279783Smikeb {
104133279783Smikeb struct oce_softc *sc = arg;
104233279783Smikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
104333279783Smikeb struct oce_eq *eq;
104433279783Smikeb struct oce_rq *rq;
104533279783Smikeb struct oce_wq *wq;
104633279783Smikeb int i;
104733279783Smikeb
104833279783Smikeb oce_stop(sc);
104933279783Smikeb
105033279783Smikeb DELAY(10);
105133279783Smikeb
105233279783Smikeb oce_macaddr_set(sc);
105333279783Smikeb
105433279783Smikeb oce_iff(sc);
105533279783Smikeb
105633279783Smikeb /* Enable VLAN promiscuous mode */
105733279783Smikeb if (oce_config_vlan(sc, NULL, 0, 1, 1))
105833279783Smikeb goto error;
105933279783Smikeb
106033279783Smikeb if (oce_set_flow_control(sc, IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE))
106133279783Smikeb goto error;
106233279783Smikeb
106333279783Smikeb OCE_RQ_FOREACH(sc, rq, i) {
1064300e55b9Sdlg rq->mtu = ifp->if_hardmtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
106533279783Smikeb ETHER_VLAN_ENCAP_LEN;
106633279783Smikeb if (oce_new_rq(sc, rq)) {
106733279783Smikeb printf("%s: failed to create rq\n",
106833279783Smikeb sc->sc_dev.dv_xname);
106933279783Smikeb goto error;
107033279783Smikeb }
107133279783Smikeb rq->ring->index = 0;
107233279783Smikeb
10737102ef8dSdlg /* oce splits jumbos into 2k chunks... */
10747102ef8dSdlg if_rxr_init(&rq->rxring, 8, rq->nitems);
10757102ef8dSdlg
107633279783Smikeb if (!oce_alloc_rx_bufs(rq)) {
107733279783Smikeb printf("%s: failed to allocate rx buffers\n",
107833279783Smikeb sc->sc_dev.dv_xname);
107933279783Smikeb goto error;
108033279783Smikeb }
108133279783Smikeb }
108233279783Smikeb
108333279783Smikeb #ifdef OCE_RSS
108433279783Smikeb /* RSS config */
108533279783Smikeb if (sc->sc_rss_enable) {
108633279783Smikeb if (oce_config_rss(sc, (uint8_t)sc->sc_if_id, 1)) {
108733279783Smikeb printf("%s: failed to configure RSS\n",
108833279783Smikeb sc->sc_dev.dv_xname);
108933279783Smikeb goto error;
109033279783Smikeb }
109133279783Smikeb }
109233279783Smikeb #endif
109333279783Smikeb
109433279783Smikeb OCE_RQ_FOREACH(sc, rq, i)
109533279783Smikeb oce_arm_cq(rq->cq, 0, TRUE);
109633279783Smikeb
109733279783Smikeb OCE_WQ_FOREACH(sc, wq, i)
109833279783Smikeb oce_arm_cq(wq->cq, 0, TRUE);
109933279783Smikeb
110033279783Smikeb oce_arm_cq(sc->sc_mq->cq, 0, TRUE);
110133279783Smikeb
110233279783Smikeb OCE_EQ_FOREACH(sc, eq, i)
110333279783Smikeb oce_arm_eq(eq, 0, TRUE, FALSE);
110433279783Smikeb
110533279783Smikeb if (oce_get_link_status(sc) == 0)
110633279783Smikeb oce_link_status(sc);
110733279783Smikeb
110833279783Smikeb ifp->if_flags |= IFF_RUNNING;
1109de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd);
111033279783Smikeb
111133279783Smikeb timeout_add_sec(&sc->sc_tick, 1);
111233279783Smikeb
111333279783Smikeb oce_intr_enable(sc);
111433279783Smikeb
111533279783Smikeb return;
111633279783Smikeb error:
111733279783Smikeb oce_stop(sc);
111833279783Smikeb }
111933279783Smikeb
112033279783Smikeb void
oce_stop(struct oce_softc * sc)112133279783Smikeb oce_stop(struct oce_softc *sc)
112233279783Smikeb {
112333279783Smikeb struct mbx_delete_nic_rq cmd;
112433279783Smikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
112533279783Smikeb struct oce_rq *rq;
112633279783Smikeb struct oce_wq *wq;
112733279783Smikeb struct oce_eq *eq;
112833279783Smikeb int i;
112933279783Smikeb
113033279783Smikeb timeout_del(&sc->sc_tick);
1131374d76d2Smikeb timeout_del(&sc->sc_rxrefill);
113233279783Smikeb
1133de6cd8fbSdlg ifp->if_flags &= ~IFF_RUNNING;
1134de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd);
113533279783Smikeb
113633279783Smikeb /* Stop intrs and finish any bottom halves pending */
113733279783Smikeb oce_intr_disable(sc);
113833279783Smikeb
113933279783Smikeb /* Invalidate any pending cq and eq entries */
114033279783Smikeb OCE_EQ_FOREACH(sc, eq, i)
114133279783Smikeb oce_drain_eq(eq);
114233279783Smikeb OCE_RQ_FOREACH(sc, rq, i) {
114333279783Smikeb /* destroy the work queue in the firmware */
11449553ae17Schris memset(&cmd, 0, sizeof(cmd));
114533279783Smikeb cmd.params.req.rq_id = htole16(rq->id);
114633279783Smikeb oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_DELETE_RQ,
114733279783Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
114833279783Smikeb DELAY(1000);
114933279783Smikeb oce_drain_rq(rq);
115033279783Smikeb oce_free_posted_rxbuf(rq);
115133279783Smikeb }
115233279783Smikeb OCE_WQ_FOREACH(sc, wq, i)
115333279783Smikeb oce_drain_wq(wq);
115433279783Smikeb }
115533279783Smikeb
115633279783Smikeb void
oce_watchdog(struct ifnet * ifp)115733279783Smikeb oce_watchdog(struct ifnet *ifp)
115833279783Smikeb {
115933279783Smikeb printf("%s: watchdog timeout -- resetting\n", ifp->if_xname);
116033279783Smikeb
116133279783Smikeb oce_init(ifp->if_softc);
116233279783Smikeb
116333279783Smikeb ifp->if_oerrors++;
116433279783Smikeb }
116533279783Smikeb
116633279783Smikeb void
oce_start(struct ifnet * ifp)116733279783Smikeb oce_start(struct ifnet *ifp)
116833279783Smikeb {
116933279783Smikeb struct oce_softc *sc = ifp->if_softc;
117033279783Smikeb struct mbuf *m;
117133279783Smikeb int pkts = 0;
117233279783Smikeb
1173de6cd8fbSdlg if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
117433279783Smikeb return;
117533279783Smikeb
117633279783Smikeb for (;;) {
117763bcfa73Spatrick m = ifq_dequeue(&ifp->if_snd);
117833279783Smikeb if (m == NULL)
117933279783Smikeb break;
118033279783Smikeb
118133279783Smikeb if (oce_encap(sc, &m, 0)) {
1182de6cd8fbSdlg ifq_set_oactive(&ifp->if_snd);
118333279783Smikeb break;
118433279783Smikeb }
118533279783Smikeb
118633279783Smikeb #if NBPFILTER > 0
118733279783Smikeb if (ifp->if_bpf)
118833279783Smikeb bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
118933279783Smikeb #endif
119033279783Smikeb pkts++;
119133279783Smikeb }
119233279783Smikeb
119333279783Smikeb /* Set a timeout in case the chip goes out to lunch */
119433279783Smikeb if (pkts)
119533279783Smikeb ifp->if_timer = 5;
119633279783Smikeb }
119733279783Smikeb
11983027f3a5Smikeb int
oce_encap(struct oce_softc * sc,struct mbuf ** mpp,int wqidx)119932735beaSmikeb oce_encap(struct oce_softc *sc, struct mbuf **mpp, int wqidx)
12003027f3a5Smikeb {
1201a7c4bff9Smikeb struct mbuf *m = *mpp;
120232735beaSmikeb struct oce_wq *wq = sc->sc_wq[wqidx];
1203753c43a0Smikeb struct oce_pkt *pkt = NULL;
1204fc40f6ceSmikeb struct oce_nic_hdr_wqe *nhe;
1205fc40f6ceSmikeb struct oce_nic_frag_wqe *nfe;
1206fc40f6ceSmikeb int i, nwqe, err;
12073027f3a5Smikeb
12083027f3a5Smikeb #ifdef OCE_TSO
12093027f3a5Smikeb if (m->m_pkthdr.csum_flags & CSUM_TSO) {
12103027f3a5Smikeb /* consolidate packet buffers for TSO/LSO segment offload */
121117c965bbSmikeb m = oce_tso(sc, mpp);
1212a7c4bff9Smikeb if (m == NULL)
1213a7c4bff9Smikeb goto error;
12143027f3a5Smikeb }
12153027f3a5Smikeb #endif
12163027f3a5Smikeb
1217753c43a0Smikeb if ((pkt = oce_pkt_get(&wq->pkt_free)) == NULL)
1218a7c4bff9Smikeb goto error;
12193027f3a5Smikeb
1220fc40f6ceSmikeb err = bus_dmamap_load_mbuf(sc->sc_dmat, pkt->map, m, BUS_DMA_NOWAIT);
1221fc40f6ceSmikeb if (err == EFBIG) {
1222a7c4bff9Smikeb if (m_defrag(m, M_DONTWAIT) ||
1223fc40f6ceSmikeb bus_dmamap_load_mbuf(sc->sc_dmat, pkt->map, m,
1224fc40f6ceSmikeb BUS_DMA_NOWAIT))
1225a7c4bff9Smikeb goto error;
12263027f3a5Smikeb *mpp = m;
1227fc40f6ceSmikeb } else if (err != 0)
1228a7c4bff9Smikeb goto error;
12293027f3a5Smikeb
1230753c43a0Smikeb pkt->nsegs = pkt->map->dm_nsegs;
12313027f3a5Smikeb
1232753c43a0Smikeb nwqe = pkt->nsegs + 1;
12333027f3a5Smikeb if (IS_BE(sc)) {
12346c24fb2aSmikeb /* BE2 and BE3 require even number of WQEs */
1235a7c4bff9Smikeb if (nwqe & 1)
1236a7c4bff9Smikeb nwqe++;
12373027f3a5Smikeb }
12386c24fb2aSmikeb
12396c24fb2aSmikeb /* Fail if there's not enough free WQEs */
12406c24fb2aSmikeb if (nwqe >= wq->ring->nitems - wq->ring->nused) {
1241fc40f6ceSmikeb bus_dmamap_unload(sc->sc_dmat, pkt->map);
1242a7c4bff9Smikeb goto error;
12433027f3a5Smikeb }
12443027f3a5Smikeb
1245fc40f6ceSmikeb bus_dmamap_sync(sc->sc_dmat, pkt->map, 0, pkt->map->dm_mapsize,
1246e8d87644Smikeb BUS_DMASYNC_PREWRITE);
1247753c43a0Smikeb pkt->mbuf = m;
12483027f3a5Smikeb
1249fc40f6ceSmikeb /* TX work queue entry for the header */
1250fc40f6ceSmikeb nhe = oce_ring_get(wq->ring);
12519553ae17Schris memset(nhe, 0, sizeof(*nhe));
12523027f3a5Smikeb
1253fc40f6ceSmikeb nhe->u0.s.complete = 1;
1254fc40f6ceSmikeb nhe->u0.s.event = 1;
1255fc40f6ceSmikeb nhe->u0.s.crc = 1;
1256fc40f6ceSmikeb nhe->u0.s.forward = 0;
1257fc40f6ceSmikeb nhe->u0.s.ipcs = (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) ? 1 : 0;
1258fc40f6ceSmikeb nhe->u0.s.udpcs = (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) ? 1 : 0;
1259fc40f6ceSmikeb nhe->u0.s.tcpcs = (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) ? 1 : 0;
1260fc40f6ceSmikeb nhe->u0.s.num_wqe = nwqe;
1261fc40f6ceSmikeb nhe->u0.s.total_length = m->m_pkthdr.len;
12623027f3a5Smikeb
12633027f3a5Smikeb #if NVLAN > 0
12643027f3a5Smikeb if (m->m_flags & M_VLANTAG) {
1265fc40f6ceSmikeb nhe->u0.s.vlan = 1; /* Vlan present */
1266fc40f6ceSmikeb nhe->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
12673027f3a5Smikeb }
12683027f3a5Smikeb #endif
12693027f3a5Smikeb
12703027f3a5Smikeb #ifdef OCE_TSO
12713027f3a5Smikeb if (m->m_pkthdr.csum_flags & CSUM_TSO) {
12723027f3a5Smikeb if (m->m_pkthdr.tso_segsz) {
1273fc40f6ceSmikeb nhe->u0.s.lso = 1;
1274fc40f6ceSmikeb nhe->u0.s.lso_mss = m->m_pkthdr.tso_segsz;
12753027f3a5Smikeb }
12763027f3a5Smikeb if (!IS_BE(sc))
1277fc40f6ceSmikeb nhe->u0.s.ipcs = 1;
12783027f3a5Smikeb }
12793027f3a5Smikeb #endif
12803027f3a5Smikeb
1281a7c4bff9Smikeb oce_dma_sync(&wq->ring->dma, BUS_DMASYNC_PREREAD |
1282a7c4bff9Smikeb BUS_DMASYNC_PREWRITE);
1283a7c4bff9Smikeb
12847d5bbea0Smikeb wq->ring->nused++;
12853027f3a5Smikeb
1286fc40f6ceSmikeb /* TX work queue entries for data chunks */
1287753c43a0Smikeb for (i = 0; i < pkt->nsegs; i++) {
1288fc40f6ceSmikeb nfe = oce_ring_get(wq->ring);
12899553ae17Schris memset(nfe, 0, sizeof(*nfe));
1290fc40f6ceSmikeb nfe->u0.s.frag_pa_hi = ADDR_HI(pkt->map->dm_segs[i].ds_addr);
1291fc40f6ceSmikeb nfe->u0.s.frag_pa_lo = ADDR_LO(pkt->map->dm_segs[i].ds_addr);
1292fc40f6ceSmikeb nfe->u0.s.frag_len = pkt->map->dm_segs[i].ds_len;
12937d5bbea0Smikeb wq->ring->nused++;
12943027f3a5Smikeb }
1295753c43a0Smikeb if (nwqe > (pkt->nsegs + 1)) {
1296fc40f6ceSmikeb nfe = oce_ring_get(wq->ring);
12979553ae17Schris memset(nfe, 0, sizeof(*nfe));
12987d5bbea0Smikeb wq->ring->nused++;
1299753c43a0Smikeb pkt->nsegs++;
13003027f3a5Smikeb }
13013027f3a5Smikeb
1302753c43a0Smikeb oce_pkt_put(&wq->pkt_list, pkt);
1303753c43a0Smikeb
1304a7c4bff9Smikeb oce_dma_sync(&wq->ring->dma, BUS_DMASYNC_POSTREAD |
1305a7c4bff9Smikeb BUS_DMASYNC_POSTWRITE);
13063027f3a5Smikeb
13073e0d1ae4Smikeb oce_write_db(sc, PD_TXULP_DB, wq->id | (nwqe << 16));
13083027f3a5Smikeb
1309a7c4bff9Smikeb return (0);
1310a7c4bff9Smikeb
1311a7c4bff9Smikeb error:
1312753c43a0Smikeb if (pkt)
1313753c43a0Smikeb oce_pkt_put(&wq->pkt_free, pkt);
13143027f3a5Smikeb m_freem(*mpp);
13153027f3a5Smikeb *mpp = NULL;
1316a7c4bff9Smikeb return (1);
13173027f3a5Smikeb }
13183027f3a5Smikeb
131932735beaSmikeb #ifdef OCE_TSO
13203027f3a5Smikeb struct mbuf *
oce_tso(struct oce_softc * sc,struct mbuf ** mpp)132117c965bbSmikeb oce_tso(struct oce_softc *sc, struct mbuf **mpp)
13223027f3a5Smikeb {
13233027f3a5Smikeb struct mbuf *m;
13243027f3a5Smikeb struct ip *ip;
13253027f3a5Smikeb #ifdef INET6
13263027f3a5Smikeb struct ip6_hdr *ip6;
13273027f3a5Smikeb #endif
13283027f3a5Smikeb struct ether_vlan_header *eh;
13293027f3a5Smikeb struct tcphdr *th;
13303027f3a5Smikeb uint16_t etype;
13313027f3a5Smikeb int total_len = 0, ehdrlen = 0;
13323027f3a5Smikeb
13333027f3a5Smikeb m = *mpp;
13343027f3a5Smikeb
13353027f3a5Smikeb if (M_WRITABLE(m) == 0) {
13363027f3a5Smikeb m = m_dup(*mpp, M_DONTWAIT);
13373027f3a5Smikeb if (!m)
133832735beaSmikeb return (NULL);
13393027f3a5Smikeb m_freem(*mpp);
13403027f3a5Smikeb *mpp = m;
13413027f3a5Smikeb }
13423027f3a5Smikeb
13433027f3a5Smikeb eh = mtod(m, struct ether_vlan_header *);
13443027f3a5Smikeb if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
13453027f3a5Smikeb etype = ntohs(eh->evl_proto);
13463027f3a5Smikeb ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
13473027f3a5Smikeb } else {
13483027f3a5Smikeb etype = ntohs(eh->evl_encap_proto);
13493027f3a5Smikeb ehdrlen = ETHER_HDR_LEN;
13503027f3a5Smikeb }
13513027f3a5Smikeb
13523027f3a5Smikeb switch (etype) {
13533027f3a5Smikeb case ETHERTYPE_IP:
13543027f3a5Smikeb ip = (struct ip *)(m->m_data + ehdrlen);
13553027f3a5Smikeb if (ip->ip_p != IPPROTO_TCP)
135632735beaSmikeb return (NULL);
13573027f3a5Smikeb th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
13583027f3a5Smikeb
13593027f3a5Smikeb total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
13603027f3a5Smikeb break;
13613027f3a5Smikeb #ifdef INET6
13623027f3a5Smikeb case ETHERTYPE_IPV6:
13633027f3a5Smikeb ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
13643027f3a5Smikeb if (ip6->ip6_nxt != IPPROTO_TCP)
13653027f3a5Smikeb return NULL;
13663027f3a5Smikeb th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
13673027f3a5Smikeb
1368fc40f6ceSmikeb total_len = ehdrlen + sizeof(struct ip6_hdr) +
1369fc40f6ceSmikeb (th->th_off << 2);
13703027f3a5Smikeb break;
13713027f3a5Smikeb #endif
13723027f3a5Smikeb default:
137332735beaSmikeb return (NULL);
13743027f3a5Smikeb }
13753027f3a5Smikeb
13763027f3a5Smikeb m = m_pullup(m, total_len);
13773027f3a5Smikeb if (!m)
137832735beaSmikeb return (NULL);
13793027f3a5Smikeb *mpp = m;
138032735beaSmikeb return (m);
13813027f3a5Smikeb
13823027f3a5Smikeb }
138332735beaSmikeb #endif /* OCE_TSO */
13843027f3a5Smikeb
138533279783Smikeb int
oce_intr(void * arg)138633279783Smikeb oce_intr(void *arg)
13876e636463Smikeb {
138833279783Smikeb struct oce_softc *sc = arg;
138933279783Smikeb struct oce_eq *eq = sc->sc_eq[0];
139033279783Smikeb struct oce_eqe *eqe;
139133279783Smikeb struct oce_cq *cq = NULL;
1392374d76d2Smikeb int i, neqe = 0;
13936e636463Smikeb
139433279783Smikeb oce_dma_sync(&eq->ring->dma, BUS_DMASYNC_POSTREAD);
13956e636463Smikeb
139633279783Smikeb OCE_RING_FOREACH(eq->ring, eqe, eqe->evnt != 0) {
139733279783Smikeb eqe->evnt = 0;
139833279783Smikeb neqe++;
13996e636463Smikeb }
14006e636463Smikeb
1401374d76d2Smikeb /* Spurious? */
1402374d76d2Smikeb if (!neqe) {
1403374d76d2Smikeb oce_arm_eq(eq, 0, TRUE, FALSE);
1404374d76d2Smikeb return (0);
1405374d76d2Smikeb }
14063027f3a5Smikeb
140733279783Smikeb oce_dma_sync(&eq->ring->dma, BUS_DMASYNC_PREWRITE);
14083027f3a5Smikeb
140933279783Smikeb /* Clear EQ entries, but dont arm */
141033279783Smikeb oce_arm_eq(eq, neqe, FALSE, TRUE);
141133279783Smikeb
141233279783Smikeb /* Process TX, RX and MCC completion queues */
141333279783Smikeb for (i = 0; i < eq->cq_valid; i++) {
141433279783Smikeb cq = eq->cq[i];
141533279783Smikeb (*cq->cq_intr)(cq->cb_arg);
141633279783Smikeb oce_arm_cq(cq, 0, TRUE);
14176e636463Smikeb }
14183027f3a5Smikeb
141933279783Smikeb oce_arm_eq(eq, 0, TRUE, FALSE);
1420374d76d2Smikeb return (1);
14213027f3a5Smikeb }
14223027f3a5Smikeb
14233027f3a5Smikeb /* Handle the Completion Queue for transmit */
14243027f3a5Smikeb void
oce_intr_wq(void * arg)1425a7c4bff9Smikeb oce_intr_wq(void *arg)
14263027f3a5Smikeb {
14273027f3a5Smikeb struct oce_wq *wq = (struct oce_wq *)arg;
14283027f3a5Smikeb struct oce_cq *cq = wq->cq;
14293027f3a5Smikeb struct oce_nic_tx_cqe *cqe;
1430e7baef61Smikeb struct oce_softc *sc = wq->sc;
1431e7baef61Smikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
14322974a94fSmikeb int ncqe = 0;
14333027f3a5Smikeb
1434a7c4bff9Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_POSTREAD);
14357d5bbea0Smikeb OCE_RING_FOREACH(cq->ring, cqe, WQ_CQE_VALID(cqe)) {
1436a7c4bff9Smikeb oce_txeof(wq);
14377d5bbea0Smikeb WQ_CQE_INVALIDATE(cqe);
14382974a94fSmikeb ncqe++;
14393027f3a5Smikeb }
1440f2d1e744Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_PREWRITE);
1441e7baef61Smikeb
1442de6cd8fbSdlg if (ifq_is_oactive(&ifp->if_snd)) {
1443e7baef61Smikeb if (wq->ring->nused < (wq->ring->nitems / 2)) {
1444de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd);
1445e7baef61Smikeb oce_start(ifp);
1446e7baef61Smikeb }
1447e7baef61Smikeb }
1448e7baef61Smikeb if (wq->ring->nused == 0)
1449e7baef61Smikeb ifp->if_timer = 0;
1450e7baef61Smikeb
14512974a94fSmikeb if (ncqe)
14522974a94fSmikeb oce_arm_cq(cq, ncqe, FALSE);
14533027f3a5Smikeb }
14543027f3a5Smikeb
14553027f3a5Smikeb void
oce_txeof(struct oce_wq * wq)145633279783Smikeb oce_txeof(struct oce_wq *wq)
145733279783Smikeb {
145833279783Smikeb struct oce_softc *sc = wq->sc;
145933279783Smikeb struct oce_pkt *pkt;
146033279783Smikeb struct mbuf *m;
146133279783Smikeb
146233279783Smikeb if ((pkt = oce_pkt_get(&wq->pkt_list)) == NULL) {
146333279783Smikeb printf("%s: missing descriptor in txeof\n",
146433279783Smikeb sc->sc_dev.dv_xname);
146533279783Smikeb return;
146633279783Smikeb }
146733279783Smikeb
146833279783Smikeb wq->ring->nused -= pkt->nsegs + 1;
146933279783Smikeb bus_dmamap_sync(sc->sc_dmat, pkt->map, 0, pkt->map->dm_mapsize,
147033279783Smikeb BUS_DMASYNC_POSTWRITE);
147133279783Smikeb bus_dmamap_unload(sc->sc_dmat, pkt->map);
147233279783Smikeb
147333279783Smikeb m = pkt->mbuf;
147433279783Smikeb m_freem(m);
147533279783Smikeb pkt->mbuf = NULL;
147633279783Smikeb oce_pkt_put(&wq->pkt_free, pkt);
147733279783Smikeb }
147833279783Smikeb
147933279783Smikeb /* Handle the Completion Queue for receive */
148033279783Smikeb void
oce_intr_rq(void * arg)148133279783Smikeb oce_intr_rq(void *arg)
148233279783Smikeb {
148333279783Smikeb struct oce_rq *rq = (struct oce_rq *)arg;
148433279783Smikeb struct oce_cq *cq = rq->cq;
148533279783Smikeb struct oce_softc *sc = rq->sc;
148633279783Smikeb struct oce_nic_rx_cqe *cqe;
148733279783Smikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
148833279783Smikeb int maxrx, ncqe = 0;
148933279783Smikeb
149033279783Smikeb maxrx = IS_XE201(sc) ? 8 : OCE_MAX_RQ_COMPL;
149133279783Smikeb
149233279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_POSTREAD);
149333279783Smikeb
149433279783Smikeb OCE_RING_FOREACH(cq->ring, cqe, RQ_CQE_VALID(cqe) && ncqe <= maxrx) {
149533279783Smikeb if (cqe->u0.s.error == 0) {
149633279783Smikeb if (cqe->u0.s.pkt_size == 0)
149733279783Smikeb /* partial DMA workaround for Lancer */
149833279783Smikeb oce_rxeoc(rq, cqe);
149933279783Smikeb else
150033279783Smikeb oce_rxeof(rq, cqe);
150133279783Smikeb } else {
150233279783Smikeb ifp->if_ierrors++;
150333279783Smikeb if (IS_XE201(sc))
150433279783Smikeb /* Lancer A0 no buffer workaround */
150533279783Smikeb oce_rxeoc(rq, cqe);
150633279783Smikeb else
150733279783Smikeb /* Post L3/L4 errors to stack.*/
150833279783Smikeb oce_rxeof(rq, cqe);
150933279783Smikeb }
151033279783Smikeb #ifdef OCE_LRO
151133279783Smikeb if (IF_LRO_ENABLED(ifp) && rq->lro_pkts_queued >= 16)
151233279783Smikeb oce_flush_lro(rq);
151333279783Smikeb #endif
151433279783Smikeb RQ_CQE_INVALIDATE(cqe);
151533279783Smikeb ncqe++;
151633279783Smikeb }
151733279783Smikeb
151833279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_PREWRITE);
151933279783Smikeb
152033279783Smikeb #ifdef OCE_LRO
152133279783Smikeb if (IF_LRO_ENABLED(ifp))
152233279783Smikeb oce_flush_lro(rq);
152333279783Smikeb #endif
152433279783Smikeb
152533279783Smikeb if (ncqe) {
152633279783Smikeb oce_arm_cq(cq, ncqe, FALSE);
15277102ef8dSdlg if (!oce_alloc_rx_bufs(rq))
152833279783Smikeb timeout_add(&sc->sc_rxrefill, 1);
152933279783Smikeb }
153033279783Smikeb }
153133279783Smikeb
153233279783Smikeb void
oce_rxeof(struct oce_rq * rq,struct oce_nic_rx_cqe * cqe)15333027f3a5Smikeb oce_rxeof(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
15343027f3a5Smikeb {
1535753c43a0Smikeb struct oce_softc *sc = rq->sc;
1536753c43a0Smikeb struct oce_pkt *pkt = NULL;
1537fc40f6ceSmikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
1538bdcfb926Smpi struct mbuf_list ml = MBUF_LIST_INITIALIZER();
15393027f3a5Smikeb struct mbuf *m = NULL, *tail = NULL;
15403027f3a5Smikeb int i, len, frag_len;
15413027f3a5Smikeb uint16_t vtag;
15423027f3a5Smikeb
15433027f3a5Smikeb len = cqe->u0.s.pkt_size;
15443027f3a5Smikeb
15453027f3a5Smikeb /* Get vlan_tag value */
15463027f3a5Smikeb if (IS_BE(sc))
1547fc40f6ceSmikeb vtag = ntohs(cqe->u0.s.vlan_tag);
15483027f3a5Smikeb else
15493027f3a5Smikeb vtag = cqe->u0.s.vlan_tag;
15503027f3a5Smikeb
15513027f3a5Smikeb for (i = 0; i < cqe->u0.s.num_fragments; i++) {
1552753c43a0Smikeb if ((pkt = oce_pkt_get(&rq->pkt_list)) == NULL) {
1553753c43a0Smikeb printf("%s: missing descriptor in rxeof\n",
1554fc40f6ceSmikeb sc->sc_dev.dv_xname);
1555753c43a0Smikeb goto exit;
15563027f3a5Smikeb }
15573027f3a5Smikeb
1558fc40f6ceSmikeb bus_dmamap_sync(sc->sc_dmat, pkt->map, 0, pkt->map->dm_mapsize,
1559a7c4bff9Smikeb BUS_DMASYNC_POSTREAD);
1560fc40f6ceSmikeb bus_dmamap_unload(sc->sc_dmat, pkt->map);
15617102ef8dSdlg if_rxr_put(&rq->rxring, 1);
15623027f3a5Smikeb
1563753c43a0Smikeb frag_len = (len > rq->fragsize) ? rq->fragsize : len;
1564753c43a0Smikeb pkt->mbuf->m_len = frag_len;
15653027f3a5Smikeb
15663027f3a5Smikeb if (tail != NULL) {
15673027f3a5Smikeb /* additional fragments */
1568753c43a0Smikeb pkt->mbuf->m_flags &= ~M_PKTHDR;
1569753c43a0Smikeb tail->m_next = pkt->mbuf;
1570753c43a0Smikeb tail = pkt->mbuf;
15713027f3a5Smikeb } else {
1572fc40f6ceSmikeb /* first fragment, fill out most of the header */
1573753c43a0Smikeb pkt->mbuf->m_pkthdr.len = len;
1574753c43a0Smikeb pkt->mbuf->m_pkthdr.csum_flags = 0;
15753027f3a5Smikeb if (cqe->u0.s.ip_cksum_pass) {
15763027f3a5Smikeb if (!cqe->u0.s.ip_ver) { /* IPV4 */
1577753c43a0Smikeb pkt->mbuf->m_pkthdr.csum_flags =
15783027f3a5Smikeb M_IPV4_CSUM_IN_OK;
15793027f3a5Smikeb }
15803027f3a5Smikeb }
15813027f3a5Smikeb if (cqe->u0.s.l4_cksum_pass) {
1582753c43a0Smikeb pkt->mbuf->m_pkthdr.csum_flags |=
15833027f3a5Smikeb M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
15843027f3a5Smikeb }
1585753c43a0Smikeb m = tail = pkt->mbuf;
15863027f3a5Smikeb }
1587753c43a0Smikeb pkt->mbuf = NULL;
1588753c43a0Smikeb oce_pkt_put(&rq->pkt_free, pkt);
15893027f3a5Smikeb len -= frag_len;
15903027f3a5Smikeb }
15913027f3a5Smikeb
15923027f3a5Smikeb if (m) {
159317c965bbSmikeb if (!oce_port_valid(sc, cqe)) {
15943027f3a5Smikeb m_freem(m);
15953027f3a5Smikeb goto exit;
15963027f3a5Smikeb }
15973027f3a5Smikeb
15983027f3a5Smikeb #if NVLAN > 0
159954af5307Sbrynet /* This determines if vlan tag is valid */
160017c965bbSmikeb if (oce_vtp_valid(sc, cqe)) {
1601fc40f6ceSmikeb if (sc->sc_fmode & FNM_FLEX10_MODE) {
16023027f3a5Smikeb /* FLEX10. If QnQ is not set, neglect VLAN */
16033027f3a5Smikeb if (cqe->u0.s.qnq) {
16043027f3a5Smikeb m->m_pkthdr.ether_vtag = vtag;
16053027f3a5Smikeb m->m_flags |= M_VLANTAG;
16063027f3a5Smikeb }
1607fc40f6ceSmikeb } else if (sc->sc_pvid != (vtag & VLAN_VID_MASK)) {
1608a7c4bff9Smikeb /*
1609fc40f6ceSmikeb * In UMC mode generally pvid will be striped.
1610fc40f6ceSmikeb * But in some cases we have seen it comes
1611a7c4bff9Smikeb * with pvid. So if pvid == vlan, neglect vlan.
16123027f3a5Smikeb */
16133027f3a5Smikeb m->m_pkthdr.ether_vtag = vtag;
16143027f3a5Smikeb m->m_flags |= M_VLANTAG;
16153027f3a5Smikeb }
16163027f3a5Smikeb }
16173027f3a5Smikeb #endif
16183027f3a5Smikeb
16193027f3a5Smikeb #ifdef OCE_LRO
16203027f3a5Smikeb /* Try to queue to LRO */
1621753c43a0Smikeb if (IF_LRO_ENABLED(ifp) && !(m->m_flags & M_VLANTAG) &&
1622753c43a0Smikeb cqe->u0.s.ip_cksum_pass && cqe->u0.s.l4_cksum_pass &&
1623753c43a0Smikeb !cqe->u0.s.ip_ver && rq->lro.lro_cnt != 0) {
16243027f3a5Smikeb
16253027f3a5Smikeb if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
16263027f3a5Smikeb rq->lro_pkts_queued ++;
1627466c422dSmikeb goto exit;
16283027f3a5Smikeb }
16293027f3a5Smikeb /* If LRO posting fails then try to post to STACK */
16303027f3a5Smikeb }
16313027f3a5Smikeb #endif
16323027f3a5Smikeb
1633bdcfb926Smpi ml_enqueue(&ml, m);
16343027f3a5Smikeb }
16353027f3a5Smikeb exit:
1636447a2df6Sdlg if (ifiq_input(&ifp->if_rcv, &ml))
1637447a2df6Sdlg if_rxr_livelocked(&rq->rxring);
16383027f3a5Smikeb }
16393027f3a5Smikeb
16403027f3a5Smikeb void
oce_rxeoc(struct oce_rq * rq,struct oce_nic_rx_cqe * cqe)164133279783Smikeb oce_rxeoc(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
16423027f3a5Smikeb {
1643753c43a0Smikeb struct oce_softc *sc = rq->sc;
1644753c43a0Smikeb struct oce_pkt *pkt;
1645753c43a0Smikeb int i, num_frags = cqe->u0.s.num_fragments;
16463027f3a5Smikeb
16473027f3a5Smikeb if (IS_XE201(sc) && cqe->u0.s.error) {
1648c0000edeSmikeb /*
1649c0000edeSmikeb * Lancer A0 workaround:
16503027f3a5Smikeb * num_frags will be 1 more than actual in case of error
16513027f3a5Smikeb */
16523027f3a5Smikeb if (num_frags)
1653c0000edeSmikeb num_frags--;
16543027f3a5Smikeb }
16553027f3a5Smikeb for (i = 0; i < num_frags; i++) {
1656753c43a0Smikeb if ((pkt = oce_pkt_get(&rq->pkt_list)) == NULL) {
165733279783Smikeb printf("%s: missing descriptor in rxeoc\n",
1658fc40f6ceSmikeb sc->sc_dev.dv_xname);
1659753c43a0Smikeb return;
16603027f3a5Smikeb }
1661fc40f6ceSmikeb bus_dmamap_sync(sc->sc_dmat, pkt->map, 0, pkt->map->dm_mapsize,
1662a7c4bff9Smikeb BUS_DMASYNC_POSTREAD);
1663fc40f6ceSmikeb bus_dmamap_unload(sc->sc_dmat, pkt->map);
16647102ef8dSdlg if_rxr_put(&rq->rxring, 1);
1665753c43a0Smikeb m_freem(pkt->mbuf);
1666753c43a0Smikeb oce_pkt_put(&rq->pkt_free, pkt);
16673027f3a5Smikeb }
16683027f3a5Smikeb }
16693027f3a5Smikeb
16703027f3a5Smikeb int
oce_vtp_valid(struct oce_softc * sc,struct oce_nic_rx_cqe * cqe)167117c965bbSmikeb oce_vtp_valid(struct oce_softc *sc, struct oce_nic_rx_cqe *cqe)
16723027f3a5Smikeb {
16733027f3a5Smikeb struct oce_nic_rx_cqe_v1 *cqe_v1;
16743027f3a5Smikeb
1675fc40f6ceSmikeb if (IS_BE(sc) && ISSET(sc->sc_flags, OCE_F_BE3_NATIVE)) {
16763027f3a5Smikeb cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1677c0000edeSmikeb return (cqe_v1->u0.s.vlan_tag_present);
1678c0000edeSmikeb }
1679c0000edeSmikeb return (cqe->u0.s.vlan_tag_present);
16803027f3a5Smikeb }
16813027f3a5Smikeb
16823027f3a5Smikeb int
oce_port_valid(struct oce_softc * sc,struct oce_nic_rx_cqe * cqe)168317c965bbSmikeb oce_port_valid(struct oce_softc *sc, struct oce_nic_rx_cqe *cqe)
16843027f3a5Smikeb {
16853027f3a5Smikeb struct oce_nic_rx_cqe_v1 *cqe_v1;
16863027f3a5Smikeb
1687fc40f6ceSmikeb if (IS_BE(sc) && ISSET(sc->sc_flags, OCE_F_BE3_NATIVE)) {
16883027f3a5Smikeb cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1689fc40f6ceSmikeb if (sc->sc_port != cqe_v1->u0.s.port)
1690c0000edeSmikeb return (0);
1691c0000edeSmikeb }
1692c0000edeSmikeb return (1);
16933027f3a5Smikeb }
16943027f3a5Smikeb
16953027f3a5Smikeb #ifdef OCE_LRO
16963027f3a5Smikeb void
oce_flush_lro(struct oce_rq * rq)169717c965bbSmikeb oce_flush_lro(struct oce_rq *rq)
16983027f3a5Smikeb {
1699753c43a0Smikeb struct oce_softc *sc = rq->sc;
1700fc40f6ceSmikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
17013027f3a5Smikeb struct lro_ctrl *lro = &rq->lro;
17023027f3a5Smikeb struct lro_entry *queued;
17033027f3a5Smikeb
1704753c43a0Smikeb if (!IF_LRO_ENABLED(ifp))
17053027f3a5Smikeb return;
17063027f3a5Smikeb
17073027f3a5Smikeb while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
17083027f3a5Smikeb SLIST_REMOVE_HEAD(&lro->lro_active, next);
17093027f3a5Smikeb tcp_lro_flush(lro, queued);
17103027f3a5Smikeb }
17113027f3a5Smikeb rq->lro_pkts_queued = 0;
17123027f3a5Smikeb }
17133027f3a5Smikeb
17143027f3a5Smikeb int
oce_init_lro(struct oce_softc * sc)17153027f3a5Smikeb oce_init_lro(struct oce_softc *sc)
17163027f3a5Smikeb {
17173027f3a5Smikeb struct lro_ctrl *lro = NULL;
17183027f3a5Smikeb int i = 0, rc = 0;
17193027f3a5Smikeb
1720fc40f6ceSmikeb for (i = 0; i < sc->sc_nrq; i++) {
1721fc40f6ceSmikeb lro = &sc->sc_rq[i]->lro;
17223027f3a5Smikeb rc = tcp_lro_init(lro);
17233027f3a5Smikeb if (rc != 0) {
1724cb582417Sgsoares printf("%s: LRO init failed\n",
1725cb582417Sgsoares sc->sc_dev.dv_xname);
17263027f3a5Smikeb return rc;
17273027f3a5Smikeb }
1728fc40f6ceSmikeb lro->ifp = &sc->sc_ac.ac_if;
17293027f3a5Smikeb }
17303027f3a5Smikeb
173132735beaSmikeb return (rc);
17323027f3a5Smikeb }
17333027f3a5Smikeb
17343027f3a5Smikeb void
oce_free_lro(struct oce_softc * sc)17353027f3a5Smikeb oce_free_lro(struct oce_softc *sc)
17363027f3a5Smikeb {
17373027f3a5Smikeb struct lro_ctrl *lro = NULL;
17383027f3a5Smikeb int i = 0;
17393027f3a5Smikeb
1740fc40f6ceSmikeb for (i = 0; i < sc->sc_nrq; i++) {
1741fc40f6ceSmikeb lro = &sc->sc_rq[i]->lro;
17423027f3a5Smikeb if (lro)
17433027f3a5Smikeb tcp_lro_free(lro);
17443027f3a5Smikeb }
17453027f3a5Smikeb }
17463027f3a5Smikeb #endif /* OCE_LRO */
17473027f3a5Smikeb
17483027f3a5Smikeb int
oce_get_buf(struct oce_rq * rq)17493027f3a5Smikeb oce_get_buf(struct oce_rq *rq)
17503027f3a5Smikeb {
1751753c43a0Smikeb struct oce_softc *sc = rq->sc;
1752753c43a0Smikeb struct oce_pkt *pkt;
17533027f3a5Smikeb struct oce_nic_rqe *rqe;
17543027f3a5Smikeb
1755753c43a0Smikeb if ((pkt = oce_pkt_get(&rq->pkt_free)) == NULL)
1756c0000edeSmikeb return (0);
17573027f3a5Smikeb
1758471f2571Sjan pkt->mbuf = MCLGETL(NULL, M_DONTWAIT, MCLBYTES);
1759753c43a0Smikeb if (pkt->mbuf == NULL) {
1760753c43a0Smikeb oce_pkt_put(&rq->pkt_free, pkt);
1761c0000edeSmikeb return (0);
17623027f3a5Smikeb }
17633027f3a5Smikeb
1764753c43a0Smikeb pkt->mbuf->m_len = pkt->mbuf->m_pkthdr.len = MCLBYTES;
1765b9c52250Smikeb #ifdef __STRICT_ALIGNMENT
176624f2625fSmikeb m_adj(pkt->mbuf, ETHER_ALIGN);
1767b9c52250Smikeb #endif
1768a7c4bff9Smikeb
1769fc40f6ceSmikeb if (bus_dmamap_load_mbuf(sc->sc_dmat, pkt->map, pkt->mbuf,
1770753c43a0Smikeb BUS_DMA_NOWAIT)) {
1771753c43a0Smikeb m_freem(pkt->mbuf);
1772753c43a0Smikeb pkt->mbuf = NULL;
1773753c43a0Smikeb oce_pkt_put(&rq->pkt_free, pkt);
1774753c43a0Smikeb return (0);
1775753c43a0Smikeb }
1776753c43a0Smikeb
1777fc40f6ceSmikeb bus_dmamap_sync(sc->sc_dmat, pkt->map, 0, pkt->map->dm_mapsize,
1778e8d87644Smikeb BUS_DMASYNC_PREREAD);
17793027f3a5Smikeb
1780a7c4bff9Smikeb oce_dma_sync(&rq->ring->dma, BUS_DMASYNC_PREREAD |
1781a7c4bff9Smikeb BUS_DMASYNC_PREWRITE);
1782a7c4bff9Smikeb
17837d5bbea0Smikeb rqe = oce_ring_get(rq->ring);
1784753c43a0Smikeb rqe->u0.s.frag_pa_hi = ADDR_HI(pkt->map->dm_segs[0].ds_addr);
1785753c43a0Smikeb rqe->u0.s.frag_pa_lo = ADDR_LO(pkt->map->dm_segs[0].ds_addr);
1786a7c4bff9Smikeb
1787a7c4bff9Smikeb oce_dma_sync(&rq->ring->dma, BUS_DMASYNC_POSTREAD |
1788a7c4bff9Smikeb BUS_DMASYNC_POSTWRITE);
1789a7c4bff9Smikeb
1790753c43a0Smikeb oce_pkt_put(&rq->pkt_list, pkt);
1791753c43a0Smikeb
1792c0000edeSmikeb return (1);
17933027f3a5Smikeb }
17943027f3a5Smikeb
17953027f3a5Smikeb int
oce_alloc_rx_bufs(struct oce_rq * rq)17963027f3a5Smikeb oce_alloc_rx_bufs(struct oce_rq *rq)
17973027f3a5Smikeb {
1798753c43a0Smikeb struct oce_softc *sc = rq->sc;
17993027f3a5Smikeb int i, nbufs = 0;
18007102ef8dSdlg u_int slots;
18013027f3a5Smikeb
18027102ef8dSdlg for (slots = if_rxr_get(&rq->rxring, rq->nitems); slots > 0; slots--) {
18037102ef8dSdlg if (oce_get_buf(rq) == 0)
18047102ef8dSdlg break;
18057102ef8dSdlg
18063027f3a5Smikeb nbufs++;
18077102ef8dSdlg }
18087102ef8dSdlg if_rxr_put(&rq->rxring, slots);
18097102ef8dSdlg
18103027f3a5Smikeb if (!nbufs)
1811c0000edeSmikeb return (0);
18123027f3a5Smikeb for (i = nbufs / OCE_MAX_RQ_POSTS; i > 0; i--) {
18133e0d1ae4Smikeb oce_write_db(sc, PD_RXULP_DB, rq->id |
18143e0d1ae4Smikeb (OCE_MAX_RQ_POSTS << 24));
18153027f3a5Smikeb nbufs -= OCE_MAX_RQ_POSTS;
18163027f3a5Smikeb }
18173e0d1ae4Smikeb if (nbufs > 0)
18183e0d1ae4Smikeb oce_write_db(sc, PD_RXULP_DB, rq->id | (nbufs << 24));
1819c0000edeSmikeb return (1);
18203027f3a5Smikeb }
18213027f3a5Smikeb
18223027f3a5Smikeb void
oce_refill_rx(void * arg)18233027f3a5Smikeb oce_refill_rx(void *arg)
18243027f3a5Smikeb {
18253027f3a5Smikeb struct oce_softc *sc = arg;
18263027f3a5Smikeb struct oce_rq *rq;
18273027f3a5Smikeb int i, s;
18283027f3a5Smikeb
18293027f3a5Smikeb s = splnet();
1830fc40f6ceSmikeb OCE_RQ_FOREACH(sc, rq, i) {
1831374d76d2Smikeb if (!oce_alloc_rx_bufs(rq))
1832374d76d2Smikeb timeout_add(&sc->sc_rxrefill, 5);
18333027f3a5Smikeb }
18343027f3a5Smikeb splx(s);
18353027f3a5Smikeb }
18363027f3a5Smikeb
18373027f3a5Smikeb /* Handle the Completion Queue for the Mailbox/Async notifications */
18383027f3a5Smikeb void
oce_intr_mq(void * arg)1839a7c4bff9Smikeb oce_intr_mq(void *arg)
18403027f3a5Smikeb {
18413027f3a5Smikeb struct oce_mq *mq = (struct oce_mq *)arg;
1842176128bcSmikeb struct oce_softc *sc = mq->sc;
18433027f3a5Smikeb struct oce_cq *cq = mq->cq;
18443027f3a5Smikeb struct oce_mq_cqe *cqe;
18453027f3a5Smikeb struct oce_async_cqe_link_state *acqe;
18463027f3a5Smikeb struct oce_async_event_grp5_pvid_state *gcqe;
18471289fc7cSmikeb int evtype, optype, ncqe = 0;
18483027f3a5Smikeb
1849a7c4bff9Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_POSTREAD);
18507d5bbea0Smikeb
18517d5bbea0Smikeb OCE_RING_FOREACH(cq->ring, cqe, MQ_CQE_VALID(cqe)) {
18523027f3a5Smikeb if (cqe->u0.s.async_event) {
18531289fc7cSmikeb evtype = cqe->u0.s.event_type;
18543027f3a5Smikeb optype = cqe->u0.s.async_type;
18551289fc7cSmikeb if (evtype == ASYNC_EVENT_CODE_LINK_STATE) {
18563027f3a5Smikeb /* Link status evt */
18573027f3a5Smikeb acqe = (struct oce_async_cqe_link_state *)cqe;
18583027f3a5Smikeb oce_link_event(sc, acqe);
18591289fc7cSmikeb } else if ((evtype == ASYNC_EVENT_GRP5) &&
18603027f3a5Smikeb (optype == ASYNC_EVENT_PVID_STATE)) {
18613027f3a5Smikeb /* GRP5 PVID */
18623027f3a5Smikeb gcqe =
18633027f3a5Smikeb (struct oce_async_event_grp5_pvid_state *)cqe;
18643027f3a5Smikeb if (gcqe->enabled)
1865fc40f6ceSmikeb sc->sc_pvid =
1866fc40f6ceSmikeb gcqe->tag & VLAN_VID_MASK;
18673027f3a5Smikeb else
1868fc40f6ceSmikeb sc->sc_pvid = 0;
18693027f3a5Smikeb }
18703027f3a5Smikeb }
18717d5bbea0Smikeb MQ_CQE_INVALIDATE(cqe);
18722974a94fSmikeb ncqe++;
18733027f3a5Smikeb }
18743027f3a5Smikeb
1875f2d1e744Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_PREWRITE);
1876f2d1e744Smikeb
18772974a94fSmikeb if (ncqe)
1878fc40f6ceSmikeb oce_arm_cq(cq, ncqe, FALSE);
18793027f3a5Smikeb }
18803027f3a5Smikeb
188133279783Smikeb void
oce_link_event(struct oce_softc * sc,struct oce_async_cqe_link_state * acqe)188233279783Smikeb oce_link_event(struct oce_softc *sc, struct oce_async_cqe_link_state *acqe)
188333279783Smikeb {
188433279783Smikeb /* Update Link status */
188533279783Smikeb sc->sc_link_up = ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
188633279783Smikeb ASYNC_EVENT_LINK_UP);
188733279783Smikeb /* Update speed */
188833279783Smikeb sc->sc_link_speed = acqe->u0.s.speed;
188933279783Smikeb oce_link_status(sc);
189033279783Smikeb }
189133279783Smikeb
18923027f3a5Smikeb int
oce_init_queues(struct oce_softc * sc)1893dcc67c68Smikeb oce_init_queues(struct oce_softc *sc)
18943027f3a5Smikeb {
18953027f3a5Smikeb struct oce_wq *wq;
18963027f3a5Smikeb struct oce_rq *rq;
1897a7c4bff9Smikeb int i;
18983027f3a5Smikeb
1899fc40f6ceSmikeb sc->sc_nrq = 1;
1900fc40f6ceSmikeb sc->sc_nwq = 1;
1901753c43a0Smikeb
19023027f3a5Smikeb /* Create network interface on card */
1903fc40f6ceSmikeb if (oce_create_iface(sc, sc->sc_macaddr))
19043027f3a5Smikeb goto error;
19053027f3a5Smikeb
19063027f3a5Smikeb /* create all of the event queues */
1907fc40f6ceSmikeb for (i = 0; i < sc->sc_nintr; i++) {
1908fc40f6ceSmikeb sc->sc_eq[i] = oce_create_eq(sc);
1909fc40f6ceSmikeb if (!sc->sc_eq[i])
19103027f3a5Smikeb goto error;
19113027f3a5Smikeb }
19123027f3a5Smikeb
1913a7c4bff9Smikeb /* alloc tx queues */
1914fc40f6ceSmikeb OCE_WQ_FOREACH(sc, wq, i) {
1915fc40f6ceSmikeb sc->sc_wq[i] = oce_create_wq(sc, sc->sc_eq[i]);
1916fc40f6ceSmikeb if (!sc->sc_wq[i])
19173027f3a5Smikeb goto error;
19183027f3a5Smikeb }
19193027f3a5Smikeb
1920a7c4bff9Smikeb /* alloc rx queues */
1921fc40f6ceSmikeb OCE_RQ_FOREACH(sc, rq, i) {
1922fc40f6ceSmikeb sc->sc_rq[i] = oce_create_rq(sc, sc->sc_eq[i > 0 ? i - 1 : 0],
1923fc40f6ceSmikeb i > 0 ? sc->sc_rss_enable : 0);
1924fc40f6ceSmikeb if (!sc->sc_rq[i])
19253027f3a5Smikeb goto error;
19263027f3a5Smikeb }
19273027f3a5Smikeb
1928a7c4bff9Smikeb /* alloc mailbox queue */
1929fc40f6ceSmikeb sc->sc_mq = oce_create_mq(sc, sc->sc_eq[0]);
1930fc40f6ceSmikeb if (!sc->sc_mq)
19313027f3a5Smikeb goto error;
19323027f3a5Smikeb
1933a7c4bff9Smikeb return (0);
19343027f3a5Smikeb error:
1935dcc67c68Smikeb oce_release_queues(sc);
1936a7c4bff9Smikeb return (1);
19373027f3a5Smikeb }
19383027f3a5Smikeb
19393027f3a5Smikeb void
oce_release_queues(struct oce_softc * sc)1940dcc67c68Smikeb oce_release_queues(struct oce_softc *sc)
19413027f3a5Smikeb {
19423027f3a5Smikeb struct oce_wq *wq;
19433027f3a5Smikeb struct oce_rq *rq;
19443027f3a5Smikeb struct oce_eq *eq;
1945753c43a0Smikeb int i;
19463027f3a5Smikeb
1947fc40f6ceSmikeb OCE_RQ_FOREACH(sc, rq, i) {
1948dcc67c68Smikeb if (rq)
1949fc40f6ceSmikeb oce_destroy_rq(sc->sc_rq[i]);
19503027f3a5Smikeb }
19513027f3a5Smikeb
1952fc40f6ceSmikeb OCE_WQ_FOREACH(sc, wq, i) {
1953dcc67c68Smikeb if (wq)
1954fc40f6ceSmikeb oce_destroy_wq(sc->sc_wq[i]);
19553027f3a5Smikeb }
19563027f3a5Smikeb
1957fc40f6ceSmikeb if (sc->sc_mq)
1958fc40f6ceSmikeb oce_destroy_mq(sc->sc_mq);
19593027f3a5Smikeb
1960fc40f6ceSmikeb OCE_EQ_FOREACH(sc, eq, i) {
19613027f3a5Smikeb if (eq)
1962fc40f6ceSmikeb oce_destroy_eq(sc->sc_eq[i]);
19633027f3a5Smikeb }
19643027f3a5Smikeb }
19653027f3a5Smikeb
19663027f3a5Smikeb /**
19673027f3a5Smikeb * @brief Function to create a WQ for NIC Tx
19683027f3a5Smikeb * @param sc software handle to the device
19693027f3a5Smikeb * @returns the pointer to the WQ created or NULL on failure
19703027f3a5Smikeb */
19713027f3a5Smikeb struct oce_wq *
oce_create_wq(struct oce_softc * sc,struct oce_eq * eq)1972753c43a0Smikeb oce_create_wq(struct oce_softc *sc, struct oce_eq *eq)
19733027f3a5Smikeb {
19743027f3a5Smikeb struct oce_wq *wq;
1975a7c4bff9Smikeb struct oce_cq *cq;
1976753c43a0Smikeb struct oce_pkt *pkt;
1977a7c4bff9Smikeb int i;
19783027f3a5Smikeb
1979fc40f6ceSmikeb if (sc->sc_tx_ring_size < 256 || sc->sc_tx_ring_size > 2048)
1980a7c4bff9Smikeb return (NULL);
19813027f3a5Smikeb
19823027f3a5Smikeb wq = malloc(sizeof(struct oce_wq), M_DEVBUF, M_NOWAIT | M_ZERO);
19833027f3a5Smikeb if (!wq)
1984a7c4bff9Smikeb return (NULL);
19853027f3a5Smikeb
1986fc40f6ceSmikeb wq->ring = oce_create_ring(sc, sc->sc_tx_ring_size, NIC_WQE_SIZE, 8);
1987a7c4bff9Smikeb if (!wq->ring) {
1988df2ac69fStedu free(wq, M_DEVBUF, 0);
1989a7c4bff9Smikeb return (NULL);
1990a7c4bff9Smikeb }
19913027f3a5Smikeb
1992a7c4bff9Smikeb cq = oce_create_cq(sc, eq, CQ_LEN_512, sizeof(struct oce_nic_tx_cqe),
1993a7c4bff9Smikeb 1, 0, 3);
1994a7c4bff9Smikeb if (!cq) {
1995a7c4bff9Smikeb oce_destroy_ring(sc, wq->ring);
1996df2ac69fStedu free(wq, M_DEVBUF, 0);
1997a7c4bff9Smikeb return (NULL);
1998a7c4bff9Smikeb }
1999a7c4bff9Smikeb
2000a7c4bff9Smikeb wq->id = -1;
2001176128bcSmikeb wq->sc = sc;
20023027f3a5Smikeb
20033027f3a5Smikeb wq->cq = cq;
2004fc40f6ceSmikeb wq->nitems = sc->sc_tx_ring_size;
20053027f3a5Smikeb
2006753c43a0Smikeb SIMPLEQ_INIT(&wq->pkt_free);
2007753c43a0Smikeb SIMPLEQ_INIT(&wq->pkt_list);
2008753c43a0Smikeb
2009fc40f6ceSmikeb for (i = 0; i < sc->sc_tx_ring_size / 2; i++) {
2010753c43a0Smikeb pkt = oce_pkt_alloc(sc, OCE_MAX_TX_SIZE, OCE_MAX_TX_ELEMENTS,
2011753c43a0Smikeb PAGE_SIZE);
2012753c43a0Smikeb if (pkt == NULL) {
201362dc823aSmikeb oce_destroy_wq(wq);
201462dc823aSmikeb return (NULL);
201562dc823aSmikeb }
2016753c43a0Smikeb oce_pkt_put(&wq->pkt_free, pkt);
2017a7c4bff9Smikeb }
20183027f3a5Smikeb
201962dc823aSmikeb if (oce_new_wq(sc, wq)) {
202062dc823aSmikeb oce_destroy_wq(wq);
202162dc823aSmikeb return (NULL);
202262dc823aSmikeb }
2023a7c4bff9Smikeb
20243027f3a5Smikeb eq->cq[eq->cq_valid] = cq;
20253027f3a5Smikeb eq->cq_valid++;
20263027f3a5Smikeb cq->cb_arg = wq;
2027a7c4bff9Smikeb cq->cq_intr = oce_intr_wq;
20283027f3a5Smikeb
2029a7c4bff9Smikeb return (wq);
2030a7c4bff9Smikeb }
2031a7c4bff9Smikeb
2032a7c4bff9Smikeb void
oce_drain_wq(struct oce_wq * wq)203333279783Smikeb oce_drain_wq(struct oce_wq *wq)
203433279783Smikeb {
203533279783Smikeb struct oce_cq *cq = wq->cq;
203633279783Smikeb struct oce_nic_tx_cqe *cqe;
203733279783Smikeb int ncqe = 0;
203833279783Smikeb
203933279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_POSTREAD);
204033279783Smikeb OCE_RING_FOREACH(cq->ring, cqe, WQ_CQE_VALID(cqe)) {
204133279783Smikeb WQ_CQE_INVALIDATE(cqe);
204233279783Smikeb ncqe++;
204333279783Smikeb }
204433279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_PREWRITE);
204533279783Smikeb oce_arm_cq(cq, ncqe, FALSE);
204633279783Smikeb }
204733279783Smikeb
204833279783Smikeb void
oce_destroy_wq(struct oce_wq * wq)2049a7c4bff9Smikeb oce_destroy_wq(struct oce_wq *wq)
2050a7c4bff9Smikeb {
205133279783Smikeb struct mbx_delete_nic_wq cmd;
2052a7c4bff9Smikeb struct oce_softc *sc = wq->sc;
2053753c43a0Smikeb struct oce_pkt *pkt;
2054a7c4bff9Smikeb
205533279783Smikeb if (wq->id >= 0) {
20569553ae17Schris memset(&cmd, 0, sizeof(cmd));
205733279783Smikeb cmd.params.req.wq_id = htole16(wq->id);
205833279783Smikeb oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_DELETE_WQ, OCE_MBX_VER_V0,
205933279783Smikeb &cmd, sizeof(cmd));
206033279783Smikeb }
2061a7c4bff9Smikeb if (wq->cq != NULL)
2062a7c4bff9Smikeb oce_destroy_cq(wq->cq);
2063a7c4bff9Smikeb if (wq->ring != NULL)
2064a7c4bff9Smikeb oce_destroy_ring(sc, wq->ring);
2065753c43a0Smikeb while ((pkt = oce_pkt_get(&wq->pkt_free)) != NULL)
2066753c43a0Smikeb oce_pkt_free(sc, pkt);
2067df2ac69fStedu free(wq, M_DEVBUF, 0);
20683027f3a5Smikeb }
20693027f3a5Smikeb
20703027f3a5Smikeb /**
20713027f3a5Smikeb * @brief function to allocate receive queue resources
20723027f3a5Smikeb * @param sc software handle to the device
2073a7c4bff9Smikeb * @param eq pointer to associated event queue
20743027f3a5Smikeb * @param rss is-rss-queue flag
20753027f3a5Smikeb * @returns the pointer to the RQ created or NULL on failure
20763027f3a5Smikeb */
20773027f3a5Smikeb struct oce_rq *
oce_create_rq(struct oce_softc * sc,struct oce_eq * eq,int rss)2078b47f6b63Smikeb oce_create_rq(struct oce_softc *sc, struct oce_eq *eq, int rss)
20793027f3a5Smikeb {
20803027f3a5Smikeb struct oce_rq *rq;
2081a7c4bff9Smikeb struct oce_cq *cq;
2082753c43a0Smikeb struct oce_pkt *pkt;
2083a7c4bff9Smikeb int i;
20843027f3a5Smikeb
20853027f3a5Smikeb /* Hardware doesn't support any other value */
2086fc40f6ceSmikeb if (sc->sc_rx_ring_size != 1024)
2087a7c4bff9Smikeb return (NULL);
20883027f3a5Smikeb
20893027f3a5Smikeb rq = malloc(sizeof(struct oce_rq), M_DEVBUF, M_NOWAIT | M_ZERO);
20903027f3a5Smikeb if (!rq)
2091a7c4bff9Smikeb return (NULL);
2092a7c4bff9Smikeb
2093fc40f6ceSmikeb rq->ring = oce_create_ring(sc, sc->sc_rx_ring_size,
2094753c43a0Smikeb sizeof(struct oce_nic_rqe), 2);
2095a7c4bff9Smikeb if (!rq->ring) {
2096df2ac69fStedu free(rq, M_DEVBUF, 0);
2097a7c4bff9Smikeb return (NULL);
2098a7c4bff9Smikeb }
2099a7c4bff9Smikeb
2100a7c4bff9Smikeb cq = oce_create_cq(sc, eq, CQ_LEN_1024, sizeof(struct oce_nic_rx_cqe),
2101a7c4bff9Smikeb 1, 0, 3);
2102a7c4bff9Smikeb if (!cq) {
2103a7c4bff9Smikeb oce_destroy_ring(sc, rq->ring);
2104df2ac69fStedu free(rq, M_DEVBUF, 0);
2105a7c4bff9Smikeb return (NULL);
2106a7c4bff9Smikeb }
2107a7c4bff9Smikeb
2108a7c4bff9Smikeb rq->id = -1;
2109a7c4bff9Smikeb rq->sc = sc;
21103027f3a5Smikeb
2111fc40f6ceSmikeb rq->nitems = sc->sc_rx_ring_size;
2112fc40f6ceSmikeb rq->fragsize = OCE_RX_BUF_SIZE;
2113753c43a0Smikeb rq->rss = rss;
21143027f3a5Smikeb
2115753c43a0Smikeb SIMPLEQ_INIT(&rq->pkt_free);
2116753c43a0Smikeb SIMPLEQ_INIT(&rq->pkt_list);
2117753c43a0Smikeb
2118fc40f6ceSmikeb for (i = 0; i < sc->sc_rx_ring_size; i++) {
2119fc40f6ceSmikeb pkt = oce_pkt_alloc(sc, OCE_RX_BUF_SIZE, 1, OCE_RX_BUF_SIZE);
2120753c43a0Smikeb if (pkt == NULL) {
212162dc823aSmikeb oce_destroy_rq(rq);
212262dc823aSmikeb return (NULL);
212362dc823aSmikeb }
2124753c43a0Smikeb oce_pkt_put(&rq->pkt_free, pkt);
21253027f3a5Smikeb }
21263027f3a5Smikeb
2127a7c4bff9Smikeb rq->cq = cq;
2128a7c4bff9Smikeb eq->cq[eq->cq_valid] = cq;
2129a7c4bff9Smikeb eq->cq_valid++;
2130a7c4bff9Smikeb cq->cb_arg = rq;
2131a7c4bff9Smikeb cq->cq_intr = oce_intr_rq;
2132a7c4bff9Smikeb
2133a7c4bff9Smikeb /* RX queue is created in oce_init */
21343027f3a5Smikeb
213562dc823aSmikeb return (rq);
21363027f3a5Smikeb }
21373027f3a5Smikeb
21383027f3a5Smikeb void
oce_drain_rq(struct oce_rq * rq)213933279783Smikeb oce_drain_rq(struct oce_rq *rq)
214033279783Smikeb {
214133279783Smikeb struct oce_nic_rx_cqe *cqe;
214233279783Smikeb struct oce_cq *cq = rq->cq;
214333279783Smikeb int ncqe = 0;
214433279783Smikeb
214533279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_POSTREAD);
214633279783Smikeb OCE_RING_FOREACH(cq->ring, cqe, RQ_CQE_VALID(cqe)) {
214733279783Smikeb RQ_CQE_INVALIDATE(cqe);
214833279783Smikeb ncqe++;
214933279783Smikeb }
215033279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_PREWRITE);
215133279783Smikeb oce_arm_cq(cq, ncqe, FALSE);
215233279783Smikeb }
215333279783Smikeb
215433279783Smikeb void
oce_destroy_rq(struct oce_rq * rq)2155a7c4bff9Smikeb oce_destroy_rq(struct oce_rq *rq)
21563027f3a5Smikeb {
215733279783Smikeb struct mbx_delete_nic_rq cmd;
2158176128bcSmikeb struct oce_softc *sc = rq->sc;
2159753c43a0Smikeb struct oce_pkt *pkt;
21603027f3a5Smikeb
216133279783Smikeb if (rq->id >= 0) {
21629553ae17Schris memset(&cmd, 0, sizeof(cmd));
216333279783Smikeb cmd.params.req.rq_id = htole16(rq->id);
216433279783Smikeb oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_DELETE_RQ, OCE_MBX_VER_V0,
216533279783Smikeb &cmd, sizeof(cmd));
216633279783Smikeb }
2167dcc67c68Smikeb if (rq->cq != NULL)
2168a7c4bff9Smikeb oce_destroy_cq(rq->cq);
2169dcc67c68Smikeb if (rq->ring != NULL)
21703027f3a5Smikeb oce_destroy_ring(sc, rq->ring);
2171753c43a0Smikeb while ((pkt = oce_pkt_get(&rq->pkt_free)) != NULL)
2172753c43a0Smikeb oce_pkt_free(sc, pkt);
2173df2ac69fStedu free(rq, M_DEVBUF, 0);
21743027f3a5Smikeb }
21753027f3a5Smikeb
21763027f3a5Smikeb struct oce_eq *
oce_create_eq(struct oce_softc * sc)2177a7c4bff9Smikeb oce_create_eq(struct oce_softc *sc)
21783027f3a5Smikeb {
21793027f3a5Smikeb struct oce_eq *eq;
21803027f3a5Smikeb
21813027f3a5Smikeb /* allocate an eq */
21823027f3a5Smikeb eq = malloc(sizeof(struct oce_eq), M_DEVBUF, M_NOWAIT | M_ZERO);
21833027f3a5Smikeb if (eq == NULL)
2184a7c4bff9Smikeb return (NULL);
21853027f3a5Smikeb
2186a7c4bff9Smikeb eq->ring = oce_create_ring(sc, EQ_LEN_1024, EQE_SIZE_4, 8);
2187dcc67c68Smikeb if (!eq->ring) {
2188df2ac69fStedu free(eq, M_DEVBUF, 0);
2189a7c4bff9Smikeb return (NULL);
2190dcc67c68Smikeb }
2191dcc67c68Smikeb
2192a7c4bff9Smikeb eq->id = -1;
2193176128bcSmikeb eq->sc = sc;
2194753c43a0Smikeb eq->nitems = EQ_LEN_1024; /* length of event queue */
2195753c43a0Smikeb eq->isize = EQE_SIZE_4; /* size of a queue item */
2196753c43a0Smikeb eq->delay = OCE_DEFAULT_EQD; /* event queue delay */
21973027f3a5Smikeb
2198a7c4bff9Smikeb if (oce_new_eq(sc, eq)) {
2199a7c4bff9Smikeb oce_destroy_ring(sc, eq->ring);
2200df2ac69fStedu free(eq, M_DEVBUF, 0);
2201a7c4bff9Smikeb return (NULL);
2202a7c4bff9Smikeb }
22033027f3a5Smikeb
2204a7c4bff9Smikeb return (eq);
22053027f3a5Smikeb }
22063027f3a5Smikeb
220733279783Smikeb /**
220833279783Smikeb * @brief Function to arm an EQ so that it can generate events
220933279783Smikeb * @param eq pointer to event queue structure
221033279783Smikeb * @param neqe number of EQEs to arm
221133279783Smikeb * @param rearm rearm bit enable/disable
221233279783Smikeb * @param clearint bit to clear the interrupt condition because of which
221333279783Smikeb * EQEs are generated
221433279783Smikeb */
221533279783Smikeb static inline void
oce_arm_eq(struct oce_eq * eq,int neqe,int rearm,int clearint)221633279783Smikeb oce_arm_eq(struct oce_eq *eq, int neqe, int rearm, int clearint)
221733279783Smikeb {
221833279783Smikeb oce_write_db(eq->sc, PD_EQ_DB, eq->id | PD_EQ_DB_EVENT |
221933279783Smikeb (clearint << 9) | (neqe << 16) | (rearm << 29));
222033279783Smikeb }
222133279783Smikeb
222233279783Smikeb void
oce_drain_eq(struct oce_eq * eq)222333279783Smikeb oce_drain_eq(struct oce_eq *eq)
222433279783Smikeb {
222533279783Smikeb struct oce_eqe *eqe;
222633279783Smikeb int neqe = 0;
222733279783Smikeb
222833279783Smikeb oce_dma_sync(&eq->ring->dma, BUS_DMASYNC_POSTREAD);
222933279783Smikeb OCE_RING_FOREACH(eq->ring, eqe, eqe->evnt != 0) {
223033279783Smikeb eqe->evnt = 0;
223133279783Smikeb neqe++;
223233279783Smikeb }
223333279783Smikeb oce_dma_sync(&eq->ring->dma, BUS_DMASYNC_PREWRITE);
223433279783Smikeb oce_arm_eq(eq, neqe, FALSE, TRUE);
223533279783Smikeb }
223633279783Smikeb
22373027f3a5Smikeb void
oce_destroy_eq(struct oce_eq * eq)2238a7c4bff9Smikeb oce_destroy_eq(struct oce_eq *eq)
22393027f3a5Smikeb {
224033279783Smikeb struct mbx_destroy_common_eq cmd;
2241176128bcSmikeb struct oce_softc *sc = eq->sc;
22423027f3a5Smikeb
224333279783Smikeb if (eq->id >= 0) {
22449553ae17Schris memset(&cmd, 0, sizeof(cmd));
224533279783Smikeb cmd.params.req.id = htole16(eq->id);
224633279783Smikeb oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_DESTROY_EQ,
224733279783Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
224833279783Smikeb }
2249dcc67c68Smikeb if (eq->ring != NULL)
22503027f3a5Smikeb oce_destroy_ring(sc, eq->ring);
2251df2ac69fStedu free(eq, M_DEVBUF, 0);
22523027f3a5Smikeb }
22533027f3a5Smikeb
22543027f3a5Smikeb struct oce_mq *
oce_create_mq(struct oce_softc * sc,struct oce_eq * eq)2255a7c4bff9Smikeb oce_create_mq(struct oce_softc *sc, struct oce_eq *eq)
22563027f3a5Smikeb {
22573027f3a5Smikeb struct oce_mq *mq = NULL;
22583027f3a5Smikeb struct oce_cq *cq;
22593027f3a5Smikeb
22603027f3a5Smikeb /* allocate the mq */
22613027f3a5Smikeb mq = malloc(sizeof(struct oce_mq), M_DEVBUF, M_NOWAIT | M_ZERO);
22623027f3a5Smikeb if (!mq)
2263a7c4bff9Smikeb return (NULL);
22643027f3a5Smikeb
2265a7c4bff9Smikeb mq->ring = oce_create_ring(sc, 128, sizeof(struct oce_mbx), 8);
2266a7c4bff9Smikeb if (!mq->ring) {
2267df2ac69fStedu free(mq, M_DEVBUF, 0);
2268a7c4bff9Smikeb return (NULL);
22693027f3a5Smikeb }
22703027f3a5Smikeb
2271a7c4bff9Smikeb cq = oce_create_cq(sc, eq, CQ_LEN_256, sizeof(struct oce_mq_cqe),
2272a7c4bff9Smikeb 1, 0, 0);
2273a7c4bff9Smikeb if (!cq) {
2274a7c4bff9Smikeb oce_destroy_ring(sc, mq->ring);
2275df2ac69fStedu free(mq, M_DEVBUF, 0);
2276a7c4bff9Smikeb return (NULL);
2277a7c4bff9Smikeb }
2278a7c4bff9Smikeb
2279a7c4bff9Smikeb mq->id = -1;
2280176128bcSmikeb mq->sc = sc;
22813027f3a5Smikeb mq->cq = cq;
22823027f3a5Smikeb
2283753c43a0Smikeb mq->nitems = 128;
22843027f3a5Smikeb
2285a7c4bff9Smikeb if (oce_new_mq(sc, mq)) {
2286a7c4bff9Smikeb oce_destroy_cq(mq->cq);
2287a7c4bff9Smikeb oce_destroy_ring(sc, mq->ring);
2288df2ac69fStedu free(mq, M_DEVBUF, 0);
2289a7c4bff9Smikeb return (NULL);
2290a7c4bff9Smikeb }
22913027f3a5Smikeb
22923027f3a5Smikeb eq->cq[eq->cq_valid] = cq;
22933027f3a5Smikeb eq->cq_valid++;
22943027f3a5Smikeb mq->cq->eq = eq;
22953027f3a5Smikeb mq->cq->cb_arg = mq;
2296a7c4bff9Smikeb mq->cq->cq_intr = oce_intr_mq;
22973027f3a5Smikeb
2298a7c4bff9Smikeb return (mq);
22993027f3a5Smikeb }
23003027f3a5Smikeb
23013027f3a5Smikeb void
oce_drain_mq(struct oce_mq * mq)230233279783Smikeb oce_drain_mq(struct oce_mq *mq)
230333279783Smikeb {
230433279783Smikeb struct oce_cq *cq = mq->cq;
230533279783Smikeb struct oce_mq_cqe *cqe;
230633279783Smikeb int ncqe = 0;
230733279783Smikeb
230833279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_POSTREAD);
230933279783Smikeb OCE_RING_FOREACH(cq->ring, cqe, MQ_CQE_VALID(cqe)) {
231033279783Smikeb MQ_CQE_INVALIDATE(cqe);
231133279783Smikeb ncqe++;
231233279783Smikeb }
231333279783Smikeb oce_dma_sync(&cq->ring->dma, BUS_DMASYNC_PREWRITE);
231433279783Smikeb oce_arm_cq(cq, ncqe, FALSE);
231533279783Smikeb }
231633279783Smikeb
231733279783Smikeb void
oce_destroy_mq(struct oce_mq * mq)2318a7c4bff9Smikeb oce_destroy_mq(struct oce_mq *mq)
23193027f3a5Smikeb {
232033279783Smikeb struct mbx_destroy_common_mq cmd;
2321176128bcSmikeb struct oce_softc *sc = mq->sc;
23223027f3a5Smikeb
232333279783Smikeb if (mq->id >= 0) {
23249553ae17Schris memset(&cmd, 0, sizeof(cmd));
232533279783Smikeb cmd.params.req.id = htole16(mq->id);
232633279783Smikeb oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_DESTROY_MQ,
232733279783Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
232833279783Smikeb }
2329dcc67c68Smikeb if (mq->ring != NULL)
2330dcc67c68Smikeb oce_destroy_ring(sc, mq->ring);
2331dcc67c68Smikeb if (mq->cq != NULL)
2332a7c4bff9Smikeb oce_destroy_cq(mq->cq);
2333df2ac69fStedu free(mq, M_DEVBUF, 0);
23343027f3a5Smikeb }
23353027f3a5Smikeb
23363027f3a5Smikeb /**
23373027f3a5Smikeb * @brief Function to create a completion queue
23383027f3a5Smikeb * @param sc software handle to the device
23393027f3a5Smikeb * @param eq optional eq to be associated with to the cq
234033279783Smikeb * @param nitems length of completion queue
234133279783Smikeb * @param isize size of completion queue items
234233279783Smikeb * @param eventable event table
23433027f3a5Smikeb * @param nodelay no delay flag
23443027f3a5Smikeb * @param ncoalesce no coalescence flag
23453027f3a5Smikeb * @returns pointer to the cq created, NULL on failure
23463027f3a5Smikeb */
23473027f3a5Smikeb struct oce_cq *
oce_create_cq(struct oce_softc * sc,struct oce_eq * eq,int nitems,int isize,int eventable,int nodelay,int ncoalesce)234833279783Smikeb oce_create_cq(struct oce_softc *sc, struct oce_eq *eq, int nitems, int isize,
234933279783Smikeb int eventable, int nodelay, int ncoalesce)
23503027f3a5Smikeb {
23513027f3a5Smikeb struct oce_cq *cq = NULL;
23523027f3a5Smikeb
23533027f3a5Smikeb cq = malloc(sizeof(struct oce_cq), M_DEVBUF, M_NOWAIT | M_ZERO);
23543027f3a5Smikeb if (!cq)
2355c0000edeSmikeb return (NULL);
23563027f3a5Smikeb
235733279783Smikeb cq->ring = oce_create_ring(sc, nitems, isize, 4);
2358dcc67c68Smikeb if (!cq->ring) {
2359df2ac69fStedu free(cq, M_DEVBUF, 0);
2360c0000edeSmikeb return (NULL);
2361dcc67c68Smikeb }
23623027f3a5Smikeb
2363176128bcSmikeb cq->sc = sc;
23643027f3a5Smikeb cq->eq = eq;
236533279783Smikeb cq->nitems = nitems;
236632735beaSmikeb cq->nodelay = nodelay;
2367753c43a0Smikeb cq->ncoalesce = ncoalesce;
2368753c43a0Smikeb cq->eventable = eventable;
23693027f3a5Smikeb
2370a7c4bff9Smikeb if (oce_new_cq(sc, cq)) {
2371a7c4bff9Smikeb oce_destroy_ring(sc, cq->ring);
2372df2ac69fStedu free(cq, M_DEVBUF, 0);
2373a7c4bff9Smikeb return (NULL);
2374a7c4bff9Smikeb }
23753027f3a5Smikeb
2376fc40f6ceSmikeb sc->sc_cq[sc->sc_ncq++] = cq;
23773027f3a5Smikeb
2378a7c4bff9Smikeb return (cq);
23793027f3a5Smikeb }
23803027f3a5Smikeb
23813027f3a5Smikeb void
oce_destroy_cq(struct oce_cq * cq)2382a7c4bff9Smikeb oce_destroy_cq(struct oce_cq *cq)
23833027f3a5Smikeb {
238433279783Smikeb struct mbx_destroy_common_cq cmd;
2385176128bcSmikeb struct oce_softc *sc = cq->sc;
2386dcc67c68Smikeb
238733279783Smikeb if (cq->id >= 0) {
23889553ae17Schris memset(&cmd, 0, sizeof(cmd));
238933279783Smikeb cmd.params.req.id = htole16(cq->id);
239033279783Smikeb oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_DESTROY_CQ,
239133279783Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
239233279783Smikeb }
239333279783Smikeb if (cq->ring != NULL)
23943027f3a5Smikeb oce_destroy_ring(sc, cq->ring);
2395df2ac69fStedu free(cq, M_DEVBUF, 0);
23963027f3a5Smikeb }
23973027f3a5Smikeb
23983027f3a5Smikeb /**
23993027f3a5Smikeb * @brief Function to arm a CQ with CQEs
24002974a94fSmikeb * @param cq pointer to the completion queue structure
240123eb8015Smikeb * @param ncqe number of CQEs to arm
24023027f3a5Smikeb * @param rearm rearm bit enable/disable
24033027f3a5Smikeb */
240423eb8015Smikeb static inline void
oce_arm_cq(struct oce_cq * cq,int ncqe,int rearm)240523eb8015Smikeb oce_arm_cq(struct oce_cq *cq, int ncqe, int rearm)
24063027f3a5Smikeb {
24073e0d1ae4Smikeb oce_write_db(cq->sc, PD_CQ_DB, cq->id | (ncqe << 16) | (rearm << 29));
24083027f3a5Smikeb }
24093027f3a5Smikeb
24103027f3a5Smikeb void
oce_free_posted_rxbuf(struct oce_rq * rq)24113027f3a5Smikeb oce_free_posted_rxbuf(struct oce_rq *rq)
24123027f3a5Smikeb {
2413753c43a0Smikeb struct oce_softc *sc = rq->sc;
2414753c43a0Smikeb struct oce_pkt *pkt;
24153027f3a5Smikeb
2416753c43a0Smikeb while ((pkt = oce_pkt_get(&rq->pkt_list)) != NULL) {
2417fc40f6ceSmikeb bus_dmamap_sync(sc->sc_dmat, pkt->map, 0, pkt->map->dm_mapsize,
2418a7c4bff9Smikeb BUS_DMASYNC_POSTREAD);
2419fc40f6ceSmikeb bus_dmamap_unload(sc->sc_dmat, pkt->map);
2420753c43a0Smikeb if (pkt->mbuf != NULL) {
2421753c43a0Smikeb m_freem(pkt->mbuf);
2422753c43a0Smikeb pkt->mbuf = NULL;
24233027f3a5Smikeb }
2424753c43a0Smikeb oce_pkt_put(&rq->pkt_free, pkt);
24257102ef8dSdlg if_rxr_put(&rq->rxring, 1);
24263027f3a5Smikeb }
24273027f3a5Smikeb }
24283027f3a5Smikeb
24293027f3a5Smikeb int
oce_dma_alloc(struct oce_softc * sc,bus_size_t size,struct oce_dma_mem * dma)2430dcc67c68Smikeb oce_dma_alloc(struct oce_softc *sc, bus_size_t size, struct oce_dma_mem *dma)
24313027f3a5Smikeb {
24323027f3a5Smikeb int rc;
24333027f3a5Smikeb
24349553ae17Schris memset(dma, 0, sizeof(struct oce_dma_mem));
24353027f3a5Smikeb
2436fc40f6ceSmikeb dma->tag = sc->sc_dmat;
24373027f3a5Smikeb rc = bus_dmamap_create(dma->tag, size, 1, size, 0, BUS_DMA_NOWAIT,
24383027f3a5Smikeb &dma->map);
24393027f3a5Smikeb if (rc != 0) {
2440fc40f6ceSmikeb printf("%s: failed to allocate DMA handle",
2441fc40f6ceSmikeb sc->sc_dev.dv_xname);
24423027f3a5Smikeb goto fail_0;
24433027f3a5Smikeb }
24443027f3a5Smikeb
24453027f3a5Smikeb rc = bus_dmamem_alloc(dma->tag, size, PAGE_SIZE, 0, &dma->segs, 1,
2446dcc67c68Smikeb &dma->nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
24473027f3a5Smikeb if (rc != 0) {
2448fc40f6ceSmikeb printf("%s: failed to allocate DMA memory",
2449fc40f6ceSmikeb sc->sc_dev.dv_xname);
24503027f3a5Smikeb goto fail_1;
24513027f3a5Smikeb }
24523027f3a5Smikeb
24533027f3a5Smikeb rc = bus_dmamem_map(dma->tag, &dma->segs, dma->nsegs, size,
24543027f3a5Smikeb &dma->vaddr, BUS_DMA_NOWAIT);
24553027f3a5Smikeb if (rc != 0) {
2456fc40f6ceSmikeb printf("%s: failed to map DMA memory", sc->sc_dev.dv_xname);
24573027f3a5Smikeb goto fail_2;
24583027f3a5Smikeb }
24593027f3a5Smikeb
24603027f3a5Smikeb rc = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, size, NULL,
2461dcc67c68Smikeb BUS_DMA_NOWAIT);
24623027f3a5Smikeb if (rc != 0) {
2463fc40f6ceSmikeb printf("%s: failed to load DMA memory", sc->sc_dev.dv_xname);
24643027f3a5Smikeb goto fail_3;
24653027f3a5Smikeb }
24663027f3a5Smikeb
2467e4b927f3Smikeb bus_dmamap_sync(dma->tag, dma->map, 0, dma->map->dm_mapsize,
2468e4b927f3Smikeb BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2469e4b927f3Smikeb
24703027f3a5Smikeb dma->paddr = dma->map->dm_segs[0].ds_addr;
24713027f3a5Smikeb dma->size = size;
24723027f3a5Smikeb
2473c0000edeSmikeb return (0);
24743027f3a5Smikeb
24753027f3a5Smikeb fail_3:
24763027f3a5Smikeb bus_dmamem_unmap(dma->tag, dma->vaddr, size);
24773027f3a5Smikeb fail_2:
24783027f3a5Smikeb bus_dmamem_free(dma->tag, &dma->segs, dma->nsegs);
24793027f3a5Smikeb fail_1:
24803027f3a5Smikeb bus_dmamap_destroy(dma->tag, dma->map);
24813027f3a5Smikeb fail_0:
2482c0000edeSmikeb return (rc);
24833027f3a5Smikeb }
24843027f3a5Smikeb
24853027f3a5Smikeb void
oce_dma_free(struct oce_softc * sc,struct oce_dma_mem * dma)24863027f3a5Smikeb oce_dma_free(struct oce_softc *sc, struct oce_dma_mem *dma)
24873027f3a5Smikeb {
24883027f3a5Smikeb if (dma->tag == NULL)
24893027f3a5Smikeb return;
24903027f3a5Smikeb
24913027f3a5Smikeb if (dma->map != NULL) {
24923027f3a5Smikeb oce_dma_sync(dma, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
24933027f3a5Smikeb bus_dmamap_unload(dma->tag, dma->map);
24943027f3a5Smikeb
24953027f3a5Smikeb if (dma->vaddr != 0) {
24963027f3a5Smikeb bus_dmamem_free(dma->tag, &dma->segs, dma->nsegs);
24973027f3a5Smikeb dma->vaddr = 0;
24983027f3a5Smikeb }
24993027f3a5Smikeb
25003027f3a5Smikeb bus_dmamap_destroy(dma->tag, dma->map);
25013027f3a5Smikeb dma->map = NULL;
25023027f3a5Smikeb dma->tag = NULL;
25033027f3a5Smikeb }
25043027f3a5Smikeb }
25053027f3a5Smikeb
25063027f3a5Smikeb struct oce_ring *
oce_create_ring(struct oce_softc * sc,int nitems,int isize,int maxsegs)2507753c43a0Smikeb oce_create_ring(struct oce_softc *sc, int nitems, int isize, int maxsegs)
25083027f3a5Smikeb {
25097d5bbea0Smikeb struct oce_dma_mem *dma;
25103027f3a5Smikeb struct oce_ring *ring;
2511753c43a0Smikeb bus_size_t size = nitems * isize;
25123027f3a5Smikeb int rc;
25133027f3a5Smikeb
2514753c43a0Smikeb if (size > maxsegs * PAGE_SIZE)
2515c0000edeSmikeb return (NULL);
25163027f3a5Smikeb
25173027f3a5Smikeb ring = malloc(sizeof(struct oce_ring), M_DEVBUF, M_NOWAIT | M_ZERO);
25183027f3a5Smikeb if (ring == NULL)
2519c0000edeSmikeb return (NULL);
25203027f3a5Smikeb
2521753c43a0Smikeb ring->isize = isize;
2522753c43a0Smikeb ring->nitems = nitems;
25233027f3a5Smikeb
25247d5bbea0Smikeb dma = &ring->dma;
2525fc40f6ceSmikeb dma->tag = sc->sc_dmat;
2526753c43a0Smikeb rc = bus_dmamap_create(dma->tag, size, maxsegs, PAGE_SIZE, 0,
25277d5bbea0Smikeb BUS_DMA_NOWAIT, &dma->map);
25283027f3a5Smikeb if (rc != 0) {
2529fc40f6ceSmikeb printf("%s: failed to allocate DMA handle",
2530fc40f6ceSmikeb sc->sc_dev.dv_xname);
25313027f3a5Smikeb goto fail_0;
25323027f3a5Smikeb }
25333027f3a5Smikeb
2534753c43a0Smikeb rc = bus_dmamem_alloc(dma->tag, size, 0, 0, &dma->segs, maxsegs,
25357d5bbea0Smikeb &dma->nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
25363027f3a5Smikeb if (rc != 0) {
2537fc40f6ceSmikeb printf("%s: failed to allocate DMA memory",
2538fc40f6ceSmikeb sc->sc_dev.dv_xname);
25393027f3a5Smikeb goto fail_1;
25403027f3a5Smikeb }
25413027f3a5Smikeb
25427d5bbea0Smikeb rc = bus_dmamem_map(dma->tag, &dma->segs, dma->nsegs, size,
25437d5bbea0Smikeb &dma->vaddr, BUS_DMA_NOWAIT);
25443027f3a5Smikeb if (rc != 0) {
2545fc40f6ceSmikeb printf("%s: failed to map DMA memory", sc->sc_dev.dv_xname);
25463027f3a5Smikeb goto fail_2;
25473027f3a5Smikeb }
25483027f3a5Smikeb
25497d5bbea0Smikeb bus_dmamap_sync(dma->tag, dma->map, 0, dma->map->dm_mapsize,
25507d5bbea0Smikeb BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2551a7c4bff9Smikeb
25527d5bbea0Smikeb dma->paddr = 0;
25537d5bbea0Smikeb dma->size = size;
25543027f3a5Smikeb
25552974a94fSmikeb return (ring);
25563027f3a5Smikeb
25573027f3a5Smikeb fail_2:
25587d5bbea0Smikeb bus_dmamem_free(dma->tag, &dma->segs, dma->nsegs);
25593027f3a5Smikeb fail_1:
25607d5bbea0Smikeb bus_dmamap_destroy(dma->tag, dma->map);
25613027f3a5Smikeb fail_0:
2562df2ac69fStedu free(ring, M_DEVBUF, 0);
25632974a94fSmikeb return (NULL);
25643027f3a5Smikeb }
25653027f3a5Smikeb
2566176128bcSmikeb void
oce_destroy_ring(struct oce_softc * sc,struct oce_ring * ring)2567176128bcSmikeb oce_destroy_ring(struct oce_softc *sc, struct oce_ring *ring)
2568176128bcSmikeb {
2569176128bcSmikeb oce_dma_free(sc, &ring->dma);
2570df2ac69fStedu free(ring, M_DEVBUF, 0);
2571176128bcSmikeb }
2572176128bcSmikeb
2573dcc67c68Smikeb int
oce_load_ring(struct oce_softc * sc,struct oce_ring * ring,struct oce_pa * pa,int maxsegs)2574dcc67c68Smikeb oce_load_ring(struct oce_softc *sc, struct oce_ring *ring,
25759ec9e807Smikeb struct oce_pa *pa, int maxsegs)
25763027f3a5Smikeb {
25773027f3a5Smikeb struct oce_dma_mem *dma = &ring->dma;
2578753c43a0Smikeb int i;
25793027f3a5Smikeb
25803027f3a5Smikeb if (bus_dmamap_load(dma->tag, dma->map, dma->vaddr,
25817d5bbea0Smikeb ring->isize * ring->nitems, NULL, BUS_DMA_NOWAIT)) {
2582fc40f6ceSmikeb printf("%s: failed to load a ring map\n", sc->sc_dev.dv_xname);
25832974a94fSmikeb return (0);
25843027f3a5Smikeb }
25853027f3a5Smikeb
2586753c43a0Smikeb if (dma->map->dm_nsegs > maxsegs) {
25879ec9e807Smikeb printf("%s: too many segments\n", sc->sc_dev.dv_xname);
25882974a94fSmikeb return (0);
25893027f3a5Smikeb }
25903027f3a5Smikeb
2591e4b927f3Smikeb bus_dmamap_sync(dma->tag, dma->map, 0, dma->map->dm_mapsize,
2592e4b927f3Smikeb BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2593e4b927f3Smikeb
25949ec9e807Smikeb for (i = 0; i < dma->map->dm_nsegs; i++)
25959ec9e807Smikeb pa[i].addr = dma->map->dm_segs[i].ds_addr;
25962974a94fSmikeb
2597753c43a0Smikeb return (dma->map->dm_nsegs);
25983027f3a5Smikeb }
2599b2b84680Smikeb
26007d5bbea0Smikeb static inline void *
oce_ring_get(struct oce_ring * ring)26017d5bbea0Smikeb oce_ring_get(struct oce_ring *ring)
26027d5bbea0Smikeb {
26037d5bbea0Smikeb int index = ring->index;
26047d5bbea0Smikeb
26057d5bbea0Smikeb if (++ring->index == ring->nitems)
26067d5bbea0Smikeb ring->index = 0;
26077d5bbea0Smikeb return ((void *)(ring->dma.vaddr + index * ring->isize));
26087d5bbea0Smikeb }
26097d5bbea0Smikeb
26107d5bbea0Smikeb static inline void *
oce_ring_first(struct oce_ring * ring)26117d5bbea0Smikeb oce_ring_first(struct oce_ring *ring)
26127d5bbea0Smikeb {
26137d5bbea0Smikeb return ((void *)(ring->dma.vaddr + ring->index * ring->isize));
26147d5bbea0Smikeb }
26157d5bbea0Smikeb
26167d5bbea0Smikeb static inline void *
oce_ring_next(struct oce_ring * ring)26177d5bbea0Smikeb oce_ring_next(struct oce_ring *ring)
26187d5bbea0Smikeb {
26197d5bbea0Smikeb if (++ring->index == ring->nitems)
26207d5bbea0Smikeb ring->index = 0;
26217d5bbea0Smikeb return ((void *)(ring->dma.vaddr + ring->index * ring->isize));
26227d5bbea0Smikeb }
26237d5bbea0Smikeb
2624753c43a0Smikeb struct oce_pkt *
oce_pkt_alloc(struct oce_softc * sc,size_t size,int nsegs,int maxsegsz)262524f2625fSmikeb oce_pkt_alloc(struct oce_softc *sc, size_t size, int nsegs, int maxsegsz)
2626753c43a0Smikeb {
2627753c43a0Smikeb struct oce_pkt *pkt;
2628753c43a0Smikeb
262924f2625fSmikeb if ((pkt = pool_get(oce_pkt_pool, PR_NOWAIT | PR_ZERO)) == NULL)
2630753c43a0Smikeb return (NULL);
2631753c43a0Smikeb
263224f2625fSmikeb if (bus_dmamap_create(sc->sc_dmat, size, nsegs, maxsegsz, 0,
2633753c43a0Smikeb BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &pkt->map)) {
2634753c43a0Smikeb pool_put(oce_pkt_pool, pkt);
2635753c43a0Smikeb return (NULL);
2636753c43a0Smikeb }
2637753c43a0Smikeb
2638753c43a0Smikeb return (pkt);
2639753c43a0Smikeb }
2640753c43a0Smikeb
2641753c43a0Smikeb void
oce_pkt_free(struct oce_softc * sc,struct oce_pkt * pkt)2642753c43a0Smikeb oce_pkt_free(struct oce_softc *sc, struct oce_pkt *pkt)
2643753c43a0Smikeb {
2644753c43a0Smikeb if (pkt->map) {
2645fc40f6ceSmikeb bus_dmamap_unload(sc->sc_dmat, pkt->map);
2646fc40f6ceSmikeb bus_dmamap_destroy(sc->sc_dmat, pkt->map);
2647753c43a0Smikeb }
2648753c43a0Smikeb pool_put(oce_pkt_pool, pkt);
2649753c43a0Smikeb }
2650753c43a0Smikeb
2651753c43a0Smikeb static inline struct oce_pkt *
oce_pkt_get(struct oce_pkt_list * lst)2652753c43a0Smikeb oce_pkt_get(struct oce_pkt_list *lst)
2653753c43a0Smikeb {
2654753c43a0Smikeb struct oce_pkt *pkt;
2655753c43a0Smikeb
2656753c43a0Smikeb pkt = SIMPLEQ_FIRST(lst);
2657753c43a0Smikeb if (pkt == NULL)
2658753c43a0Smikeb return (NULL);
2659753c43a0Smikeb
2660753c43a0Smikeb SIMPLEQ_REMOVE_HEAD(lst, entry);
2661753c43a0Smikeb
2662753c43a0Smikeb return (pkt);
2663753c43a0Smikeb }
2664753c43a0Smikeb
2665753c43a0Smikeb static inline void
oce_pkt_put(struct oce_pkt_list * lst,struct oce_pkt * pkt)2666753c43a0Smikeb oce_pkt_put(struct oce_pkt_list *lst, struct oce_pkt *pkt)
2667753c43a0Smikeb {
2668753c43a0Smikeb SIMPLEQ_INSERT_TAIL(lst, pkt, entry);
2669753c43a0Smikeb }
2670753c43a0Smikeb
2671b2b84680Smikeb /**
2672b2b84680Smikeb * @brief Wait for FW to become ready and reset it
2673b2b84680Smikeb * @param sc software handle to the device
2674b2b84680Smikeb */
2675b2b84680Smikeb int
oce_init_fw(struct oce_softc * sc)2676b2b84680Smikeb oce_init_fw(struct oce_softc *sc)
2677b2b84680Smikeb {
2678f5b67696Smikeb struct ioctl_common_function_reset cmd;
2679b2b84680Smikeb uint32_t reg;
2680b2b84680Smikeb int err = 0, tmo = 60000;
2681b2b84680Smikeb
2682b2b84680Smikeb /* read semaphore CSR */
26833e0d1ae4Smikeb reg = oce_read_csr(sc, MPU_EP_SEMAPHORE(sc));
2684b2b84680Smikeb
2685b2b84680Smikeb /* if host is ready then wait for fw ready else send POST */
2686b2b84680Smikeb if ((reg & MPU_EP_SEM_STAGE_MASK) <= POST_STAGE_AWAITING_HOST_RDY) {
2687b2b84680Smikeb reg = (reg & ~MPU_EP_SEM_STAGE_MASK) | POST_STAGE_CHIP_RESET;
26883e0d1ae4Smikeb oce_write_csr(sc, MPU_EP_SEMAPHORE(sc), reg);
2689b2b84680Smikeb }
2690b2b84680Smikeb
2691b2b84680Smikeb /* wait for FW to become ready */
2692b2b84680Smikeb for (;;) {
2693b2b84680Smikeb if (--tmo == 0)
2694b2b84680Smikeb break;
2695b2b84680Smikeb
2696b2b84680Smikeb DELAY(1000);
2697b2b84680Smikeb
26983e0d1ae4Smikeb reg = oce_read_csr(sc, MPU_EP_SEMAPHORE(sc));
2699b2b84680Smikeb if (reg & MPU_EP_SEM_ERROR) {
2700b2b84680Smikeb printf(": POST failed: %#x\n", reg);
2701b2b84680Smikeb return (ENXIO);
2702b2b84680Smikeb }
2703b2b84680Smikeb if ((reg & MPU_EP_SEM_STAGE_MASK) == POST_STAGE_ARMFW_READY) {
2704b2b84680Smikeb /* reset FW */
2705fc40f6ceSmikeb if (ISSET(sc->sc_flags, OCE_F_RESET_RQD)) {
27069553ae17Schris memset(&cmd, 0, sizeof(cmd));
2707b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON,
2708b2b84680Smikeb OPCODE_COMMON_FUNCTION_RESET,
2709f5b67696Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
2710b2b84680Smikeb }
2711b2b84680Smikeb return (err);
2712b2b84680Smikeb }
2713b2b84680Smikeb }
2714b2b84680Smikeb
2715b2b84680Smikeb printf(": POST timed out: %#x\n", reg);
2716b2b84680Smikeb
2717b2b84680Smikeb return (ENXIO);
2718b2b84680Smikeb }
2719b2b84680Smikeb
2720b2b84680Smikeb static inline int
oce_mbox_wait(struct oce_softc * sc)2721b2b84680Smikeb oce_mbox_wait(struct oce_softc *sc)
2722b2b84680Smikeb {
2723b2b84680Smikeb int i;
2724b2b84680Smikeb
2725b2b84680Smikeb for (i = 0; i < 20000; i++) {
27263e0d1ae4Smikeb if (oce_read_db(sc, PD_MPU_MBOX_DB) & PD_MPU_MBOX_DB_READY)
2727b2b84680Smikeb return (0);
2728b2b84680Smikeb DELAY(100);
2729b2b84680Smikeb }
2730b2b84680Smikeb return (ETIMEDOUT);
2731b2b84680Smikeb }
2732b2b84680Smikeb
2733b2b84680Smikeb /**
2734b2b84680Smikeb * @brief Mailbox dispatch
2735b2b84680Smikeb * @param sc software handle to the device
2736b2b84680Smikeb */
2737b2b84680Smikeb int
oce_mbox_dispatch(struct oce_softc * sc)2738b2b84680Smikeb oce_mbox_dispatch(struct oce_softc *sc)
2739b2b84680Smikeb {
2740b2b84680Smikeb uint32_t pa, reg;
2741b2b84680Smikeb int err;
2742b2b84680Smikeb
2743d5413815Smikeb pa = (uint32_t)((uint64_t)OCE_MEM_DVA(&sc->sc_mbx) >> 34);
2744b2b84680Smikeb reg = PD_MPU_MBOX_DB_HI | (pa << PD_MPU_MBOX_DB_ADDR_SHIFT);
2745b2b84680Smikeb
2746b2b84680Smikeb if ((err = oce_mbox_wait(sc)) != 0)
2747b2b84680Smikeb goto out;
2748b2b84680Smikeb
27493e0d1ae4Smikeb oce_write_db(sc, PD_MPU_MBOX_DB, reg);
2750b2b84680Smikeb
2751d5413815Smikeb pa = (uint32_t)((uint64_t)OCE_MEM_DVA(&sc->sc_mbx) >> 4) & 0x3fffffff;
2752b2b84680Smikeb reg = pa << PD_MPU_MBOX_DB_ADDR_SHIFT;
2753b2b84680Smikeb
2754b2b84680Smikeb if ((err = oce_mbox_wait(sc)) != 0)
2755b2b84680Smikeb goto out;
2756b2b84680Smikeb
27573e0d1ae4Smikeb oce_write_db(sc, PD_MPU_MBOX_DB, reg);
2758b2b84680Smikeb
2759fc40f6ceSmikeb oce_dma_sync(&sc->sc_mbx, BUS_DMASYNC_POSTWRITE);
2760b2b84680Smikeb
2761b2b84680Smikeb if ((err = oce_mbox_wait(sc)) != 0)
2762b2b84680Smikeb goto out;
2763b2b84680Smikeb
2764b2b84680Smikeb out:
2765fc40f6ceSmikeb oce_dma_sync(&sc->sc_mbx, BUS_DMASYNC_PREREAD);
2766b2b84680Smikeb return (err);
2767b2b84680Smikeb }
2768b2b84680Smikeb
2769b2b84680Smikeb /**
2770b2b84680Smikeb * @brief Function to initialize the hw with host endian information
2771b2b84680Smikeb * @param sc software handle to the device
2772b2b84680Smikeb * @returns 0 on success, ETIMEDOUT on failure
2773b2b84680Smikeb */
2774b2b84680Smikeb int
oce_mbox_init(struct oce_softc * sc)2775b2b84680Smikeb oce_mbox_init(struct oce_softc *sc)
2776b2b84680Smikeb {
2777fc40f6ceSmikeb struct oce_bmbx *bmbx = OCE_MEM_KVA(&sc->sc_mbx);
2778b2b84680Smikeb uint8_t *ptr = (uint8_t *)&bmbx->mbx;
2779b2b84680Smikeb
2780fc40f6ceSmikeb if (!ISSET(sc->sc_flags, OCE_F_MBOX_ENDIAN_RQD))
2781c0000edeSmikeb return (0);
2782c0000edeSmikeb
2783b2b84680Smikeb /* Endian Signature */
2784b2b84680Smikeb *ptr++ = 0xff;
2785b2b84680Smikeb *ptr++ = 0x12;
2786b2b84680Smikeb *ptr++ = 0x34;
2787b2b84680Smikeb *ptr++ = 0xff;
2788b2b84680Smikeb *ptr++ = 0xff;
2789b2b84680Smikeb *ptr++ = 0x56;
2790b2b84680Smikeb *ptr++ = 0x78;
2791b2b84680Smikeb *ptr = 0xff;
2792b2b84680Smikeb
2793b2b84680Smikeb return (oce_mbox_dispatch(sc));
2794b2b84680Smikeb }
2795b2b84680Smikeb
2796b2b84680Smikeb int
oce_cmd(struct oce_softc * sc,int subsys,int opcode,int version,void * payload,int length)2797b2b84680Smikeb oce_cmd(struct oce_softc *sc, int subsys, int opcode, int version,
2798b2b84680Smikeb void *payload, int length)
2799b2b84680Smikeb {
2800fc40f6ceSmikeb struct oce_bmbx *bmbx = OCE_MEM_KVA(&sc->sc_mbx);
2801b2b84680Smikeb struct oce_mbx *mbx = &bmbx->mbx;
2802b2b84680Smikeb struct mbx_hdr *hdr;
2803b2b84680Smikeb caddr_t epayload = NULL;
2804b2b84680Smikeb int err;
2805b2b84680Smikeb
2806d5413815Smikeb if (length > OCE_MBX_PAYLOAD)
2807d5413815Smikeb epayload = OCE_MEM_KVA(&sc->sc_pld);
2808d5413815Smikeb if (length > OCE_MAX_PAYLOAD)
2809d5413815Smikeb return (EINVAL);
2810b2b84680Smikeb
2811fc40f6ceSmikeb oce_dma_sync(&sc->sc_mbx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2812b2b84680Smikeb
28139553ae17Schris memset(mbx, 0, sizeof(struct oce_mbx));
2814b2b84680Smikeb
2815b2b84680Smikeb mbx->payload_length = length;
2816b2b84680Smikeb
2817b2b84680Smikeb if (epayload) {
28189ec9e807Smikeb mbx->flags = OCE_MBX_F_SGE;
2819d5413815Smikeb oce_dma_sync(&sc->sc_pld, BUS_DMASYNC_PREREAD);
28208f478c19Schris memcpy(epayload, payload, length);
28219ec9e807Smikeb mbx->pld.sgl[0].addr = OCE_MEM_DVA(&sc->sc_pld);
28229ec9e807Smikeb mbx->pld.sgl[0].length = length;
2823d5413815Smikeb hdr = (struct mbx_hdr *)epayload;
2824b2b84680Smikeb } else {
28259ec9e807Smikeb mbx->flags = OCE_MBX_F_EMBED;
28268f478c19Schris memcpy(mbx->pld.data, payload, length);
28279ec9e807Smikeb hdr = (struct mbx_hdr *)&mbx->pld.data;
2828b2b84680Smikeb }
2829b2b84680Smikeb
28309ec9e807Smikeb hdr->subsys = subsys;
28319ec9e807Smikeb hdr->opcode = opcode;
28329ec9e807Smikeb hdr->version = version;
28339ec9e807Smikeb hdr->length = length - sizeof(*hdr);
2834b2b84680Smikeb if (opcode == OPCODE_COMMON_FUNCTION_RESET)
28359ec9e807Smikeb hdr->timeout = 2 * OCE_MBX_TIMEOUT;
2836b2b84680Smikeb else
28379ec9e807Smikeb hdr->timeout = OCE_MBX_TIMEOUT;
2838b2b84680Smikeb
2839d5413815Smikeb if (epayload)
2840d5413815Smikeb oce_dma_sync(&sc->sc_pld, BUS_DMASYNC_PREWRITE);
2841d5413815Smikeb
2842b2b84680Smikeb err = oce_mbox_dispatch(sc);
2843b2b84680Smikeb if (err == 0) {
2844b2b84680Smikeb if (epayload) {
2845d5413815Smikeb oce_dma_sync(&sc->sc_pld, BUS_DMASYNC_POSTWRITE);
28468f478c19Schris memcpy(payload, epayload, length);
2847b2b84680Smikeb } else
28488f478c19Schris memcpy(payload, &mbx->pld.data, length);
2849b2b84680Smikeb } else
28501289fc7cSmikeb printf("%s: mailbox timeout, subsys %d op %d ver %d "
285157e2f549Ssthen "%spayload length %d\n", sc->sc_dev.dv_xname, subsys,
28521289fc7cSmikeb opcode, version, epayload ? "ext " : "",
28531289fc7cSmikeb length);
2854b2b84680Smikeb return (err);
2855b2b84680Smikeb }
2856b2b84680Smikeb
2857b2b84680Smikeb /**
2858b2b84680Smikeb * @brief Firmware will send gracious notifications during
28594b1a56afSjsg * attach only after sending first mcc command. We
2860b2b84680Smikeb * use MCC queue only for getting async and mailbox
2861b2b84680Smikeb * for sending cmds. So to get gracious notifications
2862b2b84680Smikeb * at least send one dummy command on mcc.
2863b2b84680Smikeb */
2864b2b84680Smikeb void
oce_first_mcc(struct oce_softc * sc)2865b2b84680Smikeb oce_first_mcc(struct oce_softc *sc)
2866b2b84680Smikeb {
2867b2b84680Smikeb struct oce_mbx *mbx;
2868fc40f6ceSmikeb struct oce_mq *mq = sc->sc_mq;
2869b2b84680Smikeb struct mbx_hdr *hdr;
2870f5b67696Smikeb struct mbx_get_common_fw_version *cmd;
2871b2b84680Smikeb
28727d5bbea0Smikeb mbx = oce_ring_get(mq->ring);
28739553ae17Schris memset(mbx, 0, sizeof(struct oce_mbx));
2874b2b84680Smikeb
28759ec9e807Smikeb cmd = (struct mbx_get_common_fw_version *)&mbx->pld.data;
2876b2b84680Smikeb
2877f5b67696Smikeb hdr = &cmd->hdr;
28789ec9e807Smikeb hdr->subsys = SUBSYS_COMMON;
28799ec9e807Smikeb hdr->opcode = OPCODE_COMMON_GET_FW_VERSION;
28809ec9e807Smikeb hdr->version = OCE_MBX_VER_V0;
28819ec9e807Smikeb hdr->timeout = OCE_MBX_TIMEOUT;
28829ec9e807Smikeb hdr->length = sizeof(*cmd) - sizeof(*hdr);
2883b2b84680Smikeb
28849ec9e807Smikeb mbx->flags = OCE_MBX_F_EMBED;
2885f5b67696Smikeb mbx->payload_length = sizeof(*cmd);
2886b2b84680Smikeb oce_dma_sync(&mq->ring->dma, BUS_DMASYNC_PREREAD |
2887b2b84680Smikeb BUS_DMASYNC_PREWRITE);
28883e0d1ae4Smikeb oce_write_db(sc, PD_MQ_DB, mq->id | (1 << 16));
2889b2b84680Smikeb }
2890b2b84680Smikeb
2891b8b7fdccSmikeb int
oce_get_fw_config(struct oce_softc * sc)2892b8b7fdccSmikeb oce_get_fw_config(struct oce_softc *sc)
2893b8b7fdccSmikeb {
2894b8b7fdccSmikeb struct mbx_common_query_fw_config cmd;
2895b8b7fdccSmikeb int err;
2896b8b7fdccSmikeb
28979553ae17Schris memset(&cmd, 0, sizeof(cmd));
2898b8b7fdccSmikeb
2899b8b7fdccSmikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
2900b8b7fdccSmikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
2901b8b7fdccSmikeb if (err)
2902b8b7fdccSmikeb return (err);
2903b8b7fdccSmikeb
2904fc40f6ceSmikeb sc->sc_port = cmd.params.rsp.port_id;
2905fc40f6ceSmikeb sc->sc_fmode = cmd.params.rsp.function_mode;
2906b8b7fdccSmikeb
2907b8b7fdccSmikeb return (0);
2908b8b7fdccSmikeb }
2909b8b7fdccSmikeb
2910b8b7fdccSmikeb int
oce_check_native_mode(struct oce_softc * sc)2911b8b7fdccSmikeb oce_check_native_mode(struct oce_softc *sc)
2912b8b7fdccSmikeb {
2913b8b7fdccSmikeb struct mbx_common_set_function_cap cmd;
2914b8b7fdccSmikeb int err;
2915b8b7fdccSmikeb
29169553ae17Schris memset(&cmd, 0, sizeof(cmd));
2917b8b7fdccSmikeb
2918b8b7fdccSmikeb cmd.params.req.valid_capability_flags = CAP_SW_TIMESTAMPS |
2919b8b7fdccSmikeb CAP_BE3_NATIVE_ERX_API;
2920b8b7fdccSmikeb cmd.params.req.capability_flags = CAP_BE3_NATIVE_ERX_API;
2921b8b7fdccSmikeb
2922b8b7fdccSmikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_SET_FUNCTIONAL_CAPS,
2923b8b7fdccSmikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
2924b8b7fdccSmikeb if (err)
2925b8b7fdccSmikeb return (err);
2926b8b7fdccSmikeb
2927b8b7fdccSmikeb if (cmd.params.rsp.capability_flags & CAP_BE3_NATIVE_ERX_API)
2928fc40f6ceSmikeb SET(sc->sc_flags, OCE_F_BE3_NATIVE);
2929b8b7fdccSmikeb
2930b8b7fdccSmikeb return (0);
2931b8b7fdccSmikeb }
2932b8b7fdccSmikeb
2933b2b84680Smikeb /**
2934b2b84680Smikeb * @brief Function for creating a network interface.
2935b2b84680Smikeb * @param sc software handle to the device
2936b2b84680Smikeb * @returns 0 on success, error otherwise
2937b2b84680Smikeb */
2938b2b84680Smikeb int
oce_create_iface(struct oce_softc * sc,uint8_t * macaddr)2939b2b84680Smikeb oce_create_iface(struct oce_softc *sc, uint8_t *macaddr)
2940b2b84680Smikeb {
2941f5b67696Smikeb struct mbx_create_common_iface cmd;
29424078f66aSmikeb uint32_t caps, caps_en;
2943b2b84680Smikeb int err = 0;
2944b2b84680Smikeb
2945b2b84680Smikeb /* interface capabilities to give device when creating interface */
2946a8db2785Smikeb caps = MBX_RX_IFACE_BROADCAST | MBX_RX_IFACE_UNTAGGED |
2947a8db2785Smikeb MBX_RX_IFACE_PROMISC | MBX_RX_IFACE_MCAST_PROMISC |
2948a8db2785Smikeb MBX_RX_IFACE_RSS;
2949b2b84680Smikeb
2950b2b84680Smikeb /* capabilities to enable by default (others set dynamically) */
2951a8db2785Smikeb caps_en = MBX_RX_IFACE_BROADCAST | MBX_RX_IFACE_UNTAGGED;
2952b2b84680Smikeb
29534078f66aSmikeb if (!IS_XE201(sc)) {
2954b2b84680Smikeb /* LANCER A0 workaround */
2955a8db2785Smikeb caps |= MBX_RX_IFACE_PASS_L3L4_ERR;
2956a8db2785Smikeb caps_en |= MBX_RX_IFACE_PASS_L3L4_ERR;
2957b2b84680Smikeb }
2958b2b84680Smikeb
2959b2b84680Smikeb /* enable capabilities controlled via driver startup parameters */
2960fc40f6ceSmikeb if (sc->sc_rss_enable)
2961a8db2785Smikeb caps_en |= MBX_RX_IFACE_RSS;
2962b2b84680Smikeb
29639553ae17Schris memset(&cmd, 0, sizeof(cmd));
2964b2b84680Smikeb
2965f5b67696Smikeb cmd.params.req.version = 0;
29664078f66aSmikeb cmd.params.req.cap_flags = htole32(caps);
29674078f66aSmikeb cmd.params.req.enable_flags = htole32(caps_en);
2968b2b84680Smikeb if (macaddr != NULL) {
29698f478c19Schris memcpy(&cmd.params.req.mac_addr[0], macaddr, ETHER_ADDR_LEN);
2970f5b67696Smikeb cmd.params.req.mac_invalid = 0;
2971b2b84680Smikeb } else
2972f5b67696Smikeb cmd.params.req.mac_invalid = 1;
2973b2b84680Smikeb
2974b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_CREATE_IFACE,
2975f5b67696Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
2976b2b84680Smikeb if (err)
2977b2b84680Smikeb return (err);
2978b2b84680Smikeb
2979fc40f6ceSmikeb sc->sc_if_id = letoh32(cmd.params.rsp.if_id);
2980b2b84680Smikeb
2981b2b84680Smikeb if (macaddr != NULL)
2982fc40f6ceSmikeb sc->sc_pmac_id = letoh32(cmd.params.rsp.pmac_id);
2983b2b84680Smikeb
2984c0000edeSmikeb return (0);
2985b2b84680Smikeb }
2986b2b84680Smikeb
2987b2b84680Smikeb /**
2988b2b84680Smikeb * @brief Function to send the mbx command to configure vlan
2989b2b84680Smikeb * @param sc software handle to the device
29904078f66aSmikeb * @param vtags array of vlan tags
29914078f66aSmikeb * @param nvtags number of elements in array
2992b2b84680Smikeb * @param untagged boolean TRUE/FLASE
2993b2b84680Smikeb * @param promisc flag to enable/disable VLAN promiscuous mode
2994b2b84680Smikeb * @returns 0 on success, EIO on failure
2995b2b84680Smikeb */
2996b2b84680Smikeb int
oce_config_vlan(struct oce_softc * sc,struct normal_vlan * vtags,int nvtags,int untagged,int promisc)29974078f66aSmikeb oce_config_vlan(struct oce_softc *sc, struct normal_vlan *vtags, int nvtags,
29984078f66aSmikeb int untagged, int promisc)
2999b2b84680Smikeb {
3000f5b67696Smikeb struct mbx_common_config_vlan cmd;
3001b2b84680Smikeb
30029553ae17Schris memset(&cmd, 0, sizeof(cmd));
3003b2b84680Smikeb
3004fc40f6ceSmikeb cmd.params.req.if_id = sc->sc_if_id;
3005f5b67696Smikeb cmd.params.req.promisc = promisc;
3006f5b67696Smikeb cmd.params.req.untagged = untagged;
30074078f66aSmikeb cmd.params.req.num_vlans = nvtags;
3008b2b84680Smikeb
3009b2b84680Smikeb if (!promisc)
30108f478c19Schris memcpy(cmd.params.req.tags.normal_vlans, vtags,
30114078f66aSmikeb nvtags * sizeof(struct normal_vlan));
3012b2b84680Smikeb
301372ecf4ceSmikeb return (oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_CONFIG_IFACE_VLAN,
301472ecf4ceSmikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd)));
3015b2b84680Smikeb }
3016b2b84680Smikeb
3017b2b84680Smikeb /**
3018b2b84680Smikeb * @brief Function to set flow control capability in the hardware
3019b2b84680Smikeb * @param sc software handle to the device
302085582348Smikeb * @param flags flow control flags to set
3021b2b84680Smikeb * @returns 0 on success, EIO on failure
3022b2b84680Smikeb */
3023b2b84680Smikeb int
oce_set_flow_control(struct oce_softc * sc,uint64_t flags)3024f2a0e423Sstsp oce_set_flow_control(struct oce_softc *sc, uint64_t flags)
3025b2b84680Smikeb {
3026f5b67696Smikeb struct mbx_common_get_set_flow_control cmd;
302785582348Smikeb int err;
3028b2b84680Smikeb
30299553ae17Schris memset(&cmd, 0, sizeof(cmd));
3030b2b84680Smikeb
303185582348Smikeb cmd.rx_flow_control = flags & IFM_ETH_RXPAUSE ? 1 : 0;
303285582348Smikeb cmd.tx_flow_control = flags & IFM_ETH_TXPAUSE ? 1 : 0;
3033b2b84680Smikeb
303485582348Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_SET_FLOW_CONTROL,
303585582348Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
303685582348Smikeb if (err)
303785582348Smikeb return (err);
303885582348Smikeb
30399553ae17Schris memset(&cmd, 0, sizeof(cmd));
304085582348Smikeb
304185582348Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_GET_FLOW_CONTROL,
304285582348Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
304385582348Smikeb if (err)
304485582348Smikeb return (err);
304585582348Smikeb
3046fc40f6ceSmikeb sc->sc_fc = cmd.rx_flow_control ? IFM_ETH_RXPAUSE : 0;
3047fc40f6ceSmikeb sc->sc_fc |= cmd.tx_flow_control ? IFM_ETH_TXPAUSE : 0;
304885582348Smikeb
304985582348Smikeb return (0);
3050b2b84680Smikeb }
3051b2b84680Smikeb
3052b2b84680Smikeb #ifdef OCE_RSS
3053b2b84680Smikeb /**
3054b2b84680Smikeb * @brief Function to set flow control capability in the hardware
3055b2b84680Smikeb * @param sc software handle to the device
3056c0000edeSmikeb * @param enable 0=disable, OCE_RSS_xxx flags otherwise
3057b2b84680Smikeb * @returns 0 on success, EIO on failure
3058b2b84680Smikeb */
3059b2b84680Smikeb int
oce_config_rss(struct oce_softc * sc,int enable)3060b47f6b63Smikeb oce_config_rss(struct oce_softc *sc, int enable)
3061b2b84680Smikeb {
3062f5b67696Smikeb struct mbx_config_nic_rss cmd;
3063f5b67696Smikeb uint8_t *tbl = &cmd.params.req.cputable;
306472ecf4ceSmikeb int i, j;
3065b2b84680Smikeb
30669553ae17Schris memset(&cmd, 0, sizeof(cmd));
3067b2b84680Smikeb
3068b2b84680Smikeb if (enable)
3069c0000edeSmikeb cmd.params.req.enable_rss = RSS_ENABLE_IPV4 | RSS_ENABLE_IPV6 |
30708860bd06Sderaadt RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_TCP_IPV6;
3071f5b67696Smikeb cmd.params.req.flush = OCE_FLUSH;
3072fc40f6ceSmikeb cmd.params.req.if_id = htole32(sc->sc_if_id);
3073b2b84680Smikeb
3074f5b67696Smikeb arc4random_buf(cmd.params.req.hash, sizeof(cmd.params.req.hash));
3075b2b84680Smikeb
3076b2b84680Smikeb /*
3077b2b84680Smikeb * Initialize the RSS CPU indirection table.
3078b2b84680Smikeb *
3079f8db2aa2Shenning * The table is used to choose the queue to place incoming packets.
3080f8db2aa2Shenning * Incoming packets are hashed. The lowest bits in the hash result
3081b2b84680Smikeb * are used as the index into the CPU indirection table.
3082b2b84680Smikeb * Each entry in the table contains the RSS CPU-ID returned by the NIC
3083b2b84680Smikeb * create. Based on the CPU ID, the receive completion is routed to
3084b2b84680Smikeb * the corresponding RSS CQs. (Non-RSS packets are always completed
3085b2b84680Smikeb * on the default (0) CQ).
3086b2b84680Smikeb */
3087fc40f6ceSmikeb for (i = 0, j = 0; j < sc->sc_nrq; j++) {
3088fc40f6ceSmikeb if (sc->sc_rq[j]->cfg.is_rss_queue)
3089fc40f6ceSmikeb tbl[i++] = sc->sc_rq[j]->rss_cpuid;
3090b2b84680Smikeb }
3091b2b84680Smikeb if (i > 0)
3092f5b67696Smikeb cmd->params.req.cpu_tbl_sz_log2 = htole16(ilog2(i));
3093b2b84680Smikeb else
3094b2b84680Smikeb return (ENXIO);
3095b2b84680Smikeb
309672ecf4ceSmikeb return (oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_CONFIG_RSS, OCE_MBX_VER_V0,
309772ecf4ceSmikeb &cmd, sizeof(cmd)));
3098b2b84680Smikeb }
3099b2b84680Smikeb #endif /* OCE_RSS */
3100b2b84680Smikeb
3101b2b84680Smikeb /**
3102b2b84680Smikeb * @brief Function for hardware update multicast filter
3103b2b84680Smikeb * @param sc software handle to the device
3104b2b84680Smikeb * @param multi table of multicast addresses
3105b2b84680Smikeb * @param naddr number of multicast addresses in the table
3106b2b84680Smikeb */
3107b2b84680Smikeb int
oce_update_mcast(struct oce_softc * sc,uint8_t multi[][ETHER_ADDR_LEN],int naddr)3108b2b84680Smikeb oce_update_mcast(struct oce_softc *sc,
3109c0000edeSmikeb uint8_t multi[][ETHER_ADDR_LEN], int naddr)
3110b2b84680Smikeb {
3111f5b67696Smikeb struct mbx_set_common_iface_multicast cmd;
3112b2b84680Smikeb
31139553ae17Schris memset(&cmd, 0, sizeof(cmd));
3114b2b84680Smikeb
31158f478c19Schris memcpy(&cmd.params.req.mac[0], &multi[0], naddr * ETHER_ADDR_LEN);
3116f5b67696Smikeb cmd.params.req.num_mac = htole16(naddr);
3117fc40f6ceSmikeb cmd.params.req.if_id = sc->sc_if_id;
3118b2b84680Smikeb
311972ecf4ceSmikeb return (oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_SET_IFACE_MULTICAST,
312072ecf4ceSmikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd)));
3121b2b84680Smikeb }
3122b2b84680Smikeb
3123b2b84680Smikeb /**
3124b2b84680Smikeb * @brief RXF function to enable/disable device promiscuous mode
3125b2b84680Smikeb * @param sc software handle to the device
3126b2b84680Smikeb * @param enable enable/disable flag
3127b2b84680Smikeb * @returns 0 on success, EIO on failure
3128b2b84680Smikeb * @note
3129b2b84680Smikeb * The OPCODE_NIC_CONFIG_PROMISCUOUS command deprecated for Lancer.
3130b2b84680Smikeb * This function uses the COMMON_SET_IFACE_RX_FILTER command instead.
3131b2b84680Smikeb */
3132b2b84680Smikeb int
oce_set_promisc(struct oce_softc * sc,int enable)3133b2b84680Smikeb oce_set_promisc(struct oce_softc *sc, int enable)
3134b2b84680Smikeb {
3135f5b67696Smikeb struct mbx_set_common_iface_rx_filter cmd;
3136b2b84680Smikeb struct iface_rx_filter_ctx *req;
3137b2b84680Smikeb
31389553ae17Schris memset(&cmd, 0, sizeof(cmd));
3139b2b84680Smikeb
3140f5b67696Smikeb req = &cmd.params.req;
3141fc40f6ceSmikeb req->if_id = sc->sc_if_id;
31424078f66aSmikeb
3143b2b84680Smikeb if (enable)
31444078f66aSmikeb req->iface_flags = req->iface_flags_mask =
3145a8db2785Smikeb MBX_RX_IFACE_PROMISC | MBX_RX_IFACE_VLAN_PROMISC;
3146b2b84680Smikeb
314772ecf4ceSmikeb return (oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_SET_IFACE_RX_FILTER,
314872ecf4ceSmikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd)));
3149b2b84680Smikeb }
3150b2b84680Smikeb
3151b2b84680Smikeb /**
3152b2b84680Smikeb * @brief Function to query the link status from the hardware
3153b2b84680Smikeb * @param sc software handle to the device
3154b2b84680Smikeb * @param[out] link pointer to the structure returning link attributes
3155b2b84680Smikeb * @returns 0 on success, EIO on failure
3156b2b84680Smikeb */
3157b2b84680Smikeb int
oce_get_link_status(struct oce_softc * sc)3158b2b84680Smikeb oce_get_link_status(struct oce_softc *sc)
3159b2b84680Smikeb {
3160f5b67696Smikeb struct mbx_query_common_link_config cmd;
3161b2b84680Smikeb int err;
3162b2b84680Smikeb
31639553ae17Schris memset(&cmd, 0, sizeof(cmd));
3164b2b84680Smikeb
3165b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_QUERY_LINK_CONFIG,
3166f5b67696Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
3167b2b84680Smikeb if (err)
3168b2b84680Smikeb return (err);
3169b2b84680Smikeb
3170fc40f6ceSmikeb sc->sc_link_up = (letoh32(cmd.params.rsp.logical_link_status) ==
3171bfd0edabSmikeb NTWK_LOGICAL_LINK_UP);
3172b2b84680Smikeb
3173bfd0edabSmikeb if (cmd.params.rsp.mac_speed < 5)
3174fc40f6ceSmikeb sc->sc_link_speed = cmd.params.rsp.mac_speed;
3175b2b84680Smikeb else
3176fc40f6ceSmikeb sc->sc_link_speed = 0;
3177b2b84680Smikeb
3178b2b84680Smikeb return (0);
3179b2b84680Smikeb }
3180b2b84680Smikeb
318133279783Smikeb void
oce_macaddr_set(struct oce_softc * sc)318233279783Smikeb oce_macaddr_set(struct oce_softc *sc)
318333279783Smikeb {
318433279783Smikeb uint32_t old_pmac_id = sc->sc_pmac_id;
318533279783Smikeb int status = 0;
318633279783Smikeb
31872f155a4aSchris if (!memcmp(sc->sc_macaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
318833279783Smikeb return;
318933279783Smikeb
319033279783Smikeb status = oce_macaddr_add(sc, sc->sc_ac.ac_enaddr, &sc->sc_pmac_id);
319133279783Smikeb if (!status)
319233279783Smikeb status = oce_macaddr_del(sc, old_pmac_id);
319333279783Smikeb else
319433279783Smikeb printf("%s: failed to set MAC address\n", sc->sc_dev.dv_xname);
319533279783Smikeb }
319633279783Smikeb
3197b2b84680Smikeb int
oce_macaddr_get(struct oce_softc * sc,uint8_t * macaddr)3198b2b84680Smikeb oce_macaddr_get(struct oce_softc *sc, uint8_t *macaddr)
3199b2b84680Smikeb {
3200f5b67696Smikeb struct mbx_query_common_iface_mac cmd;
3201b2b84680Smikeb int err;
3202b2b84680Smikeb
32039553ae17Schris memset(&cmd, 0, sizeof(cmd));
3204b2b84680Smikeb
3205f5b67696Smikeb cmd.params.req.type = MAC_ADDRESS_TYPE_NETWORK;
3206f5b67696Smikeb cmd.params.req.permanent = 1;
3207b2b84680Smikeb
3208b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_QUERY_IFACE_MAC,
3209f5b67696Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
3210b2b84680Smikeb if (err == 0)
32118f478c19Schris memcpy(macaddr, &cmd.params.rsp.mac.mac_addr[0],
3212c0000edeSmikeb ETHER_ADDR_LEN);
3213b2b84680Smikeb return (err);
3214b2b84680Smikeb }
3215b2b84680Smikeb
3216b2b84680Smikeb int
oce_macaddr_add(struct oce_softc * sc,uint8_t * enaddr,uint32_t * pmac)3217b47f6b63Smikeb oce_macaddr_add(struct oce_softc *sc, uint8_t *enaddr, uint32_t *pmac)
3218b2b84680Smikeb {
3219f5b67696Smikeb struct mbx_add_common_iface_mac cmd;
3220b2b84680Smikeb int err;
3221b2b84680Smikeb
32229553ae17Schris memset(&cmd, 0, sizeof(cmd));
3223b2b84680Smikeb
3224fc40f6ceSmikeb cmd.params.req.if_id = htole16(sc->sc_if_id);
32258f478c19Schris memcpy(cmd.params.req.mac_address, enaddr, ETHER_ADDR_LEN);
3226b2b84680Smikeb
3227b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_ADD_IFACE_MAC,
3228f5b67696Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
3229b2b84680Smikeb if (err == 0)
3230b47f6b63Smikeb *pmac = letoh32(cmd.params.rsp.pmac_id);
3231b2b84680Smikeb return (err);
3232b2b84680Smikeb }
3233b2b84680Smikeb
3234b2b84680Smikeb int
oce_macaddr_del(struct oce_softc * sc,uint32_t pmac)3235b47f6b63Smikeb oce_macaddr_del(struct oce_softc *sc, uint32_t pmac)
3236b2b84680Smikeb {
3237f5b67696Smikeb struct mbx_del_common_iface_mac cmd;
3238b2b84680Smikeb
32399553ae17Schris memset(&cmd, 0, sizeof(cmd));
3240b2b84680Smikeb
3241fc40f6ceSmikeb cmd.params.req.if_id = htole16(sc->sc_if_id);
3242b47f6b63Smikeb cmd.params.req.pmac_id = htole32(pmac);
3243b2b84680Smikeb
324472ecf4ceSmikeb return (oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_DEL_IFACE_MAC,
324572ecf4ceSmikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd)));
3246b2b84680Smikeb }
3247b2b84680Smikeb
3248b2b84680Smikeb int
oce_new_rq(struct oce_softc * sc,struct oce_rq * rq)3249b2b84680Smikeb oce_new_rq(struct oce_softc *sc, struct oce_rq *rq)
3250b2b84680Smikeb {
3251f5b67696Smikeb struct mbx_create_nic_rq cmd;
3252b2b84680Smikeb int err, npages;
3253b2b84680Smikeb
32549553ae17Schris memset(&cmd, 0, sizeof(cmd));
3255b2b84680Smikeb
3256f5b67696Smikeb npages = oce_load_ring(sc, rq->ring, &cmd.params.req.pages[0],
3257f5b67696Smikeb nitems(cmd.params.req.pages));
3258b2b84680Smikeb if (!npages) {
3259b2b84680Smikeb printf("%s: failed to load the rq ring\n", __func__);
3260b2b84680Smikeb return (1);
3261b2b84680Smikeb }
3262b2b84680Smikeb
3263b2b84680Smikeb if (IS_XE201(sc)) {
3264753c43a0Smikeb cmd.params.req.frag_size = rq->fragsize / 2048;
3265f5b67696Smikeb cmd.params.req.page_size = 1;
3266b2b84680Smikeb } else
3267753c43a0Smikeb cmd.params.req.frag_size = ilog2(rq->fragsize);
3268f5b67696Smikeb cmd.params.req.num_pages = npages;
3269f5b67696Smikeb cmd.params.req.cq_id = rq->cq->id;
3270fc40f6ceSmikeb cmd.params.req.if_id = htole32(sc->sc_if_id);
3271753c43a0Smikeb cmd.params.req.max_frame_size = htole16(rq->mtu);
3272753c43a0Smikeb cmd.params.req.is_rss_queue = htole32(rq->rss);
3273b2b84680Smikeb
3274b2b84680Smikeb err = oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_CREATE_RQ,
3275f5b67696Smikeb IS_XE201(sc) ? OCE_MBX_VER_V1 : OCE_MBX_VER_V0, &cmd,
3276f5b67696Smikeb sizeof(cmd));
3277b2b84680Smikeb if (err)
3278b2b84680Smikeb return (err);
3279b2b84680Smikeb
3280f5b67696Smikeb rq->id = letoh16(cmd.params.rsp.rq_id);
3281f5b67696Smikeb rq->rss_cpuid = cmd.params.rsp.rss_cpuid;
3282b2b84680Smikeb
3283b2b84680Smikeb return (0);
3284b2b84680Smikeb }
3285b2b84680Smikeb
3286b2b84680Smikeb int
oce_new_wq(struct oce_softc * sc,struct oce_wq * wq)3287b2b84680Smikeb oce_new_wq(struct oce_softc *sc, struct oce_wq *wq)
3288b2b84680Smikeb {
3289f5b67696Smikeb struct mbx_create_nic_wq cmd;
3290b2b84680Smikeb int err, npages;
3291b2b84680Smikeb
32929553ae17Schris memset(&cmd, 0, sizeof(cmd));
3293b2b84680Smikeb
3294f5b67696Smikeb npages = oce_load_ring(sc, wq->ring, &cmd.params.req.pages[0],
3295f5b67696Smikeb nitems(cmd.params.req.pages));
3296b2b84680Smikeb if (!npages) {
3297b2b84680Smikeb printf("%s: failed to load the wq ring\n", __func__);
3298b2b84680Smikeb return (1);
3299b2b84680Smikeb }
3300b2b84680Smikeb
3301b2b84680Smikeb if (IS_XE201(sc))
3302fc40f6ceSmikeb cmd.params.req.if_id = sc->sc_if_id;
3303753c43a0Smikeb cmd.params.req.nic_wq_type = NIC_WQ_TYPE_STANDARD;
3304f5b67696Smikeb cmd.params.req.num_pages = npages;
3305753c43a0Smikeb cmd.params.req.wq_size = ilog2(wq->nitems) + 1;
3306f5b67696Smikeb cmd.params.req.cq_id = htole16(wq->cq->id);
3307f5b67696Smikeb cmd.params.req.ulp_num = 1;
3308b2b84680Smikeb
3309b2b84680Smikeb err = oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_CREATE_WQ,
3310f5b67696Smikeb IS_XE201(sc) ? OCE_MBX_VER_V1 : OCE_MBX_VER_V0, &cmd,
3311f5b67696Smikeb sizeof(cmd));
3312b2b84680Smikeb if (err)
3313b2b84680Smikeb return (err);
3314b2b84680Smikeb
3315f5b67696Smikeb wq->id = letoh16(cmd.params.rsp.wq_id);
3316b2b84680Smikeb
3317b2b84680Smikeb return (0);
3318b2b84680Smikeb }
3319b2b84680Smikeb
3320b2b84680Smikeb int
oce_new_mq(struct oce_softc * sc,struct oce_mq * mq)3321b2b84680Smikeb oce_new_mq(struct oce_softc *sc, struct oce_mq *mq)
3322b2b84680Smikeb {
3323f5b67696Smikeb struct mbx_create_common_mq_ex cmd;
3324b2b84680Smikeb union oce_mq_ext_ctx *ctx;
3325b2b84680Smikeb int err, npages;
3326b2b84680Smikeb
33279553ae17Schris memset(&cmd, 0, sizeof(cmd));
3328b2b84680Smikeb
3329f5b67696Smikeb npages = oce_load_ring(sc, mq->ring, &cmd.params.req.pages[0],
3330f5b67696Smikeb nitems(cmd.params.req.pages));
3331b2b84680Smikeb if (!npages) {
3332b2b84680Smikeb printf("%s: failed to load the mq ring\n", __func__);
3333b2b84680Smikeb return (-1);
3334b2b84680Smikeb }
3335b2b84680Smikeb
3336f5b67696Smikeb ctx = &cmd.params.req.context;
3337b2b84680Smikeb ctx->v0.num_pages = npages;
3338b2b84680Smikeb ctx->v0.cq_id = mq->cq->id;
3339753c43a0Smikeb ctx->v0.ring_size = ilog2(mq->nitems) + 1;
3340b2b84680Smikeb ctx->v0.valid = 1;
3341b2b84680Smikeb /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
3342b2b84680Smikeb ctx->v0.async_evt_bitmap = 0xffffffff;
3343b2b84680Smikeb
3344b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_CREATE_MQ_EXT,
3345f5b67696Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
3346b2b84680Smikeb if (err)
3347b2b84680Smikeb return (err);
3348b2b84680Smikeb
3349f5b67696Smikeb mq->id = letoh16(cmd.params.rsp.mq_id);
3350b2b84680Smikeb
3351b2b84680Smikeb return (0);
3352b2b84680Smikeb }
3353b2b84680Smikeb
3354b2b84680Smikeb int
oce_new_eq(struct oce_softc * sc,struct oce_eq * eq)3355b2b84680Smikeb oce_new_eq(struct oce_softc *sc, struct oce_eq *eq)
3356b2b84680Smikeb {
3357f5b67696Smikeb struct mbx_create_common_eq cmd;
3358b2b84680Smikeb int err, npages;
3359b2b84680Smikeb
33609553ae17Schris memset(&cmd, 0, sizeof(cmd));
3361b2b84680Smikeb
3362f5b67696Smikeb npages = oce_load_ring(sc, eq->ring, &cmd.params.req.pages[0],
3363f5b67696Smikeb nitems(cmd.params.req.pages));
3364b2b84680Smikeb if (!npages) {
3365b2b84680Smikeb printf("%s: failed to load the eq ring\n", __func__);
3366b2b84680Smikeb return (-1);
3367b2b84680Smikeb }
3368b2b84680Smikeb
3369f5b67696Smikeb cmd.params.req.ctx.num_pages = htole16(npages);
3370f5b67696Smikeb cmd.params.req.ctx.valid = 1;
3371753c43a0Smikeb cmd.params.req.ctx.size = (eq->isize == 4) ? 0 : 1;
3372753c43a0Smikeb cmd.params.req.ctx.count = ilog2(eq->nitems / 256);
3373f5b67696Smikeb cmd.params.req.ctx.armed = 0;
3374753c43a0Smikeb cmd.params.req.ctx.delay_mult = htole32(eq->delay);
3375b2b84680Smikeb
3376b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_CREATE_EQ,
3377f5b67696Smikeb OCE_MBX_VER_V0, &cmd, sizeof(cmd));
3378b2b84680Smikeb if (err)
3379b2b84680Smikeb return (err);
3380b2b84680Smikeb
3381f5b67696Smikeb eq->id = letoh16(cmd.params.rsp.eq_id);
3382b2b84680Smikeb
3383b2b84680Smikeb return (0);
3384b2b84680Smikeb }
3385b2b84680Smikeb
3386b2b84680Smikeb int
oce_new_cq(struct oce_softc * sc,struct oce_cq * cq)3387b2b84680Smikeb oce_new_cq(struct oce_softc *sc, struct oce_cq *cq)
3388b2b84680Smikeb {
3389f5b67696Smikeb struct mbx_create_common_cq cmd;
3390b2b84680Smikeb union oce_cq_ctx *ctx;
3391b2b84680Smikeb int err, npages;
3392b2b84680Smikeb
33939553ae17Schris memset(&cmd, 0, sizeof(cmd));
3394b2b84680Smikeb
3395f5b67696Smikeb npages = oce_load_ring(sc, cq->ring, &cmd.params.req.pages[0],
3396f5b67696Smikeb nitems(cmd.params.req.pages));
3397b2b84680Smikeb if (!npages) {
3398b2b84680Smikeb printf("%s: failed to load the cq ring\n", __func__);
3399b2b84680Smikeb return (-1);
3400b2b84680Smikeb }
3401b2b84680Smikeb
3402f5b67696Smikeb ctx = &cmd.params.req.cq_ctx;
3403b2b84680Smikeb
3404b2b84680Smikeb if (IS_XE201(sc)) {
3405b2b84680Smikeb ctx->v2.num_pages = htole16(npages);
3406b2b84680Smikeb ctx->v2.page_size = 1; /* for 4K */
3407753c43a0Smikeb ctx->v2.eventable = cq->eventable;
3408b2b84680Smikeb ctx->v2.valid = 1;
3409753c43a0Smikeb ctx->v2.count = ilog2(cq->nitems / 256);
3410753c43a0Smikeb ctx->v2.nodelay = cq->nodelay;
3411753c43a0Smikeb ctx->v2.coalesce_wm = cq->ncoalesce;
3412b2b84680Smikeb ctx->v2.armed = 0;
3413b2b84680Smikeb ctx->v2.eq_id = cq->eq->id;
3414b2b84680Smikeb if (ctx->v2.count == 3) {
3415753c43a0Smikeb if (cq->nitems > (4*1024)-1)
3416b2b84680Smikeb ctx->v2.cqe_count = (4*1024)-1;
3417b2b84680Smikeb else
3418753c43a0Smikeb ctx->v2.cqe_count = cq->nitems;
3419b2b84680Smikeb }
3420b2b84680Smikeb } else {
3421b2b84680Smikeb ctx->v0.num_pages = htole16(npages);
3422753c43a0Smikeb ctx->v0.eventable = cq->eventable;
3423b2b84680Smikeb ctx->v0.valid = 1;
3424753c43a0Smikeb ctx->v0.count = ilog2(cq->nitems / 256);
3425753c43a0Smikeb ctx->v0.nodelay = cq->nodelay;
3426753c43a0Smikeb ctx->v0.coalesce_wm = cq->ncoalesce;
3427b2b84680Smikeb ctx->v0.armed = 0;
3428b2b84680Smikeb ctx->v0.eq_id = cq->eq->id;
3429b2b84680Smikeb }
3430b2b84680Smikeb
3431b2b84680Smikeb err = oce_cmd(sc, SUBSYS_COMMON, OPCODE_COMMON_CREATE_CQ,
3432f5b67696Smikeb IS_XE201(sc) ? OCE_MBX_VER_V2 : OCE_MBX_VER_V0, &cmd,
3433f5b67696Smikeb sizeof(cmd));
3434b2b84680Smikeb if (err)
3435b2b84680Smikeb return (err);
3436b2b84680Smikeb
3437f5b67696Smikeb cq->id = letoh16(cmd.params.rsp.cq_id);
3438b2b84680Smikeb
3439b2b84680Smikeb return (0);
3440b2b84680Smikeb }
3441b2b84680Smikeb
344205201e9aSmikeb int
oce_init_stats(struct oce_softc * sc)344305201e9aSmikeb oce_init_stats(struct oce_softc *sc)
344405201e9aSmikeb {
344549cdbe2bSmikeb union cmd {
344605201e9aSmikeb struct mbx_get_nic_stats_v0 _be2;
344705201e9aSmikeb struct mbx_get_nic_stats _be3;
344805201e9aSmikeb struct mbx_get_pport_stats _xe201;
344949cdbe2bSmikeb };
345005201e9aSmikeb
345149cdbe2bSmikeb sc->sc_statcmd = malloc(sizeof(union cmd), M_DEVBUF, M_ZERO | M_NOWAIT);
345205201e9aSmikeb if (sc->sc_statcmd == NULL) {
345305201e9aSmikeb printf("%s: failed to allocate statistics command block\n",
345405201e9aSmikeb sc->sc_dev.dv_xname);
345505201e9aSmikeb return (-1);
345605201e9aSmikeb }
345705201e9aSmikeb return (0);
345805201e9aSmikeb }
345905201e9aSmikeb
346005201e9aSmikeb int
oce_update_stats(struct oce_softc * sc)346194f89b30Smikeb oce_update_stats(struct oce_softc *sc)
346294f89b30Smikeb {
3463fc40f6ceSmikeb struct ifnet *ifp = &sc->sc_ac.ac_if;
346494f89b30Smikeb uint64_t rxe, txe;
346594f89b30Smikeb int err;
346694f89b30Smikeb
3467fc40f6ceSmikeb if (ISSET(sc->sc_flags, OCE_F_BE2))
346894f89b30Smikeb err = oce_stats_be2(sc, &rxe, &txe);
3469fc40f6ceSmikeb else if (ISSET(sc->sc_flags, OCE_F_BE3))
347094f89b30Smikeb err = oce_stats_be3(sc, &rxe, &txe);
347194f89b30Smikeb else
347294f89b30Smikeb err = oce_stats_xe(sc, &rxe, &txe);
347394f89b30Smikeb if (err)
347494f89b30Smikeb return (err);
347594f89b30Smikeb
3476fc40f6ceSmikeb ifp->if_ierrors += (rxe > sc->sc_rx_errors) ?
3477fc40f6ceSmikeb rxe - sc->sc_rx_errors : sc->sc_rx_errors - rxe;
3478fc40f6ceSmikeb sc->sc_rx_errors = rxe;
3479fc40f6ceSmikeb ifp->if_oerrors += (txe > sc->sc_tx_errors) ?
3480fc40f6ceSmikeb txe - sc->sc_tx_errors : sc->sc_tx_errors - txe;
3481fc40f6ceSmikeb sc->sc_tx_errors = txe;
348294f89b30Smikeb
348394f89b30Smikeb return (0);
348494f89b30Smikeb }
348594f89b30Smikeb
3486b2b84680Smikeb int
oce_stats_be2(struct oce_softc * sc,uint64_t * rxe,uint64_t * txe)3487b2b84680Smikeb oce_stats_be2(struct oce_softc *sc, uint64_t *rxe, uint64_t *txe)
3488b2b84680Smikeb {
348905201e9aSmikeb struct mbx_get_nic_stats_v0 *cmd = sc->sc_statcmd;
3490b2b84680Smikeb struct oce_pmem_stats *ms;
3491b2b84680Smikeb struct oce_rxf_stats_v0 *rs;
3492b2b84680Smikeb struct oce_port_rxf_stats_v0 *ps;
3493b2b84680Smikeb int err;
3494b2b84680Smikeb
349505201e9aSmikeb memset(cmd, 0, sizeof(*cmd));
3496b2b84680Smikeb
3497b2b84680Smikeb err = oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_GET_STATS, OCE_MBX_VER_V0,
349805201e9aSmikeb cmd, sizeof(*cmd));
3499b2b84680Smikeb if (err)
3500b2b84680Smikeb return (err);
3501b2b84680Smikeb
350205201e9aSmikeb ms = &cmd->params.rsp.stats.pmem;
350305201e9aSmikeb rs = &cmd->params.rsp.stats.rxf;
3504fc40f6ceSmikeb ps = &rs->port[sc->sc_port];
3505b2b84680Smikeb
3506b2b84680Smikeb *rxe = ps->rx_crc_errors + ps->rx_in_range_errors +
3507b2b84680Smikeb ps->rx_frame_too_long + ps->rx_dropped_runt +
3508b2b84680Smikeb ps->rx_ip_checksum_errs + ps->rx_tcp_checksum_errs +
3509b2b84680Smikeb ps->rx_udp_checksum_errs + ps->rxpp_fifo_overflow_drop +
3510b2b84680Smikeb ps->rx_dropped_tcp_length + ps->rx_dropped_too_small +
3511b2b84680Smikeb ps->rx_dropped_too_short + ps->rx_out_range_errors +
3512b2b84680Smikeb ps->rx_dropped_header_too_small + ps->rx_input_fifo_overflow_drop +
3513b2b84680Smikeb ps->rx_alignment_symbol_errors;
3514fc40f6ceSmikeb if (sc->sc_if_id)
3515b2b84680Smikeb *rxe += rs->port1_jabber_events;
3516b2b84680Smikeb else
3517b2b84680Smikeb *rxe += rs->port0_jabber_events;
3518b2b84680Smikeb *rxe += ms->eth_red_drops;
3519b2b84680Smikeb
3520b2b84680Smikeb *txe = 0; /* hardware doesn't provide any extra tx error statistics */
3521b2b84680Smikeb
3522b2b84680Smikeb return (0);
3523b2b84680Smikeb }
3524b2b84680Smikeb
3525b2b84680Smikeb int
oce_stats_be3(struct oce_softc * sc,uint64_t * rxe,uint64_t * txe)3526b2b84680Smikeb oce_stats_be3(struct oce_softc *sc, uint64_t *rxe, uint64_t *txe)
3527b2b84680Smikeb {
352805201e9aSmikeb struct mbx_get_nic_stats *cmd = sc->sc_statcmd;
3529b2b84680Smikeb struct oce_pmem_stats *ms;
3530b2b84680Smikeb struct oce_rxf_stats_v1 *rs;
3531b2b84680Smikeb struct oce_port_rxf_stats_v1 *ps;
3532b2b84680Smikeb int err;
3533b2b84680Smikeb
353405201e9aSmikeb memset(cmd, 0, sizeof(*cmd));
3535b2b84680Smikeb
3536b2b84680Smikeb err = oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_GET_STATS, OCE_MBX_VER_V1,
353705201e9aSmikeb cmd, sizeof(*cmd));
3538b2b84680Smikeb if (err)
3539b2b84680Smikeb return (err);
3540b2b84680Smikeb
354105201e9aSmikeb ms = &cmd->params.rsp.stats.pmem;
354205201e9aSmikeb rs = &cmd->params.rsp.stats.rxf;
3543fc40f6ceSmikeb ps = &rs->port[sc->sc_port];
3544b2b84680Smikeb
3545b2b84680Smikeb *rxe = ps->rx_crc_errors + ps->rx_in_range_errors +
3546b2b84680Smikeb ps->rx_frame_too_long + ps->rx_dropped_runt +
3547b2b84680Smikeb ps->rx_ip_checksum_errs + ps->rx_tcp_checksum_errs +
3548b2b84680Smikeb ps->rx_udp_checksum_errs + ps->rxpp_fifo_overflow_drop +
3549b2b84680Smikeb ps->rx_dropped_tcp_length + ps->rx_dropped_too_small +
3550b2b84680Smikeb ps->rx_dropped_too_short + ps->rx_out_range_errors +
3551b2b84680Smikeb ps->rx_dropped_header_too_small + ps->rx_input_fifo_overflow_drop +
3552b2b84680Smikeb ps->rx_alignment_symbol_errors + ps->jabber_events;
3553b2b84680Smikeb *rxe += ms->eth_red_drops;
3554b2b84680Smikeb
3555b2b84680Smikeb *txe = 0; /* hardware doesn't provide any extra tx error statistics */
3556b2b84680Smikeb
3557b2b84680Smikeb return (0);
3558b2b84680Smikeb }
3559b2b84680Smikeb
3560b2b84680Smikeb int
oce_stats_xe(struct oce_softc * sc,uint64_t * rxe,uint64_t * txe)3561b2b84680Smikeb oce_stats_xe(struct oce_softc *sc, uint64_t *rxe, uint64_t *txe)
3562b2b84680Smikeb {
356305201e9aSmikeb struct mbx_get_pport_stats *cmd = sc->sc_statcmd;
3564b2b84680Smikeb struct oce_pport_stats *pps;
3565b2b84680Smikeb int err;
3566b2b84680Smikeb
356705201e9aSmikeb memset(cmd, 0, sizeof(*cmd));
3568b2b84680Smikeb
356905201e9aSmikeb cmd->params.req.reset_stats = 0;
357005201e9aSmikeb cmd->params.req.port_number = sc->sc_if_id;
3571b2b84680Smikeb
3572b2b84680Smikeb err = oce_cmd(sc, SUBSYS_NIC, OPCODE_NIC_GET_PPORT_STATS,
357305201e9aSmikeb OCE_MBX_VER_V0, cmd, sizeof(*cmd));
3574b2b84680Smikeb if (err)
3575b2b84680Smikeb return (err);
3576b2b84680Smikeb
357705201e9aSmikeb pps = &cmd->params.rsp.pps;
3578b2b84680Smikeb
3579b2b84680Smikeb *rxe = pps->rx_discards + pps->rx_errors + pps->rx_crc_errors +
3580b2b84680Smikeb pps->rx_alignment_errors + pps->rx_symbol_errors +
3581b2b84680Smikeb pps->rx_frames_too_long + pps->rx_internal_mac_errors +
3582b2b84680Smikeb pps->rx_undersize_pkts + pps->rx_oversize_pkts + pps->rx_jabbers +
3583b2b84680Smikeb pps->rx_control_frames_unknown_opcode + pps->rx_in_range_errors +
3584b2b84680Smikeb pps->rx_out_of_range_errors + pps->rx_ip_checksum_errors +
3585b2b84680Smikeb pps->rx_tcp_checksum_errors + pps->rx_udp_checksum_errors +
3586b2b84680Smikeb pps->rx_fifo_overflow + pps->rx_input_fifo_overflow +
3587b2b84680Smikeb pps->rx_drops_too_many_frags + pps->rx_drops_mtu;
3588b2b84680Smikeb
3589b2b84680Smikeb *txe = pps->tx_discards + pps->tx_errors + pps->tx_internal_mac_errors;
3590b2b84680Smikeb
3591b2b84680Smikeb return (0);
3592b2b84680Smikeb }
3593