344 lines
13 KiB
C
344 lines
13 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#ifndef __MXL862XX_H
|
|
#define __MXL862XX_H
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <linux/mdio.h>
|
|
#include <linux/workqueue.h>
|
|
#include <net/dsa.h>
|
|
|
|
struct mxl862xx_priv;
|
|
|
|
#define MXL862XX_MAX_PORTS 17
|
|
#define MXL862XX_FIRST_SERDES_PORT 9
|
|
#define MXL862XX_SERDES_SLOTS 4
|
|
|
|
#define MXL862XX_DEFAULT_BRIDGE 0
|
|
#define MXL862XX_MAX_BRIDGES 48
|
|
#define MXL862XX_MAX_BRIDGE_PORTS 128
|
|
#define MXL862XX_TOTAL_EVLAN_ENTRIES 1024
|
|
#define MXL862XX_TOTAL_VF_ENTRIES 1024
|
|
|
|
/* Number of __le16 words in a firmware portmap (128-bit bitmap). */
|
|
#define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16)
|
|
|
|
/**
|
|
* mxl862xx_fw_portmap_set_bit - set a single port bit in a firmware portmap
|
|
* @map: firmware portmap array (MXL862XX_FW_PORTMAP_WORDS entries)
|
|
* @port: port index (0..MXL862XX_MAX_BRIDGE_PORTS-1)
|
|
*/
|
|
static inline void mxl862xx_fw_portmap_set_bit(__le16 *map, int port)
|
|
{
|
|
map[port / 16] |= cpu_to_le16(BIT(port % 16));
|
|
}
|
|
|
|
/**
|
|
* mxl862xx_fw_portmap_clear_bit - clear a single port bit in a firmware portmap
|
|
* @map: firmware portmap array (MXL862XX_FW_PORTMAP_WORDS entries)
|
|
* @port: port index (0..MXL862XX_MAX_BRIDGE_PORTS-1)
|
|
*/
|
|
static inline void mxl862xx_fw_portmap_clear_bit(__le16 *map, int port)
|
|
{
|
|
map[port / 16] &= ~cpu_to_le16(BIT(port % 16));
|
|
}
|
|
|
|
/**
|
|
* mxl862xx_fw_portmap_is_empty - check whether a firmware portmap has no
|
|
* bits set
|
|
* @map: firmware portmap array (MXL862XX_FW_PORTMAP_WORDS entries)
|
|
*
|
|
* Return: true if every word in @map is zero.
|
|
*/
|
|
static inline bool mxl862xx_fw_portmap_is_empty(const __le16 *map)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MXL862XX_FW_PORTMAP_WORDS; i++)
|
|
if (map[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* struct mxl862xx_vf_vid - Per-VID entry within a VLAN Filter block
|
|
* @list: Linked into &mxl862xx_vf_block.vids
|
|
* @vid: VLAN ID
|
|
* @index: Entry index within the VLAN Filter HW block
|
|
* @untagged: Strip tag on egress for this VID (drives EVLAN tag-stripping)
|
|
*/
|
|
struct mxl862xx_vf_vid {
|
|
struct list_head list;
|
|
u16 vid;
|
|
u16 index;
|
|
bool untagged;
|
|
};
|
|
|
|
/**
|
|
* struct mxl862xx_vf_block - Per-port VLAN Filter block
|
|
* @allocated: Whether the HW block has been allocated via VLANFILTER_ALLOC
|
|
* @block_id: HW VLAN Filter block ID from VLANFILTER_ALLOC
|
|
* @block_size: Total entries allocated in this block
|
|
* @active_count: Number of ALLOW entries at indices [0, active_count).
|
|
* The bridge port config sends max(active_count, 1) as
|
|
* block_size to narrow the HW scan window.
|
|
* discard_unmatched_tagged handles frames outside this range.
|
|
* @vids: List of &mxl862xx_vf_vid entries programmed in this block
|
|
*/
|
|
struct mxl862xx_vf_block {
|
|
bool allocated;
|
|
u16 block_id;
|
|
u16 block_size;
|
|
u16 active_count;
|
|
struct list_head vids;
|
|
};
|
|
|
|
/**
|
|
* struct mxl862xx_evlan_block - Per-port per-direction extended VLAN block
|
|
* @allocated: Whether the HW block has been allocated via EXTENDEDVLAN_ALLOC.
|
|
* Guards alloc/free idempotency--the block_id is only valid
|
|
* while allocated is true.
|
|
* @in_use: Whether the EVLAN engine should be enabled for this block
|
|
* on the bridge port (sent as the enable flag in
|
|
* set_bridge_port). Can be false while allocated is still
|
|
* true -- e.g. when all egress VIDs are removed (idx == 0 in
|
|
* evlan_program_egress) the block stays allocated for
|
|
* potential reuse, but the engine is disabled so an empty
|
|
* rule set does not discard all traffic.
|
|
* @block_id: HW block ID from EXTENDEDVLAN_ALLOC
|
|
* @block_size: Total entries allocated
|
|
* @n_active: Number of HW entries currently written. The bridge port
|
|
* config sends this as the egress scan window, so entries
|
|
* beyond n_active are never scanned. Always equals
|
|
* block_size for ingress blocks (fixed catchall rules).
|
|
*/
|
|
struct mxl862xx_evlan_block {
|
|
bool allocated;
|
|
bool in_use;
|
|
u16 block_id;
|
|
u16 block_size;
|
|
u16 n_active;
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
* @fid: firmware FID for the permanent single-port bridge;
|
|
* kept alive for the lifetime of the port so traffic is
|
|
* never forwarded while the port is unbridged
|
|
* @flood_block: bitmask of firmware meter indices that are currently
|
|
* rate-limiting flood traffic on this port (zero-rate
|
|
* meters used to block flooding)
|
|
* @learning: true when address learning is enabled on this port
|
|
* @setup_done: set at end of port_setup, cleared at start of
|
|
* port_teardown; guards deferred work against
|
|
* acting on torn-down state
|
|
* @pvid: port VLAN ID (native VLAN) assigned to untagged traffic
|
|
* @vlan_filtering: true when VLAN filtering is enabled on this port
|
|
* @vf: per-port VLAN Filter block state
|
|
* @ingress_evlan: ingress extended VLAN block state
|
|
* @egress_evlan: egress extended VLAN block state
|
|
* @host_flood_uc: desired host unicast flood state (true = flood);
|
|
* updated atomically by port_set_host_flood, consumed
|
|
* by the deferred host_flood_work
|
|
* @host_flood_mc: desired host multicast flood state (true = flood)
|
|
* @host_flood_work: deferred work for applying host flood changes;
|
|
* port_set_host_flood runs in atomic context (under
|
|
* netif_addr_lock) so firmware calls must be deferred.
|
|
* 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;
|
|
u16 fid;
|
|
unsigned long flood_block;
|
|
bool learning;
|
|
bool setup_done;
|
|
u16 pvid;
|
|
bool vlan_filtering;
|
|
struct mxl862xx_vf_block vf;
|
|
struct mxl862xx_evlan_block ingress_evlan;
|
|
struct mxl862xx_evlan_block egress_evlan;
|
|
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 */
|
|
};
|
|
|
|
/**
|
|
* struct mxl862xx_pcs - link SerDes interfaces to bridge ports
|
|
* @pcs: &struct phylink_pcs instance
|
|
* @priv: pointer to &struct mxl862xx_priv
|
|
* @serdes_id: SerDes instance index (0 or 1)
|
|
* @slot: slot within the SerDes (0-3 for QSGMII/QUSXGMII, 0 otherwise)
|
|
* @interface: cached PHY interface, last value passed to pcs_config().
|
|
* %PHY_INTERFACE_MODE_NA before the first successful
|
|
* pcs_config(). Used by pcs_an_restart() to populate the
|
|
* firmware command and by pcs_disable() to skip the
|
|
* firmware power-down for shared (QSGMII/QUSXGMII) modes.
|
|
*/
|
|
struct mxl862xx_pcs {
|
|
struct phylink_pcs pcs;
|
|
struct mxl862xx_priv *priv;
|
|
int serdes_id;
|
|
int slot;
|
|
phy_interface_t interface;
|
|
};
|
|
|
|
/**
|
|
* struct mxl862xx_fw_version - firmware version for comparison and display
|
|
* @major: firmware major version
|
|
* @minor: firmware minor version
|
|
* @revision: firmware revision number
|
|
*/
|
|
struct mxl862xx_fw_version {
|
|
u8 major;
|
|
u8 minor;
|
|
u16 revision;
|
|
};
|
|
|
|
#define MXL862XX_FW_VER(maj, min, rev) \
|
|
(((u32)(maj) << 24) | ((u32)(min) << 16) | (rev))
|
|
#define MXL862XX_FW_VER_MIN(priv, maj, min, rev) \
|
|
(MXL862XX_FW_VER((priv)->fw_version.major, (priv)->fw_version.minor, \
|
|
(priv)->fw_version.revision) >= \
|
|
MXL862XX_FW_VER(maj, min, rev))
|
|
|
|
/* 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
|
|
* @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)
|
|
* @fw_version: cached firmware version, populated at probe and
|
|
* compared with MXL862XX_FW_VER_MIN()
|
|
* @serdes_ports: SerDes interfaces incl. sub-interfaces in case of
|
|
* 10G_QXGMII or QSGMII
|
|
* @serdes_refcount: per-XPCS count of sub-ports enabled by phylink;
|
|
* pcs_disable powers an XPCS down when the count
|
|
* reaches zero. Protected by @serdes_lock.
|
|
* @serdes_lock: serializes the @serdes_refcount transitions with
|
|
* the XPCS power-down so a sibling sub-port enable
|
|
* cannot race a power-down to zero
|
|
* @ports: per-port state, indexed by switch port number
|
|
* @bridges: maps DSA bridge number to firmware bridge ID;
|
|
* zero means no firmware bridge allocated for that
|
|
* DSA bridge number. Indexed by dsa_bridge.num
|
|
* (0 .. ds->max_num_bridges).
|
|
* @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 flags;
|
|
u16 drop_meter;
|
|
struct mxl862xx_fw_version fw_version;
|
|
struct mxl862xx_pcs serdes_ports[8];
|
|
int serdes_refcount[2];
|
|
struct mutex serdes_lock;
|
|
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 */
|