/*      $NetBSD: igc_hw.h,v 1.2 2023/10/04 07:35:27 rin Exp $   */
/*      $OpenBSD: igc_hw.h,v 1.2 2022/05/11 06:14:15 kevlo Exp $        */
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/

#ifndef _IGC_HW_H_
#define _IGC_HW_H_

#ifdef _KERNEL_OPT
#include "vlan.h"
#endif

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/socket.h>
#include <sys/device.h>
#include <sys/endian.h>

#include <net/bpf.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_ether.h>

#include <netinet/in.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>

#include <dev/pci/igc/igc_base.h>
#include <dev/pci/igc/igc_defines.h>
#include <dev/pci/igc/igc_i225.h>
#include <dev/pci/igc/igc_mac.h>
#include <dev/pci/igc/igc_nvm.h>
#include <dev/pci/igc/igc_phy.h>
#include <dev/pci/igc/igc_regs.h>

struct igc_hw;

#define IGC_FUNC_1      1

#define IGC_ALT_MAC_ADDRESS_OFFSET_LAN0 0
#define IGC_ALT_MAC_ADDRESS_OFFSET_LAN1 3

#define IGC_MAX_NQUEUES 4

enum igc_mac_type {
       igc_undefined = 0,
       igc_i225,
       igc_num_macs    /* List is 1-based, so subtract 1 for TRUE count. */
};

enum igc_media_type {
       igc_media_type_unknown = 0,
       igc_media_type_copper = 1,
       igc_num_media_types
};

enum igc_nvm_type {
       igc_nvm_unknown = 0,
       igc_nvm_eeprom_spi,
       igc_nvm_flash_hw,
       igc_nvm_invm
};

enum igc_phy_type {
       igc_phy_unknown = 0,
       igc_phy_none,
       igc_phy_i225
};

enum igc_bus_type {
       igc_bus_type_unknown = 0,
       igc_bus_type_pci,
       igc_bus_type_pcix,
       igc_bus_type_pci_express,
       igc_bus_type_reserved
};

enum igc_bus_speed {
       igc_bus_speed_unknown = 0,
       igc_bus_speed_33,
       igc_bus_speed_66,
       igc_bus_speed_100,
       igc_bus_speed_120,
       igc_bus_speed_133,
       igc_bus_speed_2500,
       igc_bus_speed_5000,
       igc_bus_speed_reserved
};

enum igc_bus_width {
       igc_bus_width_unknown = 0,
       igc_bus_width_pcie_x1,
       igc_bus_width_pcie_x2,
       igc_bus_width_pcie_x4 = 4,
       igc_bus_width_pcie_x8 = 8,
       igc_bus_width_32,
       igc_bus_width_64,
       igc_bus_width_reserved
};

enum igc_fc_mode {
       igc_fc_none = 0,
       igc_fc_rx_pause,
       igc_fc_tx_pause,
       igc_fc_full,
       igc_fc_default = 0xFF
};

enum igc_ms_type {
       igc_ms_hw_default = 0,
       igc_ms_force_master,
       igc_ms_force_slave,
       igc_ms_auto
};

enum igc_smart_speed {
       igc_smart_speed_default = 0,
       igc_smart_speed_on,
       igc_smart_speed_off
};

/* Receive Descriptor */
struct igc_rx_desc {
       uint64_t buffer_addr;   /* Address of the descriptor's data buffer */
       uint16_t length;        /* Length of data DMAed into data buffer */
       uint16_t csum;          /* Packet checksum */
       uint8_t  status;        /* Descriptor status */
       uint8_t  errors;        /* Descriptor errors */
       uint16_t special;
};

