root/drivers/net/ethernet/marvell/prestera/prestera.h
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved. */

#ifndef _PRESTERA_H_
#define _PRESTERA_H_

#include <linux/notifier.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <linux/phylink.h>
#include <net/devlink.h>
#include <uapi/linux/if_ether.h>

#define PRESTERA_DRV_NAME       "prestera"

#define PRESTERA_DEFAULT_VID    1

struct prestera_fw_rev {
        u16 maj;
        u16 min;
        u16 sub;
};

struct prestera_flood_domain {
        struct prestera_switch *sw;
        struct list_head flood_domain_port_list;
        u32 idx;
};

struct prestera_mdb_entry {
        struct prestera_switch *sw;
        struct prestera_flood_domain *flood_domain;
        unsigned char addr[ETH_ALEN];
        u16 vid;
};

struct prestera_flood_domain_port {
        struct prestera_flood_domain *flood_domain;
        struct net_device *dev;
        struct list_head flood_domain_port_node;
        u16 vid;
};

struct prestera_port_stats {
        u64 good_octets_received;
        u64 bad_octets_received;
        u64 mac_trans_error;
        u64 broadcast_frames_received;
        u64 multicast_frames_received;
        u64 frames_64_octets;
        u64 frames_65_to_127_octets;
        u64 frames_128_to_255_octets;
        u64 frames_256_to_511_octets;
        u64 frames_512_to_1023_octets;
        u64 frames_1024_to_max_octets;
        u64 excessive_collision;
        u64 multicast_frames_sent;
        u64 broadcast_frames_sent;
        u64 fc_sent;
        u64 fc_received;
        u64 buffer_overrun;
        u64 undersize;
        u64 fragments;
        u64 oversize;
        u64 jabber;
        u64 rx_error_frame_received;
        u64 bad_crc;
        u64 collisions;
        u64 late_collision;
        u64 unicast_frames_received;
        u64 unicast_frames_sent;
        u64 sent_multiple;
        u64 sent_deferred;
        u64 good_octets_sent;
};

#define PRESTERA_AP_PORT_MAX   (10)

struct prestera_port_caps {
        u64 supp_link_modes;
        u8 supp_fec;
        u8 type;
        u8 transceiver;
};

struct prestera_lag {
        struct net_device *dev;
        struct list_head members;
        u16 member_count;
        u16 lag_id;
};

struct prestera_flow_block;

struct prestera_port_mac_state {
        bool valid;
        u32 mode;
        u32 speed;
        bool oper;
        u8 duplex;
        u8 fc;
        u8 fec;
};

struct prestera_port_phy_state {
        u64 lmode_bmap;
        struct {
                bool pause;
                bool asym_pause;
        } remote_fc;
        u8 mdix;
};

struct prestera_port_mac_config {
        u32 mode;
        u32 speed;
        bool admin;
        u8 inband;
        u8 duplex;
        u8 fec;
};

struct prestera_port_phy_config {
        u32 mode;
        bool admin;
        u8 mdix;
};

struct prestera_port {
        struct net_device *dev;
        struct prestera_switch *sw;
        struct prestera_flow_block *ingress_flow_block;
        struct prestera_flow_block *egress_flow_block;
        struct devlink_port dl_port;
        struct list_head lag_member;
        struct prestera_lag *lag;
        u32 id;
        u32 hw_id;
        u32 dev_id;
        u16 fp_id;
        u16 pvid;
        bool autoneg;
        u64 adver_link_modes;
        u8 adver_fec;
        struct prestera_port_caps caps;
        struct list_head list;
        struct list_head vlans_list;
        struct {
                struct prestera_port_stats stats;
                struct delayed_work caching_dw;
        } cached_hw_stats;
        struct prestera_port_mac_config cfg_mac;
        struct prestera_port_phy_config cfg_phy;
        struct prestera_port_mac_state state_mac;
        struct prestera_port_phy_state state_phy;

        struct phylink_config phy_config;
        struct phylink *phy_link;
        struct phylink_pcs phylink_pcs;

        /* protects state_mac */
        spinlock_t state_mac_lock;
};

