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