/* Receive Descriptor - Extended */
union igc_rx_desc_extended {
       struct {
               uint64_t buffer_addr;
               uint64_t reserved;
       } read;
       struct {
               struct {
                       uint32_t mrq;   /* Multiple Rx queues */
                       union {
                               uint32_t rss;   /* RSS hash */
                               struct {
                                       uint16_t ip_id; /* IP id */
                                       uint16_t csum;  /* Packet checksum */
                               } csum_ip;
                       } hi_dword;
               } lower;
               struct {
                       uint32_t status_error;  /* ext status/error */
                       uint16_t length;
                       uint16_t vlan;  /* VLAN tag */
               } upper;
       } wb;   /* writeback */
};

/* Transmit Descriptor */
struct igc_tx_desc {
       uint64_t buffer_addr;   /* Address of the descriptor's data buffer */
       union {
               uint32_t data;
               struct {
                       uint16_t length;        /* Data buffer length */
                       uint8_t cso;    /* Checksum offset */
                       uint8_t cmd;    /* Descriptor control */
               } flags;
       } lower;
       union {
               uint32_t data;
               struct {
                       uint8_t status; /* Descriptor status */
                       uint8_t css;    /* Checksum start */
                       uint16_t special;
               } fields;
       } upper;
};

/* Function pointers for the MAC. */
struct igc_mac_operations {
       int     (*init_params)(struct igc_hw *);
       int     (*check_for_link)(struct igc_hw *);
       void    (*clear_hw_cntrs)(struct igc_hw *);
       void    (*clear_vfta)(struct igc_hw *);
       int     (*get_bus_info)(struct igc_hw *);
       void    (*set_lan_id)(struct igc_hw *);
       int     (*get_link_up_info)(struct igc_hw *, uint16_t *, uint16_t *);
       void    (*update_mc_addr_list)(struct igc_hw *, uint8_t *, uint32_t);
       int     (*reset_hw)(struct igc_hw *);
       int     (*init_hw)(struct igc_hw *);
       int     (*setup_link)(struct igc_hw *);
       int     (*setup_physical_interface)(struct igc_hw *);
       void    (*write_vfta)(struct igc_hw *, uint32_t, uint32_t);
       void    (*config_collision_dist)(struct igc_hw *);
       int     (*rar_set)(struct igc_hw *, uint8_t *, uint32_t);
       int     (*read_mac_addr)(struct igc_hw *);
       int     (*validate_mdi_setting)(struct igc_hw *);
       int     (*acquire_swfw_sync)(struct igc_hw *, uint16_t);
       void    (*release_swfw_sync)(struct igc_hw *, uint16_t);
};

/* When to use various PHY register access functions:
*
*                 Func   Caller
*   Function      Does   Does    When to use
*   ~~~~~~~~~~~~  ~~~~~  ~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*   X_reg         L,P,A  n/a     for simple PHY reg accesses
*   X_reg_locked  P,A    L       for multiple accesses of different regs
*                                on different pages
*   X_reg_page    A      L,P     for multiple accesses of different regs
*                                on the same page
*
* Where X=[read|write], L=locking, P=sets page, A=register access
*
*/
struct igc_phy_operations {
       int     (*init_params)(struct igc_hw *);
       int     (*acquire)(struct igc_hw *);
       int     (*check_reset_block)(struct igc_hw *);
       int     (*force_speed_duplex)(struct igc_hw *);
       int     (*get_info)(struct igc_hw *);
       int     (*set_page)(struct igc_hw *, uint16_t);
       int     (*read_reg)(struct igc_hw *, uint32_t, uint16_t *);
       int     (*read_reg_locked)(struct igc_hw *, uint32_t, uint16_t *);
       int     (*read_reg_page)(struct igc_hw *, uint32_t, uint16_t *);
       void    (*release)(struct igc_hw *);
       int     (*reset)(struct igc_hw *);
       int     (*set_d0_lplu_state)(struct igc_hw *, bool);
       int     (*set_d3_lplu_state)(struct igc_hw *, bool);
       int     (*write_reg)(struct igc_hw *, uint32_t, uint16_t);
       int     (*write_reg_locked)(struct igc_hw *, uint32_t, uint16_t);
       int     (*write_reg_page)(struct igc_hw *, uint32_t, uint16_t);
       void    (*power_up)(struct igc_hw *);
       void    (*power_down)(struct igc_hw *);
};

