root/sys/dev/al_eth/al_eth.h
/*-
 * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates
 * All rights reserved.
 *
 * Developed by Semihalf.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef __AL_ETH_H__
#define __AL_ETH_H__

#include "al_init_eth_lm.h"
#include "al_hal_eth.h"
#include "al_hal_udma_iofic.h"
#include "al_hal_udma_debug.h"
#include "al_serdes.h"

enum board_t {
        ALPINE_INTEGRATED = 0,
        ALPINE_NIC = 1,
        ALPINE_FPGA_NIC = 2,
};

#define AL_ETH_MAX_HW_QUEUES    4
#define AL_ETH_NUM_QUEUES       4
#define AL_ETH_MAX_MSIX_VEC     (1 + 2 * AL_ETH_MAX_HW_QUEUES)

#define AL_ETH_DEFAULT_TX_SW_DESCS      (512)
#define AL_ETH_DEFAULT_TX_HW_DESCS      (512)
#define AL_ETH_DEFAULT_RX_DESCS         (512)

#if ((AL_ETH_DEFAULT_TX_SW_DESCS / 4) < (AL_ETH_PKT_MAX_BUFS + 2))
#define AL_ETH_TX_WAKEUP_THRESH         (AL_ETH_DEFAULT_TX_SW_DESCS / 4)
#else
#define AL_ETH_TX_WAKEUP_THRESH         (AL_ETH_PKT_MAX_BUFS + 2)
#endif

#define NET_IP_ALIGN                            2
#define AL_ETH_DEFAULT_SMALL_PACKET_LEN         (128 - NET_IP_ALIGN)
#define AL_ETH_HEADER_COPY_SIZE                 (128 - NET_IP_ALIGN)

#define AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE   9216
/*
 * Minimum the buffer size to 600 to avoid situation the mtu will be changed
 * from too little buffer to very big one and then the number of buffer per
 * packet could reach the maximum AL_ETH_PKT_MAX_BUFS
 */
#define AL_ETH_DEFAULT_MIN_RX_BUFF_ALLOC_SIZE   600
#define AL_ETH_DEFAULT_FORCE_1000_BASEX FALSE

#define AL_ETH_DEFAULT_LINK_POLL_INTERVAL       100
#define AL_ETH_FIRST_LINK_POLL_INTERVAL         1

#define AL_ETH_NAME_MAX_LEN     20
#define AL_ETH_IRQNAME_SIZE     40

#define AL_ETH_DEFAULT_MDIO_FREQ_KHZ    2500
#define AL_ETH_MDIO_FREQ_1000_KHZ       1000

struct al_eth_irq {
        driver_filter_t *handler;
        void            *data;
        unsigned int    vector;
        uint8_t         requested;
        char            name[AL_ETH_IRQNAME_SIZE];
        struct resource *res;
        void            *cookie;
};

struct al_eth_tx_buffer {
        struct mbuf *m;
        struct al_eth_pkt hal_pkt;
        bus_dmamap_t    dma_map;
        unsigned int    tx_descs;
};

struct al_eth_rx_buffer {
        struct mbuf     *m;
        unsigned int    data_size;
        bus_dmamap_t    dma_map;
        struct al_buf   al_buf;
};

struct al_eth_ring {
        device_t dev;
        struct al_eth_adapter *adapter;
        /* Used to get rx packets from hal */
        struct al_eth_pkt hal_pkt;
        /* Udma queue handler */
        struct al_udma_q *dma_q;
        uint32_t ring_id;
        uint16_t next_to_use;
        uint16_t next_to_clean;
        /* The offset of the interrupt unmask register */
        uint32_t *unmask_reg_offset;
        /* 
         * The value to write to the above register to
         * unmask the interrupt of this ring
         */
        uint32_t unmask_val;
        struct al_eth_meta_data hal_meta;
        /* Contex of tx packet */
        struct al_eth_tx_buffer *tx_buffer_info;
        /* Contex of rx packet */
        struct al_eth_rx_buffer *rx_buffer_info;
        /* Number of tx/rx_buffer_info's entries */
        int sw_count;
        /* Number of hw descriptors */
        int hw_count;
        /* Size (in bytes) of hw descriptors */
        size_t descs_size;
        /* Size (in bytes) of hw completion descriptors, used for rx */
        size_t cdescs_size;
        struct ifnet *netdev;
        struct al_udma_q_params q_params;
        struct buf_ring *br;
        struct mtx br_mtx;
        struct task enqueue_task;
        struct taskqueue *enqueue_tq;
        volatile uint32_t enqueue_is_running;
        struct task cmpl_task;
        struct taskqueue *cmpl_tq;
        volatile uint32_t cmpl_is_running;
        uint32_t lro_enabled;
        struct lro_ctrl lro;
        bus_dma_tag_t dma_buf_tag;
        volatile uint32_t stall;
};

