1*4bf8ce03SAdrian Chadd /*-
2*4bf8ce03SAdrian Chadd * SPDX-License-Identifier: BSD-2-Clause
3*4bf8ce03SAdrian Chadd *
4*4bf8ce03SAdrian Chadd * Copyright (c) 2019, 2020, 2023-2025 Kevin Lo <kevlo@openbsd.org>
5*4bf8ce03SAdrian Chadd * Copyright (c) 2025 Adrian Chadd <adrian@FreeBSD.org>
6*4bf8ce03SAdrian Chadd *
7*4bf8ce03SAdrian Chadd * Permission to use, copy, modify, and distribute this software for any
8*4bf8ce03SAdrian Chadd * purpose with or without fee is hereby granted, provided that the above
9*4bf8ce03SAdrian Chadd * copyright notice and this permission notice appear in all copies.
10*4bf8ce03SAdrian Chadd *
11*4bf8ce03SAdrian Chadd * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12*4bf8ce03SAdrian Chadd * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13*4bf8ce03SAdrian Chadd * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14*4bf8ce03SAdrian Chadd * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*4bf8ce03SAdrian Chadd * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*4bf8ce03SAdrian Chadd * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*4bf8ce03SAdrian Chadd * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*4bf8ce03SAdrian Chadd */
19*4bf8ce03SAdrian Chadd
20*4bf8ce03SAdrian Chadd /* $OpenBSD: if_rge.c,v 1.38 2025/09/19 00:41:14 kevlo Exp $ */
21*4bf8ce03SAdrian Chadd
22*4bf8ce03SAdrian Chadd #include <sys/param.h>
23*4bf8ce03SAdrian Chadd #include <sys/systm.h>
24*4bf8ce03SAdrian Chadd #include <sys/sockio.h>
25*4bf8ce03SAdrian Chadd #include <sys/mbuf.h>
26*4bf8ce03SAdrian Chadd #include <sys/malloc.h>
27*4bf8ce03SAdrian Chadd #include <sys/endian.h>
28*4bf8ce03SAdrian Chadd #include <sys/socket.h>
29*4bf8ce03SAdrian Chadd #include <net/if.h>
30*4bf8ce03SAdrian Chadd #include <net/if_media.h>
31*4bf8ce03SAdrian Chadd #include <sys/queue.h>
32*4bf8ce03SAdrian Chadd #include <sys/taskqueue.h>
33*4bf8ce03SAdrian Chadd #include <sys/bus.h>
34*4bf8ce03SAdrian Chadd #include <sys/module.h>
35*4bf8ce03SAdrian Chadd #include <sys/rman.h>
36*4bf8ce03SAdrian Chadd
37*4bf8ce03SAdrian Chadd #include <netinet/in.h>
38*4bf8ce03SAdrian Chadd #include <netinet/if_ether.h>
39*4bf8ce03SAdrian Chadd
40*4bf8ce03SAdrian Chadd #include <net/bpf.h>
41*4bf8ce03SAdrian Chadd #include <net/ethernet.h>
42*4bf8ce03SAdrian Chadd #include <net/if.h>
43*4bf8ce03SAdrian Chadd #include <net/if_var.h>
44*4bf8ce03SAdrian Chadd #include <net/if_arp.h>
45*4bf8ce03SAdrian Chadd #include <net/if_dl.h>
46*4bf8ce03SAdrian Chadd #include <net/if_media.h>
47*4bf8ce03SAdrian Chadd #include <net/if_types.h>
48*4bf8ce03SAdrian Chadd #include <net/if_vlan_var.h>
49*4bf8ce03SAdrian Chadd
50*4bf8ce03SAdrian Chadd #include <machine/bus.h>
51*4bf8ce03SAdrian Chadd #include <machine/resource.h>
52*4bf8ce03SAdrian Chadd
53*4bf8ce03SAdrian Chadd #include <dev/mii/mii.h>
54*4bf8ce03SAdrian Chadd
55*4bf8ce03SAdrian Chadd #include <dev/pci/pcivar.h>
56*4bf8ce03SAdrian Chadd #include <dev/pci/pcireg.h>
57*4bf8ce03SAdrian Chadd
58*4bf8ce03SAdrian Chadd #include "if_rge_vendor.h"
59*4bf8ce03SAdrian Chadd #include "if_rgereg.h"
60*4bf8ce03SAdrian Chadd #include "if_rgevar.h"
61*4bf8ce03SAdrian Chadd #include "if_rge_debug.h"
62*4bf8ce03SAdrian Chadd
63*4bf8ce03SAdrian Chadd #include "if_rge_stats.h"
64*4bf8ce03SAdrian Chadd
65*4bf8ce03SAdrian Chadd
66*4bf8ce03SAdrian Chadd /**
67*4bf8ce03SAdrian Chadd * @brief Fetch the MAC statistics from the hardware
68*4bf8ce03SAdrian Chadd *
69*4bf8ce03SAdrian Chadd * I don't know if this can be done asynchronously (eg via
70*4bf8ce03SAdrian Chadd * an interrupt notification path for completion) as I
71*4bf8ce03SAdrian Chadd * currently don't have datasheets. OpenBSD and the
72*4bf8ce03SAdrian Chadd * older if_re driver both implement this using polling.
73*4bf8ce03SAdrian Chadd *
74*4bf8ce03SAdrian Chadd * Must be called with the driver lock held.
75*4bf8ce03SAdrian Chadd */
76*4bf8ce03SAdrian Chadd int
rge_hw_mac_stats_fetch(struct rge_softc * sc,struct rge_hw_mac_stats * hws)77*4bf8ce03SAdrian Chadd rge_hw_mac_stats_fetch(struct rge_softc *sc, struct rge_hw_mac_stats *hws)
78*4bf8ce03SAdrian Chadd {
79*4bf8ce03SAdrian Chadd struct rge_mac_stats *ss = &sc->sc_mac_stats;
80*4bf8ce03SAdrian Chadd uint32_t reg;
81*4bf8ce03SAdrian Chadd uint8_t command;
82*4bf8ce03SAdrian Chadd int i;
83*4bf8ce03SAdrian Chadd
84*4bf8ce03SAdrian Chadd RGE_ASSERT_LOCKED(sc);
85*4bf8ce03SAdrian Chadd
86*4bf8ce03SAdrian Chadd command = RGE_READ_1(sc, RGE_CMD);
87*4bf8ce03SAdrian Chadd if (command == 0xff || (command & RGE_CMD_RXENB) == 0)
88*4bf8ce03SAdrian Chadd return (ENETDOWN);
89*4bf8ce03SAdrian Chadd
90*4bf8ce03SAdrian Chadd bus_dmamap_sync(sc->sc_dmat_stats_buf, ss->map, BUS_DMASYNC_PREREAD);
91*4bf8ce03SAdrian Chadd
92*4bf8ce03SAdrian Chadd #if 0
93*4bf8ce03SAdrian Chadd if (extend_stats)
94*4bf8ce03SAdrian Chadd re_set_mac_ocp_bit(sc, 0xEA84, (BIT_1 | BIT_0));
95*4bf8ce03SAdrian Chadd #endif
96*4bf8ce03SAdrian Chadd
97*4bf8ce03SAdrian Chadd /* Program in the memory page to write data into */
98*4bf8ce03SAdrian Chadd RGE_WRITE_4(sc, RGE_DTCCR_HI, RGE_ADDR_HI(ss->paddr));
99*4bf8ce03SAdrian Chadd RGE_WRITE_BARRIER_4(sc, RGE_DTCCR_HI);
100*4bf8ce03SAdrian Chadd
101*4bf8ce03SAdrian Chadd (void) RGE_READ_1(sc, RGE_CMD);
102*4bf8ce03SAdrian Chadd
103*4bf8ce03SAdrian Chadd RGE_WRITE_4(sc, RGE_DTCCR_LO, RGE_ADDR_LO(ss->paddr));
104*4bf8ce03SAdrian Chadd RGE_WRITE_BARRIER_4(sc, RGE_DTCCR_LO);
105*4bf8ce03SAdrian Chadd
106*4bf8ce03SAdrian Chadd /* Inform the hardware to begin stats writing */
107*4bf8ce03SAdrian Chadd RGE_WRITE_4(sc, RGE_DTCCR_LO, RGE_ADDR_LO(ss->paddr) | RGE_DTCCR_CMD);
108*4bf8ce03SAdrian Chadd RGE_WRITE_BARRIER_4(sc, RGE_DTCCR_LO);
109*4bf8ce03SAdrian Chadd
110*4bf8ce03SAdrian Chadd for (i = 0; i < 1000; i++) {
111*4bf8ce03SAdrian Chadd RGE_READ_BARRIER_4(sc, RGE_DTCCR_LO);
112*4bf8ce03SAdrian Chadd reg = RGE_READ_4(sc, RGE_DTCCR_LO);
113*4bf8ce03SAdrian Chadd if ((reg & RGE_DTCCR_CMD) == 0)
114*4bf8ce03SAdrian Chadd break;
115*4bf8ce03SAdrian Chadd DELAY(10);
116*4bf8ce03SAdrian Chadd }
117*4bf8ce03SAdrian Chadd
118*4bf8ce03SAdrian Chadd #if 0
119*4bf8ce03SAdrian Chadd if (extend_stats)
120*4bf8ce03SAdrian Chadd re_clear_mac_ocp_bit(sc, 0xEA84, (BIT_1 | BIT_0));
121*4bf8ce03SAdrian Chadd #endif
122*4bf8ce03SAdrian Chadd
123*4bf8ce03SAdrian Chadd if ((reg & RGE_DTCCR_CMD) != 0)
124*4bf8ce03SAdrian Chadd return (ETIMEDOUT);
125*4bf8ce03SAdrian Chadd
126*4bf8ce03SAdrian Chadd bus_dmamap_sync(sc->sc_dmat_stats_buf, ss->map, BUS_DMASYNC_POSTREAD);
127*4bf8ce03SAdrian Chadd
128*4bf8ce03SAdrian Chadd /* Copy them out - assume host == NIC order for now for bring-up */
129*4bf8ce03SAdrian Chadd if (hws != NULL)
130*4bf8ce03SAdrian Chadd *hws = *ss->stats;
131*4bf8ce03SAdrian Chadd
132*4bf8ce03SAdrian Chadd return (0);
133*4bf8ce03SAdrian Chadd }
134