/* Function pointers for the NVM. */
struct igc_nvm_operations {
       int     (*init_params)(struct igc_hw *);
       int     (*acquire)(struct igc_hw *);
       int     (*read)(struct igc_hw *, uint16_t, uint16_t, uint16_t *);
       void    (*release)(struct igc_hw *);
       void    (*reload)(struct igc_hw *);
       int     (*update)(struct igc_hw *);
       int     (*validate)(struct igc_hw *);
       int     (*write)(struct igc_hw *, uint16_t, uint16_t, uint16_t *);
};

struct igc_info {
       int                             (*get_invariants)(struct igc_hw *hw);
       struct igc_mac_operations       *mac_ops;
       const struct igc_phy_operations *phy_ops;
       struct igc_nvm_operations       *nvm_ops;
};

extern const struct igc_info igc_i225_info;

struct igc_mac_info {
       struct igc_mac_operations       ops;
       uint8_t                         addr[ETHER_ADDR_LEN];
       uint8_t                         perm_addr[ETHER_ADDR_LEN];

       enum igc_mac_type               type;

       uint32_t                        mc_filter_type;

       uint16_t                        current_ifs_val;
       uint16_t                        ifs_max_val;
       uint16_t                        ifs_min_val;
       uint16_t                        ifs_ratio;
       uint16_t                        ifs_step_size;
       uint16_t                        mta_reg_count;
       uint16_t                        uta_reg_count;

       /* Maximum size of the MTA register table in all supported adapters */
#define MAX_MTA_REG     128
       uint32_t                        mta_shadow[MAX_MTA_REG];
       uint16_t                        rar_entry_count;

       uint8_t                         forced_speed_duplex;

       bool                            asf_firmware_present;
       bool                            autoneg;
       bool                            get_link_status;
       uint32_t                        max_frame_size;
};

struct igc_phy_info {
       struct igc_phy_operations       ops;
       enum igc_phy_type               type;

       enum igc_smart_speed            smart_speed;

       uint32_t                        addr;
       uint32_t                        id;
       uint32_t                        reset_delay_us; /* in usec */
       uint32_t                        revision;

       enum igc_media_type             media_type;

       uint16_t                        autoneg_advertised;
       uint16_t                        autoneg_mask;

       uint8_t                         mdix;

       bool                            polarity_correction;
       bool                            speed_downgraded;
       bool                            autoneg_wait_to_complete;
};

struct igc_nvm_info {
       struct igc_nvm_operations       ops;
       enum igc_nvm_type               type;

       uint16_t                        word_size;
       uint16_t                        delay_usec;
       uint16_t                        address_bits;
       uint16_t                        opcode_bits;
       uint16_t                        page_size;
};

struct igc_bus_info {
       enum igc_bus_type       type;
       enum igc_bus_speed      speed;
       enum igc_bus_width      width;

       uint16_t                func;
       uint16_t                pci_cmd_word;
};

struct igc_fc_info {
       uint32_t        high_water;
       uint32_t        low_water;
       uint16_t        pause_time;
       uint16_t        refresh_time;
       bool            send_xon;
       bool            strict_ieee;
       enum            igc_fc_mode current_mode;
       enum            igc_fc_mode requested_mode;
};

struct igc_dev_spec_i225 {
       bool            eee_disable;
       bool            clear_semaphore_once;
       uint32_t        mtu;
};

struct igc_hw {
       void                    *back;

       bus_addr_t              hw_addr;

       struct igc_mac_info     mac;
       struct igc_fc_info      fc;
       struct igc_phy_info     phy;
       struct igc_nvm_info     nvm;
       struct igc_bus_info     bus;

       union {
               struct igc_dev_spec_i225 _i225;
       } dev_spec;

       uint16_t                device_id;
};

#endif  /* _IGC_HW_H_ */