struct prestera_device {
        struct device *dev;
        u8 __iomem *ctl_regs;
        u8 __iomem *pp_regs;
        struct prestera_fw_rev fw_rev;
        void *priv;

        /* called by device driver to handle received packets */
        void (*recv_pkt)(struct prestera_device *dev);

        /* called by device driver to pass event up to the higher layer */
        int (*recv_msg)(struct prestera_device *dev, void *msg, size_t size);

        /* called by higher layer to send request to the firmware */
        int (*send_req)(struct prestera_device *dev, int qid, void *in_msg,
                        size_t in_size, void *out_msg, size_t out_size,
                        unsigned int wait);
};

enum prestera_event_type {
        PRESTERA_EVENT_TYPE_UNSPEC,

        PRESTERA_EVENT_TYPE_PORT,
        PRESTERA_EVENT_TYPE_FDB,
        PRESTERA_EVENT_TYPE_RXTX,

        PRESTERA_EVENT_TYPE_MAX
};

enum prestera_rxtx_event_id {
        PRESTERA_RXTX_EVENT_UNSPEC,
        PRESTERA_RXTX_EVENT_RCV_PKT,
};

enum prestera_port_event_id {
        PRESTERA_PORT_EVENT_UNSPEC,
        PRESTERA_PORT_EVENT_MAC_STATE_CHANGED,
};

struct prestera_port_event {
        u32 port_id;
        union {
                struct {
                        u32 mode;
                        u32 speed;
                        u8 oper;
                        u8 duplex;
                        u8 fc;
                        u8 fec;
                } mac;
                struct {
                        u64 lmode_bmap;
                        struct {
                                bool pause;
                                bool asym_pause;
                        } remote_fc;
                        u8 mdix;
                } phy;
        } data;
};

enum prestera_fdb_entry_type {
        PRESTERA_FDB_ENTRY_TYPE_REG_PORT,
        PRESTERA_FDB_ENTRY_TYPE_LAG,
        PRESTERA_FDB_ENTRY_TYPE_MAX
};

enum prestera_fdb_event_id {
        PRESTERA_FDB_EVENT_UNSPEC,
        PRESTERA_FDB_EVENT_LEARNED,
        PRESTERA_FDB_EVENT_AGED,
};

struct prestera_fdb_event {
        enum prestera_fdb_entry_type type;
        union {
                u32 port_id;
                u16 lag_id;
        } dest;
        u32 vid;
        union {
                u8 mac[ETH_ALEN];
        } data;
};

struct prestera_event {
        u16 id;
        union {
                struct prestera_port_event port_evt;
                struct prestera_fdb_event fdb_evt;
        };
};

enum prestera_if_type {
        /* the interface is of port type (dev,port) */
        PRESTERA_IF_PORT_E = 0,

        /* the interface is of lag type (lag-id) */
        PRESTERA_IF_LAG_E = 1,

        /* the interface is of Vid type (vlan-id) */
        PRESTERA_IF_VID_E = 3,
};

struct prestera_iface {
        enum prestera_if_type type;
        struct {
                u32 hw_dev_num;
                u32 port_num;
        } dev_port;
        u32 hw_dev_num;
        u16 vr_id;
        u16 lag_id;
        u16 vlan_id;
};

struct prestera_switchdev;
struct prestera_span;
struct prestera_rxtx;
struct prestera_trap_data;
struct prestera_acl;

struct prestera_switch {
        struct prestera_device *dev;
        struct prestera_switchdev *swdev;
        struct prestera_rxtx *rxtx;
        struct prestera_acl *acl;
        struct prestera_span *span;
        struct list_head event_handlers;
        struct notifier_block netdev_nb;
        struct prestera_trap_data *trap_data;
        char base_mac[ETH_ALEN];
        struct list_head port_list;
        rwlock_t port_list_lock;
        u32 port_count;
        u32 mtu_min;
        u32 mtu_max;
        u8 id;
        struct device_node *np;
        struct prestera_router *router;
        struct prestera_lag *lags;
        struct prestera_counter *counter;
        u8 lag_member_max;
        u8 lag_max;
        u32 size_tbl_router_nexthop;
};