#define AL_ETH_TX_RING_IDX_NEXT(tx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_TX_SW_DESCS - 1))

#define AL_ETH_RX_RING_IDX_NEXT(rx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_RX_DESCS - 1))
#define AL_ETH_RX_RING_IDX_ADD(rx_ring, idx, n) (((idx) + (n)) & (AL_ETH_DEFAULT_RX_DESCS - 1))

/* flow control configuration */
#define AL_ETH_FLOW_CTRL_RX_FIFO_TH_HIGH        0x160
#define AL_ETH_FLOW_CTRL_RX_FIFO_TH_LOW         0x90
#define AL_ETH_FLOW_CTRL_QUANTA                 0xffff
#define AL_ETH_FLOW_CTRL_QUANTA_TH              0x8000

#define AL_ETH_FLOW_CTRL_AUTONEG        1 
#define AL_ETH_FLOW_CTRL_RX_PAUSE       2
#define AL_ETH_FLOW_CTRL_TX_PAUSE       4

/* link configuration for 1G port */
struct al_eth_link_config {
        int old_link;
        /* Describes what we actually have. */
        int     active_duplex;
        int     active_speed;

        /* current flow control status */
        uint8_t flow_ctrl_active;
        /* supported configuration (can be changed from ethtool) */
        uint8_t flow_ctrl_supported;

        /* the following are not relevant to RGMII */
        bool    force_1000_base_x;
        bool    autoneg;
};

/* SFP detection event */
enum al_eth_sfp_detect_evt {
        /* No change (no connect, disconnect, or new SFP module */
        AL_ETH_SFP_DETECT_EVT_NO_CHANGE,
        /* SFP module connected */
        AL_ETH_SFP_DETECT_EVT_CONNECTED,
        /* SFP module disconnected */
        AL_ETH_SFP_DETECT_EVT_DISCONNECTED,
        /* SFP module replaced */
        AL_ETH_SFP_DETECT_EVT_CHANGED,
};

/* SFP detection status */
struct al_eth_sfp_detect_stat {
        /* Status is valid (i.e. rest of fields are valid) */
        bool                    valid;
        bool                    connected;
        uint8_t                 sfp_10g;
        uint8_t                 sfp_1g;
        uint8_t                 sfp_cable_tech;
        bool                    lt_en;
        bool                    an_en;
        enum al_eth_mac_mode    mac_mode;
};

struct al_eth_retimer_params {
        bool                            exist;
        uint8_t                         bus_id;
        uint8_t                         i2c_addr;
        enum al_eth_retimer_channel     channel;
};

struct msix_entry {
        int entry;
        int vector;
};

/* board specific private data structure */
struct al_eth_adapter {
        enum board_t    board_type;
        device_t        miibus;
        struct mii_data *mii;
        uint16_t dev_id;
        uint8_t rev_id;

        device_t dev;
        struct ifnet *netdev;
        struct ifmedia media;
        struct resource *udma_res;
        struct resource *mac_res;
        struct resource *ec_res;
        int if_flags;
        struct callout wd_callout;
        struct mtx     wd_mtx;
        struct callout stats_callout;
        struct mtx     stats_mtx;

        /* this is for intx mode */
        void *irq_cookie;
        struct resource *irq_res;

        /* 
         * Some features need tri-state capability,
         * thus the additional *_CAPABLE flags.
         */
        uint32_t flags;
#define AL_ETH_FLAG_MSIX_CAPABLE                (uint32_t)(1 << 1)
#define AL_ETH_FLAG_MSIX_ENABLED                (uint32_t)(1 << 2)
#define AL_ETH_FLAG_IN_NETPOLL                  (uint32_t)(1 << 3)
#define AL_ETH_FLAG_MQ_CAPABLE                  (uint32_t)(1 << 4)
#define AL_ETH_FLAG_SRIOV_CAPABLE               (uint32_t)(1 << 5)
#define AL_ETH_FLAG_SRIOV_ENABLED               (uint32_t)(1 << 6)
#define AL_ETH_FLAG_RESET_REQUESTED             (uint32_t)(1 << 7)

