Swap pending with accepted patches, rebase remaining pending patches on top of new upstream. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
438 lines
16 KiB
Diff
438 lines
16 KiB
Diff
From a21d33a5265f0b31d935a8b9b2b6faefb5185911 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Sun, 12 Apr 2026 01:02:05 +0100
|
|
Subject: [PATCH 2/2] net: dsa: mxl862xx: implement .get_stats64
|
|
|
|
Poll free-running firmware RMON counters every 2 seconds and accumulate
|
|
deltas into 64-bit per-port statistics. 32-bit packet counters wrap
|
|
in ~220s at 10 Gbps line rate with minimum-size frames; the 2s polling
|
|
interval provides a comfortable margin. The .get_stats64 callback
|
|
forces a fresh poll so that counters are always up to date when queried.
|
|
|
|
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|
Link: https://patch.msgid.link/fa38548ba05866879e8912721edc91947ce4ff12.1775951347.git.daniel@makrotopia.org
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
---
|
|
drivers/net/dsa/mxl862xx/mxl862xx-host.c | 8 +-
|
|
drivers/net/dsa/mxl862xx/mxl862xx.c | 175 +++++++++++++++++++++++
|
|
drivers/net/dsa/mxl862xx/mxl862xx.h | 94 +++++++++++-
|
|
3 files changed, 270 insertions(+), 7 deletions(-)
|
|
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx-host.c
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-host.c
|
|
@@ -48,7 +48,7 @@ static void mxl862xx_crc_err_work_fn(str
|
|
dev_close(dp->conduit);
|
|
rtnl_unlock();
|
|
|
|
- clear_bit(0, &priv->crc_err);
|
|
+ clear_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags);
|
|
}
|
|
|
|
/* Firmware CRC error codes (outside normal Zephyr errno range). */
|
|
@@ -247,7 +247,7 @@ static int mxl862xx_issue_cmd(struct mxl
|
|
|
|
ret = mxl862xx_crc6_verify(ctrl_enc, len_enc, &fw_result);
|
|
if (ret) {
|
|
- if (!test_and_set_bit(0, &priv->crc_err))
|
|
+ if (!test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags))
|
|
schedule_work(&priv->crc_err_work);
|
|
return -EIO;
|
|
}
|
|
@@ -314,7 +314,7 @@ static int mxl862xx_send_cmd(struct mxl8
|
|
if (ret < 0) {
|
|
if ((ret == MXL862XX_FW_CRC6_ERR ||
|
|
ret == MXL862XX_FW_CRC16_ERR) &&
|
|
- !test_and_set_bit(0, &priv->crc_err))
|
|
+ !test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags))
|
|
schedule_work(&priv->crc_err_work);
|
|
if (!quiet)
|
|
dev_err(&priv->mdiodev->dev,
|
|
@@ -458,7 +458,7 @@ int mxl862xx_api_wrap(struct mxl862xx_pr
|
|
}
|
|
|
|
if (crc16(0xffff, (const u8 *)data, size) != crc) {
|
|
- if (!test_and_set_bit(0, &priv->crc_err))
|
|
+ if (!test_and_set_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags))
|
|
schedule_work(&priv->crc_err_work);
|
|
ret = -EIO;
|
|
goto out;
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
|
@@ -30,6 +30,12 @@
|
|
#define MXL862XX_API_READ_QUIET(dev, cmd, data) \
|
|
mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), true, true)
|
|
|
|
+/* Polling interval for RMON counter accumulation. At 2.5 Gbps with
|
|
+ * minimum-size (64-byte) frames, a 32-bit packet counter wraps in ~880s.
|
|
+ * 2s gives a comfortable margin.
|
|
+ */
|
|
+#define MXL862XX_STATS_POLL_INTERVAL (2 * HZ)
|
|
+
|
|
struct mxl862xx_mib_desc {
|
|
unsigned int size;
|
|
unsigned int offset;
|
|
@@ -677,6 +683,9 @@ static int mxl862xx_setup(struct dsa_swi
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ schedule_delayed_work(&priv->stats_work,
|
|
+ MXL862XX_STATS_POLL_INTERVAL);
|
|
+
|
|
return mxl862xx_setup_mdio(ds);
|
|
}
|
|
|
|
@@ -1900,6 +1909,159 @@ static void mxl862xx_get_rmon_stats(stru
|
|
|
|
*ranges = mxl862xx_rmon_ranges;
|
|
}
|
|
+
|
|
+/* Compute the delta between two 32-bit free-running counter snapshots,
|
|
+ * handling a single wrap-around correctly via unsigned subtraction.
|
|
+ */
|
|
+static u64 mxl862xx_delta32(u32 cur, u32 prev)
|
|
+{
|
|
+ return (u32)(cur - prev);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mxl862xx_stats_poll - Read RMON counters and accumulate into 64-bit stats
|
|
+ * @ds: DSA switch
|
|
+ * @port: port index
|
|
+ *
|
|
+ * The firmware RMON counters are free-running 32-bit values (64-bit for
|
|
+ * byte counters). This function reads the hardware via MDIO (may sleep),
|
|
+ * computes deltas from the previous snapshot, and accumulates them into
|
|
+ * 64-bit per-port stats under a spinlock.
|
|
+ *
|
|
+ * Called only from the stats polling workqueue -- serialized by the
|
|
+ * single-threaded delayed_work, so no MDIO locking is needed here.
|
|
+ */
|
|
+static void mxl862xx_stats_poll(struct dsa_switch *ds, int port)
|
|
+{
|
|
+ struct mxl862xx_priv *priv = ds->priv;
|
|
+ struct mxl862xx_port_stats *s = &priv->ports[port].stats;
|
|
+ u32 rx_fcserr, rx_under, rx_over, rx_align, tx_drop;
|
|
+ u32 rx_drop, rx_evlan, mtu_exc, tx_acm;
|
|
+ struct mxl862xx_rmon_port_cnt cnt;
|
|
+ u64 rx_bytes, tx_bytes;
|
|
+ u32 rx_mcast, tx_coll;
|
|
+ u32 rx_pkts, tx_pkts;
|
|
+
|
|
+ /* MDIO read -- may sleep, done outside the spinlock. */
|
|
+ if (mxl862xx_read_rmon(ds, port, &cnt))
|
|
+ return;
|
|
+
|
|
+ rx_pkts = le32_to_cpu(cnt.rx_good_pkts);
|
|
+ tx_pkts = le32_to_cpu(cnt.tx_good_pkts);
|
|
+ rx_bytes = le64_to_cpu(cnt.rx_good_bytes);
|
|
+ tx_bytes = le64_to_cpu(cnt.tx_good_bytes);
|
|
+ rx_fcserr = le32_to_cpu(cnt.rx_fcserror_pkts);
|
|
+ rx_under = le32_to_cpu(cnt.rx_under_size_error_pkts);
|
|
+ rx_over = le32_to_cpu(cnt.rx_oversize_error_pkts);
|
|
+ rx_align = le32_to_cpu(cnt.rx_align_error_pkts);
|
|
+ tx_drop = le32_to_cpu(cnt.tx_dropped_pkts);
|
|
+ rx_drop = le32_to_cpu(cnt.rx_dropped_pkts);
|
|
+ rx_evlan = le32_to_cpu(cnt.rx_extended_vlan_discard_pkts);
|
|
+ mtu_exc = le32_to_cpu(cnt.mtu_exceed_discard_pkts);
|
|
+ tx_acm = le32_to_cpu(cnt.tx_acm_dropped_pkts);
|
|
+ rx_mcast = le32_to_cpu(cnt.rx_multicast_pkts);
|
|
+ tx_coll = le32_to_cpu(cnt.tx_coll_count);
|
|
+
|
|
+ /* Accumulate deltas under spinlock -- .get_stats64 reads these. */
|
|
+ spin_lock_bh(&priv->ports[port].stats_lock);
|
|
+
|
|
+ s->rx_packets += mxl862xx_delta32(rx_pkts, s->prev_rx_good_pkts);
|
|
+ s->tx_packets += mxl862xx_delta32(tx_pkts, s->prev_tx_good_pkts);
|
|
+ s->rx_bytes += rx_bytes - s->prev_rx_good_bytes;
|
|
+ s->tx_bytes += tx_bytes - s->prev_tx_good_bytes;
|
|
+
|
|
+ s->rx_errors +=
|
|
+ mxl862xx_delta32(rx_fcserr, s->prev_rx_fcserror_pkts) +
|
|
+ mxl862xx_delta32(rx_under, s->prev_rx_under_size_error_pkts) +
|
|
+ mxl862xx_delta32(rx_over, s->prev_rx_oversize_error_pkts) +
|
|
+ mxl862xx_delta32(rx_align, s->prev_rx_align_error_pkts);
|
|
+ s->tx_errors +=
|
|
+ mxl862xx_delta32(tx_drop, s->prev_tx_dropped_pkts);
|
|
+
|
|
+ s->rx_dropped +=
|
|
+ mxl862xx_delta32(rx_drop, s->prev_rx_dropped_pkts) +
|
|
+ mxl862xx_delta32(rx_evlan, s->prev_rx_evlan_discard_pkts) +
|
|
+ mxl862xx_delta32(mtu_exc, s->prev_mtu_exceed_discard_pkts);
|
|
+ s->tx_dropped +=
|
|
+ mxl862xx_delta32(tx_drop, s->prev_tx_dropped_pkts) +
|
|
+ mxl862xx_delta32(tx_acm, s->prev_tx_acm_dropped_pkts);
|
|
+
|
|
+ s->multicast += mxl862xx_delta32(rx_mcast, s->prev_rx_multicast_pkts);
|
|
+ s->collisions += mxl862xx_delta32(tx_coll, s->prev_tx_coll_count);
|
|
+
|
|
+ s->rx_length_errors +=
|
|
+ mxl862xx_delta32(rx_under, s->prev_rx_under_size_error_pkts) +
|
|
+ mxl862xx_delta32(rx_over, s->prev_rx_oversize_error_pkts);
|
|
+ s->rx_crc_errors +=
|
|
+ mxl862xx_delta32(rx_fcserr, s->prev_rx_fcserror_pkts);
|
|
+ s->rx_frame_errors +=
|
|
+ mxl862xx_delta32(rx_align, s->prev_rx_align_error_pkts);
|
|
+
|
|
+ s->prev_rx_good_pkts = rx_pkts;
|
|
+ s->prev_tx_good_pkts = tx_pkts;
|
|
+ s->prev_rx_good_bytes = rx_bytes;
|
|
+ s->prev_tx_good_bytes = tx_bytes;
|
|
+ s->prev_rx_fcserror_pkts = rx_fcserr;
|
|
+ s->prev_rx_under_size_error_pkts = rx_under;
|
|
+ s->prev_rx_oversize_error_pkts = rx_over;
|
|
+ s->prev_rx_align_error_pkts = rx_align;
|
|
+ s->prev_tx_dropped_pkts = tx_drop;
|
|
+ s->prev_rx_dropped_pkts = rx_drop;
|
|
+ s->prev_rx_evlan_discard_pkts = rx_evlan;
|
|
+ s->prev_mtu_exceed_discard_pkts = mtu_exc;
|
|
+ s->prev_tx_acm_dropped_pkts = tx_acm;
|
|
+ s->prev_rx_multicast_pkts = rx_mcast;
|
|
+ s->prev_tx_coll_count = tx_coll;
|
|
+
|
|
+ spin_unlock_bh(&priv->ports[port].stats_lock);
|
|
+}
|
|
+
|
|
+static void mxl862xx_stats_work_fn(struct work_struct *work)
|
|
+{
|
|
+ struct mxl862xx_priv *priv =
|
|
+ container_of(work, struct mxl862xx_priv, stats_work.work);
|
|
+ struct dsa_switch *ds = priv->ds;
|
|
+ struct dsa_port *dp;
|
|
+
|
|
+ dsa_switch_for_each_available_port(dp, ds)
|
|
+ mxl862xx_stats_poll(ds, dp->index);
|
|
+
|
|
+ if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags))
|
|
+ schedule_delayed_work(&priv->stats_work,
|
|
+ MXL862XX_STATS_POLL_INTERVAL);
|
|
+}
|
|
+
|
|
+static void mxl862xx_get_stats64(struct dsa_switch *ds, int port,
|
|
+ struct rtnl_link_stats64 *s)
|
|
+{
|
|
+ struct mxl862xx_priv *priv = ds->priv;
|
|
+ struct mxl862xx_port_stats *ps = &priv->ports[port].stats;
|
|
+
|
|
+ spin_lock_bh(&priv->ports[port].stats_lock);
|
|
+
|
|
+ s->rx_packets = ps->rx_packets;
|
|
+ s->tx_packets = ps->tx_packets;
|
|
+ s->rx_bytes = ps->rx_bytes;
|
|
+ s->tx_bytes = ps->tx_bytes;
|
|
+ s->rx_errors = ps->rx_errors;
|
|
+ s->tx_errors = ps->tx_errors;
|
|
+ s->rx_dropped = ps->rx_dropped;
|
|
+ s->tx_dropped = ps->tx_dropped;
|
|
+ s->multicast = ps->multicast;
|
|
+ s->collisions = ps->collisions;
|
|
+ s->rx_length_errors = ps->rx_length_errors;
|
|
+ s->rx_crc_errors = ps->rx_crc_errors;
|
|
+ s->rx_frame_errors = ps->rx_frame_errors;
|
|
+
|
|
+ spin_unlock_bh(&priv->ports[port].stats_lock);
|
|
+
|
|
+ /* Trigger a fresh poll so the next read sees up-to-date counters.
|
|
+ * No-op if the work is already pending, running, or teardown started.
|
|
+ */
|
|
+ if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags))
|
|
+ schedule_delayed_work(&priv->stats_work, 0);
|
|
+}
|
|
+
|
|
static const struct dsa_switch_ops mxl862xx_switch_ops = {
|
|
.get_tag_protocol = mxl862xx_get_tag_protocol,
|
|
.setup = mxl862xx_setup,
|
|
@@ -1931,6 +2093,7 @@ static const struct dsa_switch_ops mxl86
|
|
.get_eth_ctrl_stats = mxl862xx_get_eth_ctrl_stats,
|
|
.get_pause_stats = mxl862xx_get_pause_stats,
|
|
.get_rmon_stats = mxl862xx_get_rmon_stats,
|
|
+ .get_stats64 = mxl862xx_get_stats64,
|
|
};
|
|
|
|
static void mxl862xx_phylink_mac_config(struct phylink_config *config,
|
|
@@ -1992,16 +2155,22 @@ static int mxl862xx_probe(struct mdio_de
|
|
priv->ports[i].priv = priv;
|
|
INIT_WORK(&priv->ports[i].host_flood_work,
|
|
mxl862xx_host_flood_work_fn);
|
|
+ spin_lock_init(&priv->ports[i].stats_lock);
|
|
}
|
|
|
|
+ INIT_DELAYED_WORK(&priv->stats_work, mxl862xx_stats_work_fn);
|
|
+
|
|
dev_set_drvdata(dev, ds);
|
|
|
|
err = dsa_register_switch(ds);
|
|
if (err) {
|
|
+ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
|
+ cancel_delayed_work_sync(&priv->stats_work);
|
|
mxl862xx_host_shutdown(priv);
|
|
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
|
|
cancel_work_sync(&priv->ports[i].host_flood_work);
|
|
}
|
|
+
|
|
return err;
|
|
}
|
|
|
|
@@ -2016,6 +2185,9 @@ static void mxl862xx_remove(struct mdio_
|
|
|
|
priv = ds->priv;
|
|
|
|
+ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
|
+ cancel_delayed_work_sync(&priv->stats_work);
|
|
+
|
|
dsa_unregister_switch(ds);
|
|
|
|
mxl862xx_host_shutdown(priv);
|
|
@@ -2042,6 +2214,9 @@ static void mxl862xx_shutdown(struct mdi
|
|
|
|
dsa_switch_shutdown(ds);
|
|
|
|
+ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
|
+ cancel_delayed_work_sync(&priv->stats_work);
|
|
+
|
|
mxl862xx_host_shutdown(priv);
|
|
|
|
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
|
@@ -117,6 +117,79 @@ struct mxl862xx_evlan_block {
|
|
};
|
|
|
|
/**
|
|
+ * struct mxl862xx_port_stats - 64-bit accumulated hardware port statistics
|
|
+ * @rx_packets: total received packets
|
|
+ * @tx_packets: total transmitted packets
|
|
+ * @rx_bytes: total received bytes
|
|
+ * @tx_bytes: total transmitted bytes
|
|
+ * @rx_errors: total receive errors
|
|
+ * @tx_errors: total transmit errors
|
|
+ * @rx_dropped: total received packets dropped
|
|
+ * @tx_dropped: total transmitted packets dropped
|
|
+ * @multicast: total received multicast packets
|
|
+ * @collisions: total transmit collisions
|
|
+ * @rx_length_errors: received length errors (undersize + oversize)
|
|
+ * @rx_crc_errors: received FCS errors
|
|
+ * @rx_frame_errors: received alignment errors
|
|
+ * @prev_rx_good_pkts: previous snapshot of rx good packet counter
|
|
+ * @prev_tx_good_pkts: previous snapshot of tx good packet counter
|
|
+ * @prev_rx_good_bytes: previous snapshot of rx good byte counter
|
|
+ * @prev_tx_good_bytes: previous snapshot of tx good byte counter
|
|
+ * @prev_rx_fcserror_pkts: previous snapshot of rx FCS error counter
|
|
+ * @prev_rx_under_size_error_pkts: previous snapshot of rx undersize
|
|
+ * error counter
|
|
+ * @prev_rx_oversize_error_pkts: previous snapshot of rx oversize
|
|
+ * error counter
|
|
+ * @prev_rx_align_error_pkts: previous snapshot of rx alignment
|
|
+ * error counter
|
|
+ * @prev_tx_dropped_pkts: previous snapshot of tx dropped counter
|
|
+ * @prev_rx_dropped_pkts: previous snapshot of rx dropped counter
|
|
+ * @prev_rx_evlan_discard_pkts: previous snapshot of extended VLAN
|
|
+ * discard counter
|
|
+ * @prev_mtu_exceed_discard_pkts: previous snapshot of MTU exceed
|
|
+ * discard counter
|
|
+ * @prev_tx_acm_dropped_pkts: previous snapshot of tx ACM dropped
|
|
+ * counter
|
|
+ * @prev_rx_multicast_pkts: previous snapshot of rx multicast counter
|
|
+ * @prev_tx_coll_count: previous snapshot of tx collision counter
|
|
+ *
|
|
+ * The firmware RMON counters are 32-bit free-running (64-bit for byte
|
|
+ * counters). This structure holds 64-bit accumulators alongside the
|
|
+ * previous raw snapshot so that deltas can be computed across polls,
|
|
+ * handling 32-bit wrap correctly via unsigned subtraction.
|
|
+ */
|
|
+struct mxl862xx_port_stats {
|
|
+ u64 rx_packets;
|
|
+ u64 tx_packets;
|
|
+ u64 rx_bytes;
|
|
+ u64 tx_bytes;
|
|
+ u64 rx_errors;
|
|
+ u64 tx_errors;
|
|
+ u64 rx_dropped;
|
|
+ u64 tx_dropped;
|
|
+ u64 multicast;
|
|
+ u64 collisions;
|
|
+ u64 rx_length_errors;
|
|
+ u64 rx_crc_errors;
|
|
+ u64 rx_frame_errors;
|
|
+ u32 prev_rx_good_pkts;
|
|
+ u32 prev_tx_good_pkts;
|
|
+ u64 prev_rx_good_bytes;
|
|
+ u64 prev_tx_good_bytes;
|
|
+ u32 prev_rx_fcserror_pkts;
|
|
+ u32 prev_rx_under_size_error_pkts;
|
|
+ u32 prev_rx_oversize_error_pkts;
|
|
+ u32 prev_rx_align_error_pkts;
|
|
+ u32 prev_tx_dropped_pkts;
|
|
+ u32 prev_rx_dropped_pkts;
|
|
+ u32 prev_rx_evlan_discard_pkts;
|
|
+ u32 prev_mtu_exceed_discard_pkts;
|
|
+ u32 prev_tx_acm_dropped_pkts;
|
|
+ u32 prev_rx_multicast_pkts;
|
|
+ u32 prev_tx_coll_count;
|
|
+};
|
|
+
|
|
+/**
|
|
* struct mxl862xx_port - per-port state tracked by the driver
|
|
* @priv: back-pointer to switch private data; needed by
|
|
* deferred work handlers to access ds and priv
|
|
@@ -145,6 +218,10 @@ struct mxl862xx_evlan_block {
|
|
* The worker acquires rtnl_lock() to serialize with
|
|
* DSA callbacks and checks @setup_done to avoid
|
|
* acting on torn-down ports.
|
|
+ * @stats: 64-bit accumulated hardware statistics; updated
|
|
+ * periodically by the stats polling work
|
|
+ * @stats_lock: protects accumulator reads in .get_stats64 against
|
|
+ * concurrent updates from the polling work
|
|
*/
|
|
struct mxl862xx_port {
|
|
struct mxl862xx_priv *priv;
|
|
@@ -160,16 +237,24 @@ struct mxl862xx_port {
|
|
bool host_flood_uc;
|
|
bool host_flood_mc;
|
|
struct work_struct host_flood_work;
|
|
+ struct mxl862xx_port_stats stats;
|
|
+ spinlock_t stats_lock; /* protects stats accumulators */
|
|
};
|
|
|
|
+/* Bit indices for struct mxl862xx_priv::flags */
|
|
+#define MXL862XX_FLAG_CRC_ERR 0
|
|
+#define MXL862XX_FLAG_WORK_STOPPED 1
|
|
+
|
|
/**
|
|
* struct mxl862xx_priv - driver private data for an MxL862xx switch
|
|
* @ds: pointer to the DSA switch instance
|
|
* @mdiodev: MDIO device used to communicate with the switch firmware
|
|
* @crc_err_work: deferred work for shutting down all ports on MDIO CRC
|
|
* errors
|
|
- * @crc_err: set atomically before CRC-triggered shutdown, cleared
|
|
- * after
|
|
+ * @flags: atomic status flags; %MXL862XX_FLAG_CRC_ERR is set
|
|
+ * before CRC-triggered shutdown and cleared after;
|
|
+ * %MXL862XX_FLAG_WORK_STOPPED is set before cancelling
|
|
+ * stats_work to prevent rescheduling during teardown
|
|
* @drop_meter: index of the single shared zero-rate firmware meter
|
|
* used to unconditionally drop traffic (used to block
|
|
* flooding)
|
|
@@ -181,18 +266,21 @@ struct mxl862xx_port {
|
|
* @evlan_ingress_size: per-port ingress Extended VLAN block size
|
|
* @evlan_egress_size: per-port egress Extended VLAN block size
|
|
* @vf_block_size: per-port VLAN Filter block size
|
|
+ * @stats_work: periodic work item that polls RMON hardware counters
|
|
+ * and accumulates them into 64-bit per-port stats
|
|
*/
|
|
struct mxl862xx_priv {
|
|
struct dsa_switch *ds;
|
|
struct mdio_device *mdiodev;
|
|
struct work_struct crc_err_work;
|
|
- unsigned long crc_err;
|
|
+ unsigned long flags;
|
|
u16 drop_meter;
|
|
struct mxl862xx_port ports[MXL862XX_MAX_PORTS];
|
|
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
|
|
u16 evlan_ingress_size;
|
|
u16 evlan_egress_size;
|
|
u16 vf_block_size;
|
|
+ struct delayed_work stats_work;
|
|
};
|
|
|
|
#endif /* __MXL862XX_H */
|