/*	$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_ */
