summaryrefslogtreecommitdiffstats
path: root/sys/dev/re/if_re.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/re/if_re.c')
-rw-r--r--sys/dev/re/if_re.c174
1 files changed, 151 insertions, 23 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index 8fd20b6..95983af 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -123,6 +123,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/sysctl.h>
#include <sys/taskqueue.h>
#include <net/if.h>
@@ -281,6 +282,9 @@ static void re_clrwol (struct rl_softc *);
static int re_diag (struct rl_softc *);
#endif
+static void re_add_sysctls (struct rl_softc *);
+static int re_sysctl_stats (SYSCTL_HANDLER_ARGS);
+
static device_method_t re_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, re_probe),
@@ -880,7 +884,7 @@ re_probe(device_t dev)
uint16_t devid, vendor;
uint16_t revid, sdevid;
int i;
-
+
vendor = pci_get_vendor(dev);
devid = pci_get_device(dev);
revid = pci_get_revid(dev);
@@ -934,6 +938,7 @@ re_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
static int
re_allocmem(device_t dev, struct rl_softc *sc)
{
+ bus_addr_t lowaddr;
bus_size_t rx_list_size, tx_list_size;
int error;
int i;
@@ -947,10 +952,13 @@ re_allocmem(device_t dev, struct rl_softc *sc)
* register should be set. However some RealTek chips are known
* to be buggy on DAC handling, therefore disable DAC by limiting
* DMA address space to 32bit. PCIe variants of RealTek chips
- * may not have the limitation but I took safer path.
+ * may not have the limitation.
*/
+ lowaddr = BUS_SPACE_MAXADDR;
+ if ((sc->rl_flags & RL_FLAG_PCIE) == 0)
+ lowaddr = BUS_SPACE_MAXADDR_32BIT;
error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ lowaddr, BUS_SPACE_MAXADDR, NULL, NULL,
BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0,
NULL, NULL, &sc->rl_parent_tag);
if (error) {
@@ -1080,6 +1088,35 @@ re_allocmem(device_t dev, struct rl_softc *sc)
}
}
+ /* Create DMA map for statistics. */
+ error = bus_dma_tag_create(sc->rl_parent_tag, RL_DUMP_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ sizeof(struct rl_stats), 1, sizeof(struct rl_stats), 0, NULL, NULL,
+ &sc->rl_ldata.rl_stag);
+ if (error) {
+ device_printf(dev, "could not create statistics DMA tag\n");
+ return (error);
+ }
+ /* Allocate DMA'able memory for statistics. */
+ error = bus_dmamem_alloc(sc->rl_ldata.rl_stag,
+ (void **)&sc->rl_ldata.rl_stats,
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
+ &sc->rl_ldata.rl_smap);
+ if (error) {
+ device_printf(dev,
+ "could not allocate statistics DMA memory\n");
+ return (error);
+ }
+ /* Load the map for statistics. */
+ sc->rl_ldata.rl_stats_addr = 0;
+ error = bus_dmamap_load(sc->rl_ldata.rl_stag, sc->rl_ldata.rl_smap,
+ sc->rl_ldata.rl_stats, sizeof(struct rl_stats), re_dma_map_addr,
+ &sc->rl_ldata.rl_stats_addr, BUS_DMA_NOWAIT);
+ if (error != 0 || sc->rl_ldata.rl_stats_addr == 0) {
+ device_printf(dev, "could not load statistics DMA memory\n");
+ return (ENOMEM);
+ }
+
return (0);
}
@@ -1117,7 +1154,7 @@ re_attach(device_t dev)
/*
* Prefer memory space register mapping over IO space.
* Because RTL8169SC does not seem to work when memory mapping
- * is used always activate io mapping.
+ * is used always activate io mapping.
*/
if (devid == RT_DEVICEID_8169SC)
prefer_iomap = 1;
@@ -1370,6 +1407,7 @@ re_attach(device_t dev)
error = re_allocmem(dev, sc);
if (error)
goto fail;
+ re_add_sysctls(sc);
ifp = sc->rl_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
@@ -1599,22 +1637,26 @@ re_detach(device_t dev)
/* Unload and free the RX DMA ring memory and map */
if (sc->rl_ldata.rl_rx_list_tag) {
- bus_dmamap_unload(sc->rl_ldata.rl_rx_list_tag,
- sc->rl_ldata.rl_rx_list_map);
- bus_dmamem_free(sc->rl_ldata.rl_rx_list_tag,
- sc->rl_ldata.rl_rx_list,
- sc->rl_ldata.rl_rx_list_map);
+ if (sc->rl_ldata.rl_rx_list_map)
+ bus_dmamap_unload(sc->rl_ldata.rl_rx_list_tag,
+ sc->rl_ldata.rl_rx_list_map);
+ if (sc->rl_ldata.rl_rx_list_map && sc->rl_ldata.rl_rx_list)
+ bus_dmamem_free(sc->rl_ldata.rl_rx_list_tag,
+ sc->rl_ldata.rl_rx_list,
+ sc->rl_ldata.rl_rx_list_map);
bus_dma_tag_destroy(sc->rl_ldata.rl_rx_list_tag);
}
/* Unload and free the TX DMA ring memory and map */
if (sc->rl_ldata.rl_tx_list_tag) {
- bus_dmamap_unload(sc->rl_ldata.rl_tx_list_tag,
- sc->rl_ldata.rl_tx_list_map);
- bus_dmamem_free(sc->rl_ldata.rl_tx_list_tag,
- sc->rl_ldata.rl_tx_list,
- sc->rl_ldata.rl_tx_list_map);
+ if (sc->rl_ldata.rl_tx_list_map)
+ bus_dmamap_unload(sc->rl_ldata.rl_tx_list_tag,
+ sc->rl_ldata.rl_tx_list_map);
+ if (sc->rl_ldata.rl_tx_list_map && sc->rl_ldata.rl_tx_list)
+ bus_dmamem_free(sc->rl_ldata.rl_tx_list_tag,
+ sc->rl_ldata.rl_tx_list,
+ sc->rl_ldata.rl_tx_list_map);
bus_dma_tag_destroy(sc->rl_ldata.rl_tx_list_tag);
}
@@ -1639,11 +1681,12 @@ re_detach(device_t dev)
/* Unload and free the stats buffer and map */
if (sc->rl_ldata.rl_stag) {
- bus_dmamap_unload(sc->rl_ldata.rl_stag,
- sc->rl_ldata.rl_rx_list_map);
- bus_dmamem_free(sc->rl_ldata.rl_stag,
- sc->rl_ldata.rl_stats,
- sc->rl_ldata.rl_smap);
+ if (sc->rl_ldata.rl_smap)
+ bus_dmamap_unload(sc->rl_ldata.rl_stag,
+ sc->rl_ldata.rl_smap);
+ if (sc->rl_ldata.rl_smap && sc->rl_ldata.rl_stats)
+ bus_dmamem_free(sc->rl_ldata.rl_stag,
+ sc->rl_ldata.rl_stats, sc->rl_ldata.rl_smap);
bus_dma_tag_destroy(sc->rl_ldata.rl_stag);
}
@@ -2016,9 +2059,9 @@ re_rxeof(struct rl_softc *sc, int *rx_npktsp)
if (rx_npktsp != NULL)
*rx_npktsp = rx_npkts;
if (maxpkt)
- return(EAGAIN);
+ return (EAGAIN);
- return(0);
+ return (0);
}
static void
@@ -2107,7 +2150,7 @@ re_tick(void *xsc)
* Reclaim transmitted frames here. Technically it is not
* necessary to do here but it ensures periodic reclamation
* regardless of Tx completion interrupt which seems to be
- * lost on PCIe based controllers under certain situations.
+ * lost on PCIe based controllers under certain situations.
*/
re_txeof(sc);
re_watchdog(sc);
@@ -2835,7 +2878,7 @@ re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if (ifr->ifr_reqcap & IFCAP_POLLING) {
error = ether_poll_register(re_poll, ifp);
if (error)
- return(error);
+ return (error);
RL_LOCK(sc);
/* Disable interrupts */
CSR_WRITE_2(sc, RL_IMR, 0x0000);
@@ -3181,3 +3224,88 @@ re_clrwol(struct rl_softc *sc)
v &= ~RL_CFG5_WOL_LANWAKE;
CSR_WRITE_1(sc, RL_CFG5, v);
}
+
+static void
+re_add_sysctls(struct rl_softc *sc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid_list *children;
+
+ ctx = device_get_sysctl_ctx(sc->rl_dev);
+ children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->rl_dev));
+
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "stats",
+ CTLTYPE_INT | CTLFLAG_RW, sc, 0, re_sysctl_stats, "I",
+ "Statistics Information");
+}
+
+static int
+re_sysctl_stats(SYSCTL_HANDLER_ARGS)
+{
+ struct rl_softc *sc;
+ struct rl_stats *stats;
+ int error, i, result;
+
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+ if (error || req->newptr == NULL)
+ return (error);
+
+ if (result == 1) {
+ sc = (struct rl_softc *)arg1;
+ RL_LOCK(sc);
+ bus_dmamap_sync(sc->rl_ldata.rl_stag,
+ sc->rl_ldata.rl_smap, BUS_DMASYNC_PREREAD);
+ CSR_WRITE_4(sc, RL_DUMPSTATS_HI,
+ RL_ADDR_HI(sc->rl_ldata.rl_stats_addr));
+ CSR_WRITE_4(sc, RL_DUMPSTATS_LO,
+ RL_ADDR_LO(sc->rl_ldata.rl_stats_addr));
+ CSR_WRITE_4(sc, RL_DUMPSTATS_LO,
+ RL_ADDR_LO(sc->rl_ldata.rl_stats_addr |
+ RL_DUMPSTATS_START));
+ for (i = RL_TIMEOUT; i > 0; i--) {
+ if ((CSR_READ_4(sc, RL_DUMPSTATS_LO) &
+ RL_DUMPSTATS_START) == 0)
+ break;
+ DELAY(1000);
+ }
+ bus_dmamap_sync(sc->rl_ldata.rl_stag,
+ sc->rl_ldata.rl_smap, BUS_DMASYNC_POSTREAD);
+ RL_UNLOCK(sc);
+ if (i == 0) {
+ device_printf(sc->rl_dev,
+ "DUMP statistics request timedout\n");
+ return (ETIMEDOUT);
+ }
+ stats = sc->rl_ldata.rl_stats;
+ printf("%s statistics:\n", device_get_nameunit(sc->rl_dev));
+ printf("Tx frames : %ju\n",
+ (uintmax_t)le64toh(stats->rl_tx_pkts));
+ printf("Rx frames : %ju\n",
+ (uintmax_t)le64toh(stats->rl_rx_pkts));
+ printf("Tx errors : %ju\n",
+ (uintmax_t)le64toh(stats->rl_tx_errs));
+ printf("Rx errors : %u\n",
+ le32toh(stats->rl_rx_errs));
+ printf("Rx missed frames : %u\n",
+ (uint32_t)le16toh(stats->rl_missed_pkts));
+ printf("Rx frame alignment errs : %u\n",
+ (uint32_t)le16toh(stats->rl_rx_framealign_errs));
+ printf("Tx single collisions : %u\n",
+ le32toh(stats->rl_tx_onecoll));
+ printf("Tx multiple collisions : %u\n",
+ le32toh(stats->rl_tx_multicolls));
+ printf("Rx unicast frames : %ju\n",
+ (uintmax_t)le64toh(stats->rl_rx_ucasts));
+ printf("Rx broadcast frames : %ju\n",
+ (uintmax_t)le64toh(stats->rl_rx_bcasts));
+ printf("Rx multicast frames : %u\n",
+ le32toh(stats->rl_rx_mcasts));
+ printf("Tx aborts : %u\n",
+ (uint32_t)le16toh(stats->rl_tx_aborts));
+ printf("Tx underruns : %u\n",
+ (uint32_t)le16toh(stats->rl_rx_underruns));
+ }
+
+ return (error);
+}
OpenPOWER on IntegriCloud