Signed-off-by: Kenny Cheung <kenny.cheung@elitestek.com> Signed-off-by: Mohamad Noor Alim Hussin <mnalim@efinixinc.com>
460 lines
15 KiB
C
460 lines
15 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2023 Efinix, Inc. All rights reserved.
|
|
*/
|
|
|
|
#ifndef EFINIX_TSE_H
|
|
#define EFINIX_TSE_H
|
|
|
|
#include <linux/netdevice.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/if_vlan.h>
|
|
#include <linux/phylink.h>
|
|
#include <linux/completion.h>
|
|
|
|
#define ETHERNET_HDR_SIZE 14 /* Size of Ethernet header */
|
|
#define ETHERNET_TRL_SIZE 4 /* Size of Ethernet trailer (FCS) */
|
|
#define ETHERNET_MTU 1500 /* Max MTU of an Ethernet frame */
|
|
#define ETHERNET_JUMBO_MTU 9000 /* Max MTU of a jumbo Eth. frame */
|
|
#define ETHERNET_MAX_FRAME_SIZE (ETHERNET_HDR_SIZE + ETHERNET_TRL_SIZE + ETHERNET_MTU)
|
|
|
|
#define EFXTSE_TX_COUNT 0
|
|
#define EFXTSE_TX_USEC 0
|
|
#define EFXTSE_RX_COUNT 0
|
|
#define EFXTSE_RX_USEC 0
|
|
|
|
#define BIT_0 (1U << 0)
|
|
#define BIT_1 (1U << 1)
|
|
#define BIT_2 (1U << 2)
|
|
#define BIT_3 (1U << 3)
|
|
#define BIT_4 (1U << 4)
|
|
#define BIT_5 (1U << 5)
|
|
#define BIT_6 (1U << 6)
|
|
#define BIT_7 (1U << 7)
|
|
#define BIT_8 (1U << 8)
|
|
#define BIT_9 (1U << 9)
|
|
#define BIT_10 (1U << 10)
|
|
#define BIT_11 (1U << 11)
|
|
#define BIT_12 (1U << 12)
|
|
#define BIT_13 (1U << 13)
|
|
#define BIT_14 (1U << 14)
|
|
#define BIT_15 (1U << 15)
|
|
#define BIT_16 (1U << 16)
|
|
#define BIT_17 (1U << 17)
|
|
#define BIT_18 (1U << 18)
|
|
#define BIT_19 (1U << 19)
|
|
#define BIT_20 (1U << 20)
|
|
#define BIT_21 (1U << 21)
|
|
#define BIT_22 (1U << 22)
|
|
#define BIT_23 (1U << 23)
|
|
#define BIT_24 (1U << 24)
|
|
#define BIT_25 (1U << 25)
|
|
#define BIT_26 (1U << 26)
|
|
#define BIT_27 (1U << 27)
|
|
#define BIT_28 (1U << 28)
|
|
#define BIT_29 (1U << 29)
|
|
#define BIT_30 (1U << 30)
|
|
#define BIT_31 (1U << 31)
|
|
|
|
#define ETHERNET_CMD_TX_ENA BIT_0
|
|
#define ETHERNET_CMD_RX_ENA BIT_1
|
|
#define ETHERNET_CMD_XON_GEN BIT_2
|
|
#define ETHERNET_CMD_PROMIS_EN BIT_4
|
|
#define ETHERNET_CMD_CRC_FWD BIT_6
|
|
#define ETHERNET_CMD_PAUSE_IGNORE BIT_8
|
|
#define ETHERNET_CMD_TX_ADDR_INS BIT_9
|
|
#define ETHERNET_CMD_RGMII_LOOP_ENA BIT_15
|
|
#define ETHERNET_CMD_ETH_SPEED BIT_16
|
|
#define ETHERNET_CMD_XOFF_GEN BIT_22
|
|
#define ETHERNET_CMD_CNT_RESET BIT_31
|
|
|
|
//MAC Configuration Registers
|
|
#define TSEMAC_VERSION 0x0000
|
|
#define TSEMAC_COMMAND_CONFIG 0x0008
|
|
#define TSEMAC_MAC_ADDR_LO 0x000C
|
|
#define TSEMAC_MAC_ADDR_HI 0x0010
|
|
#define TSEMAC_FRM_LENGHT 0x0014
|
|
#define TSEMAC_PAUSE_QUANT 0x0018
|
|
#define TSEMAC_TX_IPG_LEN 0x005C
|
|
|
|
// //MDIO Configuration Registers
|
|
// #define TSEMAC_DIVIDER_PRE 0x0100
|
|
// #define TSEMAC_RD_WR_EN 0x0104
|
|
// #define TSEMAC_REG_PHY_ADDR 0x0108
|
|
// #define TSEMAC_WR_DATA 0x010C
|
|
// #define TSEMAC_RD_DATA 0x0110
|
|
// #define TSEMAC_STATUS 0x0114
|
|
#define TSEMAC_A_FRAMES_TRANSMITTED_OK 0x68
|
|
#define TSEMAC_A_FRAMES_RECEIVED_OK 0x6C
|
|
#define TSEMAC_CRC_ERRORS 0x70
|
|
#define TSEMAC_IF_IN_ERRORS 0x88
|
|
#define TSEMAC_IF_OUT_ERRORS 0x8C
|
|
#define TSEMAC_ETHER_STATS_UNDER_SIZE_PKTS 0xB8
|
|
|
|
//Receive Supplementary Registers
|
|
#define TSEMAC_BOARD_FILTER_EN 0x0140
|
|
#define TSEMAC_MAC_ADDR_MAKE_LO 0x0144
|
|
#define TSEMAC_MAC_ADDR_MAKE_HI 0x0148
|
|
#define TSEMAC_TX_DST_ADDR_INS 0x0180
|
|
#define TSEMAC_DST_MAC_ADDR_LO 0x0184
|
|
#define TSEMAC_DST_MAC_ADDR_HI 0x0188
|
|
|
|
// additional TSEMAC control
|
|
#define ETHERNET_CTRL_MAC_RST 0x200
|
|
#define ETHERNET_CTRL_PHY_RST 0x204
|
|
#define ETHERNET_CTRL_DMA_RX_RESET 0x208
|
|
#define ETHERNET_CTRL_DMA_TX_RESET 0x20C
|
|
#define ETHERNET_CTRL_HW_RX_CHECKSUM_EN 0x210
|
|
#define ETHERNET_CTRL_HW_TX_CHECKSUM_EN 0x214
|
|
|
|
#define TSEMAC_PHY_TYPE_MII 0
|
|
#define TSEMAC_PHY_TYPE_GMII 1
|
|
#define TSEMAC_PHY_TYPE_RGMII_1_3 2
|
|
#define TSEMAC_PHY_TYPE_RGMII_2_0 3
|
|
#define TSEMAC_PHY_TYPE_SGMII 4
|
|
#define TSEMAC_PHY_TYPE_1000BASE_X 5
|
|
|
|
#define ETH_SPEED_MASK 0x00070000
|
|
#define ETH_SPEED_MASK_10 0x00010000
|
|
#define ETH_SPEED_MASK_100 0x00020000
|
|
#define ETH_SPEED_MASK_1000 0x00040000
|
|
|
|
|
|
#define dmasg_ca(base, channel) (base + channel*0x80)
|
|
#define DMA_CH_BYTE_PER_BURST_MASK 0xFFF
|
|
#define DMA_CH_INPUT_ADDRESS 0x00
|
|
#define DMA_CH_INPUT_STREAM 0x08
|
|
#define DMA_CH_INPUT_CONFIG 0x0C
|
|
#define DMA_CH_INPUT_CONFIG_MEMORY BIT_12
|
|
#define DMA_CH_INPUT_CONFIG_COMPLETION_ON_PACKET BIT_13
|
|
#define DMA_CH_INPUT_CONFIG_WAIT_ON_PACKET BIT_14
|
|
#define DMA_CH_OUTPUT_ADDRESS 0x10
|
|
#define DMA_CH_OUTPUT_STREAM 0x18
|
|
#define DMA_CH_OUTPUT_CONFIG 0x1C
|
|
#define DMA_CH_OUTPUT_CONFIG_MEMORY BIT_12
|
|
#define DMA_CH_OUTPUT_CONFIG_LAST BIT_13
|
|
#define DMA_CH_DIRECT_BYTES 0x20
|
|
#define DMA_CH_STATUS 0x2C
|
|
#define DMA_CH_STATUS_DIRECT_START BIT_0
|
|
#define DMA_CH_STATUS_BUSY BIT_0
|
|
#define DMA_CH_STATUS_SELF_RESTART BIT_1
|
|
#define DMA_CH_STATUS_STOP BIT_2
|
|
#define DMA_CH_STATUS_LINKED_LIST_START BIT_4
|
|
#define DMA_CH_FIFO 0x40
|
|
#define DMA_CH_PRIORITY 0x44
|
|
#define DMA_CH_INTERRUPT_ENABLE 0x50
|
|
#define DMA_CH_INTERRUPT_PENDING 0x54
|
|
#define DMA_CH_PROGRESS_BYTES 0x60
|
|
#define DMA_CH_LINKED_LIST_HEAD 0x70
|
|
#define DMA_CH_PORT_BASE 0
|
|
#define DMA_CH_SINK_ID_BASE 8
|
|
#define DMA_CH_DEST_ID_BASE 16
|
|
#define DMA_CH_PRIORITY_MASK 0x7
|
|
#define DMA_CH_WEIGHT_MASK 0x7
|
|
// Interrupt at the end of each descriptor
|
|
#define DMA_CH_INTERRUPT_DESCRIPTOR_COMPLETION_MASK BIT_0
|
|
// Interrupt at the middle of each descriptor, require the half_completion_interrupt option to be enabled for the channel
|
|
#define DMA_CH_INTERRUPT_DESCRIPTOR_COMPLETION_HALF_MASK BIT_1
|
|
// Interrupt when the channel is going off (not busy anymore)
|
|
#define DMA_CH_INTERRUPT_CHANNEL_COMPLETION_MASK BIT_2
|
|
// Interrupt each time that a linked list's descriptor status field is updated
|
|
#define DMA_CH_INTERRUPT_LINKED_LIST_UPDATE_MASK BIT_3
|
|
// Interrupt each time a S -> M channel has done transferring a packet into the memory
|
|
#define DMA_CH_INTERRUPT_INPUT_PACKET_MASK BIT_4
|
|
// Number of bytes (minus one) reserved at the descriptor FROM/TO addresses.
|
|
// If you want to transfer 10 bytes, this field should take the value 9
|
|
#define DMASG_DESCRIPTOR_CONTROL_BYTES 0x7FFFFFF
|
|
//Only for M -> S transfers, specify if a end of packet should be send at the end of the transfer
|
|
#define DMASG_DESCRIPTOR_CONTROL_END_OF_PACKET BIT_30
|
|
// Number of bytes transferred by the DMA for this descriptor.
|
|
#define DMASG_DESCRIPTOR_STATUS_BYTES 0x7FFFFFF
|
|
// Only for S -> M transfers, specify if the descriptor mark the end of a received packet
|
|
// Can be used when the dmasg_input_stream function is called with completion_on_packet set.
|
|
#define DMASG_DESCRIPTOR_STATUS_END_OF_PACKET BIT_30
|
|
// Specify if the descriptor was executed by the DMA.
|
|
// If the DMA read a completed descriptor, the channel is stopped and will produce a CHANNEL_COMPLETION interrupt.
|
|
#define DMASG_DESCRIPTOR_STATUS_COMPLETED BIT_31
|
|
#define DMASG_RX_BASE 0x0
|
|
#define DMASG_TX_BASE 0x80
|
|
|
|
#define DMASG_IRQ_ALL_MASK 0x1F
|
|
|
|
#define TSEMAC_FEATURE_PARTIAL_RX_CSUM (1 << 0)
|
|
#define TSEMAC_FEATURE_PARTIAL_TX_CSUM (1 << 1)
|
|
#define TSEMAC_FEATURE_FULL_RX_CSUM (1 << 2)
|
|
#define TSEMAC_FEATURE_FULL_TX_CSUM (1 << 3)
|
|
#define TSEMAC_FEATURE_DMA_64BIT (1 << 4)
|
|
|
|
#define TSEMAC_NO_CSUM_OFFLOAD 0
|
|
|
|
|
|
asm(".set regnum_x0 , 0");
|
|
asm(".set regnum_x1 , 1");
|
|
asm(".set regnum_x2 , 2");
|
|
asm(".set regnum_x3 , 3");
|
|
asm(".set regnum_x4 , 4");
|
|
asm(".set regnum_x5 , 5");
|
|
asm(".set regnum_x6 , 6");
|
|
asm(".set regnum_x7 , 7");
|
|
asm(".set regnum_x8 , 8");
|
|
asm(".set regnum_x9 , 9");
|
|
asm(".set regnum_x10 , 10");
|
|
asm(".set regnum_x11 , 11");
|
|
asm(".set regnum_x12 , 12");
|
|
asm(".set regnum_x13 , 13");
|
|
asm(".set regnum_x14 , 14");
|
|
asm(".set regnum_x15 , 15");
|
|
asm(".set regnum_x16 , 16");
|
|
asm(".set regnum_x17 , 17");
|
|
asm(".set regnum_x18 , 18");
|
|
asm(".set regnum_x19 , 19");
|
|
asm(".set regnum_x20 , 20");
|
|
asm(".set regnum_x21 , 21");
|
|
asm(".set regnum_x22 , 22");
|
|
asm(".set regnum_x23 , 23");
|
|
asm(".set regnum_x24 , 24");
|
|
asm(".set regnum_x25 , 25");
|
|
asm(".set regnum_x26 , 26");
|
|
asm(".set regnum_x27 , 27");
|
|
asm(".set regnum_x28 , 28");
|
|
asm(".set regnum_x29 , 29");
|
|
asm(".set regnum_x30 , 30");
|
|
asm(".set regnum_x31 , 31");
|
|
|
|
asm(".set regnum_zero, 0");
|
|
asm(".set regnum_ra , 1");
|
|
asm(".set regnum_sp , 2");
|
|
asm(".set regnum_gp , 3");
|
|
asm(".set regnum_tp , 4");
|
|
asm(".set regnum_t0 , 5");
|
|
asm(".set regnum_t1 , 6");
|
|
asm(".set regnum_t2 , 7");
|
|
asm(".set regnum_s0 , 8");
|
|
asm(".set regnum_s1 , 9");
|
|
asm(".set regnum_a0 , 10");
|
|
asm(".set regnum_a1 , 11");
|
|
asm(".set regnum_a2 , 12");
|
|
asm(".set regnum_a3 , 13");
|
|
asm(".set regnum_a4 , 14");
|
|
asm(".set regnum_a5 , 15");
|
|
asm(".set regnum_a6 , 16");
|
|
asm(".set regnum_a7 , 17");
|
|
asm(".set regnum_s2 , 18");
|
|
asm(".set regnum_s3 , 19");
|
|
asm(".set regnum_s4 , 20");
|
|
asm(".set regnum_s5 , 21");
|
|
asm(".set regnum_s6 , 22");
|
|
asm(".set regnum_s7 , 23");
|
|
asm(".set regnum_s8 , 24");
|
|
asm(".set regnum_s9 , 25");
|
|
asm(".set regnum_s10 , 26");
|
|
asm(".set regnum_s11 , 27");
|
|
asm(".set regnum_t3 , 28");
|
|
asm(".set regnum_t4 , 29");
|
|
asm(".set regnum_t5 , 30");
|
|
asm(".set regnum_t6 , 31");
|
|
|
|
#if defined(CONFIG_32BIT)
|
|
//Invalidate the whole data cache
|
|
#define data_cache_invalidate_all() asm(".word(0x500F)");
|
|
|
|
//Invalidate all the data cache ways lines which could store the given address
|
|
#define data_cache_invalidate_address(address) \
|
|
({ \
|
|
asm volatile( \
|
|
".word ((0x500F) | (regnum_%0 << 15));" \
|
|
: \
|
|
: "r" (address) \
|
|
); \
|
|
})
|
|
#else
|
|
#define data_cache_invalidate_all()
|
|
#define data_cache_invalidate_address(address)
|
|
#endif /* CONFIG_32_BIT */
|
|
|
|
//Invalidate the whole instruction cache
|
|
#define instruction_cache_invalidate() asm("fence.i");
|
|
|
|
|
|
|
|
struct dmasg_descriptor {
|
|
// See all DMASG_DESCRIPTOR_STATUS_* defines
|
|
// Updated by the DMA at the end of each descriptor and when a S -> M packet is completely transferred into memory
|
|
u32 status;
|
|
// See all DMASG_DESCRIPTOR_CONTROL_* defines
|
|
u32 control;
|
|
// For M -> ? transfers, memory address of the input data
|
|
u64 from;
|
|
// For ? -> M transfers, memory address of the output data
|
|
u64 to;
|
|
// Memory address of the next descriptor
|
|
u64 next;
|
|
struct sk_buff *skb;
|
|
} __aligned(0x40);
|
|
|
|
struct efx_tsemac_local {
|
|
struct net_device *ndev;
|
|
struct device *dev;
|
|
|
|
/* Connection to PHY device */
|
|
struct phylink *phylink;
|
|
struct phylink_config phylink_config;
|
|
|
|
struct mdio_device *pcs_phy;
|
|
struct phylink_pcs pcs;
|
|
|
|
struct clk *axi_clk;
|
|
/* MDIO bus data */
|
|
struct mii_bus *mii_bus; /* MII bus reference */
|
|
u8 mii_clk_div;
|
|
|
|
/* IO registers, dma functions and IRQs */
|
|
resource_size_t regs_start;
|
|
void __iomem *regs;
|
|
void __iomem *dma_regs;
|
|
|
|
struct work_struct dma_err_task;
|
|
|
|
int tx_irq;
|
|
int rx_irq;
|
|
int eth_irq;
|
|
phy_interface_t phy_mode;
|
|
|
|
/* Buffer descriptors */
|
|
struct napi_struct napi_rx;
|
|
struct napi_struct napi_tx;
|
|
|
|
struct dmasg_descriptor *tx_bd_v;
|
|
dma_addr_t tx_bd_p;
|
|
u32 tx_bd_ci;
|
|
u32 tx_bd_tail;
|
|
u32 tx_dma_cr;
|
|
u32 tx_bd_num;
|
|
|
|
struct dmasg_descriptor *rx_bd_v;
|
|
dma_addr_t rx_bd_p;
|
|
u32 rx_bd_ci;
|
|
u32 rx_dma_cr;
|
|
u32 rx_bd_num;
|
|
|
|
u64_stats_t rx_packets;
|
|
u64_stats_t rx_bytes;
|
|
struct u64_stats_sync rx_stat_sync;
|
|
u64_stats_t tx_packets;
|
|
u64_stats_t tx_bytes;
|
|
struct u64_stats_sync tx_stat_sync;
|
|
u32 options;
|
|
u32 features;
|
|
|
|
u32 max_frm_size;
|
|
u32 rxmem;
|
|
|
|
int csum_offload_on_tx_path;
|
|
int csum_offload_on_rx_path;
|
|
|
|
u32 coalesce_count_rx;
|
|
u32 coalesce_usec_rx;
|
|
u32 coalesce_count_tx;
|
|
u32 coalesce_usec_tx;
|
|
|
|
/* statistics */
|
|
u64 prev_tx_err;
|
|
u64 prev_rx_err;
|
|
|
|
spinlock_t lock;
|
|
};
|
|
|
|
static inline void tsemac_lock_mii(struct efx_tsemac_local *lp)
|
|
{
|
|
if (lp->mii_bus)
|
|
mutex_lock(&lp->mii_bus->mdio_lock);
|
|
}
|
|
|
|
static inline void tsemac_unlock_mii(struct efx_tsemac_local *lp)
|
|
{
|
|
if (lp->mii_bus)
|
|
mutex_unlock(&lp->mii_bus->mdio_lock);
|
|
}
|
|
|
|
static inline void desc_set_tx_phys_addr(struct efx_tsemac_local *lp, dma_addr_t addr,
|
|
struct dmasg_descriptor *desc)
|
|
{
|
|
desc->from = lower_32_bits(addr);
|
|
}
|
|
|
|
static inline dma_addr_t desc_get_tx_phys_addr(struct efx_tsemac_local *lp,
|
|
struct dmasg_descriptor *desc)
|
|
{
|
|
return desc->from;
|
|
}
|
|
|
|
static inline void desc_set_rx_phys_addr(struct efx_tsemac_local *lp, dma_addr_t addr,
|
|
struct dmasg_descriptor *desc)
|
|
{
|
|
desc->to = lower_32_bits(addr);
|
|
}
|
|
|
|
static inline dma_addr_t desc_get_rx_phys_addr(struct efx_tsemac_local *lp,
|
|
struct dmasg_descriptor *desc)
|
|
{
|
|
return desc->to;
|
|
}
|
|
|
|
static inline u32 tsemac_in32(struct efx_tsemac_local *lp, off_t reg)
|
|
{
|
|
return ioread32(lp->regs + reg);
|
|
}
|
|
|
|
static inline void tsemac_out32(struct efx_tsemac_local *lp, off_t reg,
|
|
u32 value)
|
|
{
|
|
iowrite32(value, lp->regs + reg);
|
|
}
|
|
|
|
static inline void tsemac_set_32bit(struct efx_tsemac_local *lp, off_t reg,
|
|
u32 value)
|
|
{
|
|
u32 temp = tsemac_in32(lp, reg);
|
|
temp |= value;
|
|
tsemac_out32(lp, reg, temp);
|
|
}
|
|
|
|
static inline void tsemac_clear_32bit(struct efx_tsemac_local *lp, off_t reg,
|
|
u32 value)
|
|
{
|
|
u32 temp = tsemac_in32(lp, reg);
|
|
temp &= ~value;
|
|
tsemac_out32(lp, reg, temp);
|
|
}
|
|
|
|
static inline u32 tsemac_dma_in32(struct efx_tsemac_local *lp, off_t reg, off_t ch_offset)
|
|
{
|
|
return ioread32(lp->dma_regs + reg + ch_offset);
|
|
}
|
|
|
|
static inline void tsemac_dma_out32(struct efx_tsemac_local *lp, off_t reg, off_t ch_offset,
|
|
u32 value)
|
|
{
|
|
return iowrite32(value, lp->dma_regs + reg + ch_offset);
|
|
}
|
|
|
|
int __tsemac_device_reset(struct efx_tsemac_local *lp);
|
|
|
|
int tsemac_free_tx_chain(struct efx_tsemac_local *lp, u32 first_bd,
|
|
int nr_bds, bool force, u32 *sizep, int budget);
|
|
|
|
void tsemac_dma_stop(struct efx_tsemac_local *lp);
|
|
|
|
void tsemac_dma_bd_release(struct net_device *ndev);
|
|
|
|
int tsemac_dma_bd_init(struct net_device *ndev);
|
|
|
|
void tsemac_dma_start(struct efx_tsemac_local *lp);
|
|
|
|
void tsemac_mdio_teardown(struct efx_tsemac_local *lp);
|
|
|
|
int tsemac_mdio_setup(struct efx_tsemac_local *lp);
|
|
|
|
#endif
|