struct prestera_router {
        struct prestera_switch *sw;
        struct list_head vr_list;
        struct list_head rif_entry_list;
        struct rhashtable nh_neigh_ht;
        struct rhashtable nexthop_group_ht;
        struct rhashtable fib_ht;
        struct rhashtable kern_neigh_cache_ht;
        struct rhashtable kern_fib_cache_ht;
        struct notifier_block inetaddr_nb;
        struct notifier_block inetaddr_valid_nb;
        struct notifier_block fib_nb;
        struct notifier_block netevent_nb;
        u8 *nhgrp_hw_state_cache; /* Bitmap cached hw state of nhs */
        unsigned long nhgrp_hw_cache_kick; /* jiffies */
        struct {
                struct delayed_work dw;
        } neighs_update;
};

struct prestera_rxtx_params {
        bool use_sdma;
        u32 map_addr;
};

#define prestera_dev(sw)                ((sw)->dev->dev)

static inline void prestera_write(const struct prestera_switch *sw,
                                  unsigned int reg, u32 val)
{
        writel(val, sw->dev->pp_regs + reg);
}

static inline u32 prestera_read(const struct prestera_switch *sw,
                                unsigned int reg)
{
        return readl(sw->dev->pp_regs + reg);
}

int prestera_device_register(struct prestera_device *dev);
void prestera_device_unregister(struct prestera_device *dev);

struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,
                                                 u32 dev_id, u32 hw_id);

int prestera_port_autoneg_set(struct prestera_port *port, u64 link_modes);

int prestera_router_init(struct prestera_switch *sw);
void prestera_router_fini(struct prestera_switch *sw);

struct prestera_port *prestera_find_port(struct prestera_switch *sw, u32 id);

struct prestera_switch *prestera_switch_get(struct net_device *dev);

int prestera_port_cfg_mac_read(struct prestera_port *port,
                               struct prestera_port_mac_config *cfg);

int prestera_port_cfg_mac_write(struct prestera_port *port,
                                struct prestera_port_mac_config *cfg);

struct prestera_port *prestera_port_dev_lower_find(struct net_device *dev);

void prestera_queue_work(struct work_struct *work);
void prestera_queue_delayed_work(struct delayed_work *work, unsigned long delay);
void prestera_queue_drain(void);

int prestera_port_learning_set(struct prestera_port *port, bool learn_enable);
int prestera_port_uc_flood_set(struct prestera_port *port, bool flood);
int prestera_port_mc_flood_set(struct prestera_port *port, bool flood);

int prestera_port_br_locked_set(struct prestera_port *port, bool br_locked);

int prestera_port_pvid_set(struct prestera_port *port, u16 vid);

bool prestera_netdev_check(const struct net_device *dev);

int prestera_is_valid_mac_addr(struct prestera_port *port, const u8 *addr);

bool prestera_port_is_lag_member(const struct prestera_port *port);
int prestera_lag_id(struct prestera_switch *sw,
                    struct net_device *lag_dev, u16 *lag_id);

struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id);

u16 prestera_port_lag_id(const struct prestera_port *port);

struct prestera_mdb_entry *
prestera_mdb_entry_create(struct prestera_switch *sw,
                          const unsigned char *addr, u16 vid);
void prestera_mdb_entry_destroy(struct prestera_mdb_entry *mdb_entry);

struct prestera_flood_domain *
prestera_flood_domain_create(struct prestera_switch *sw);
void prestera_flood_domain_destroy(struct prestera_flood_domain *flood_domain);

int
prestera_flood_domain_port_create(struct prestera_flood_domain *flood_domain,
                                  struct net_device *dev,
                                  u16 vid);
void
prestera_flood_domain_port_destroy(struct prestera_flood_domain_port *port);
struct prestera_flood_domain_port *
prestera_flood_domain_port_find(struct prestera_flood_domain *flood_domain,
                                struct net_device *dev, u16 vid);

#endif /* _PRESTERA_H_ */