        struct al_hal_eth_adapter hal_adapter;

        /*
         * Rx packets that shorter that this len will be copied to the mbuf 
         */
        unsigned int small_copy_len;

        /* Maximum size for rx buffer */
        unsigned int max_rx_buff_alloc_size;
        uint32_t rx_mbuf_sz;

        /* Tx fast path data */
        int num_tx_queues;

        /* Rx fast path data */
        int num_rx_queues;

        /* TX */
        struct al_eth_ring tx_ring[AL_ETH_NUM_QUEUES];

        /* RX */
        struct al_eth_ring rx_ring[AL_ETH_NUM_QUEUES];

        enum al_iofic_mode int_mode;

#define AL_ETH_MGMT_IRQ_IDX             0
#define AL_ETH_RXQ_IRQ_IDX(adapter, q)  (1 + (q))
#define AL_ETH_TXQ_IRQ_IDX(adapter, q)  (1 + (adapter)->num_rx_queues + (q))
        struct al_eth_irq irq_tbl[AL_ETH_MAX_MSIX_VEC];
        struct msix_entry *msix_entries;
        int     msix_vecs;
        int     irq_vecs;

        unsigned int tx_usecs, rx_usecs; /* interrupt coalescing */

        unsigned int tx_ring_count;
        unsigned int tx_descs_count;
        unsigned int rx_ring_count;
        unsigned int rx_descs_count;

        /* RSS */
        uint32_t toeplitz_hash_key[AL_ETH_RX_HASH_KEY_NUM];
#define AL_ETH_RX_RSS_TABLE_SIZE        AL_ETH_RX_THASH_TABLE_SIZE
        uint8_t  rss_ind_tbl[AL_ETH_RX_RSS_TABLE_SIZE];

        uint32_t msg_enable;
        struct al_eth_mac_stats mac_stats;

        enum al_eth_mac_mode    mac_mode;
        bool                    mac_mode_set; /* Relevant only when 'auto_speed' is set */
        uint8_t mac_addr[ETHER_ADDR_LEN];
        /* mdio and phy*/
        bool                    phy_exist;
        struct mii_bus          *mdio_bus;
        struct phy_device       *phydev;
        uint8_t                 phy_addr;
        struct al_eth_link_config       link_config;

        /* HAL layer data */
        int                     id_number;
        char                    name[AL_ETH_NAME_MAX_LEN];
        void                    *internal_pcie_base; /* use for ALPINE_NIC devices */
        void                    *udma_base;
        void                    *ec_base;
        void                    *mac_base;

        struct al_eth_flow_control_params flow_ctrl_params;

        struct al_eth_adapter_params eth_hal_params;

        struct task                     link_status_task;
        uint32_t                        link_poll_interval; /* task interval in mSec */

        bool                            serdes_init;
        struct al_serdes_grp_obj        serdes_obj;
        uint8_t                         serdes_grp;
        uint8_t                         serdes_lane;

        bool                            an_en;  /* run kr auto-negotiation */
        bool                            lt_en;  /* run kr link-training */

        bool                            sfp_detection_needed; /* true if need to run sfp detection */
        bool                            auto_speed; /* true if allowed to change SerDes speed configuration */
        uint8_t                         i2c_adapter_id; /* identifier for the i2c adapter to use to access SFP+ module */
        enum al_eth_ref_clk_freq        ref_clk_freq; /* reference clock frequency */
        unsigned int                    mdio_freq; /* MDIO frequency [Khz] */

        bool up;

        bool                            last_link;
        bool                            last_establish_failed;
        struct al_eth_lm_context        lm_context;
        bool                            use_lm;

        bool                            dont_override_serdes; /* avoid overriding serdes parameters
                                                                   to preset static values */
        struct mtx                      serdes_config_lock;
        struct mtx                      if_rx_lock;

        uint32_t wol;

        struct al_eth_retimer_params    retimer;

        bool                            phy_fixup_needed;

        enum al_eth_lm_max_speed        max_speed;
};

#endif /* !(AL_ETH_H) */