mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-21 12:11:49 +08:00
rtase: Add support for a pci table in this module
Add support for a pci table in this module, and implement pci_driver function to initialize this driver, remove this driver, or shutdown this driver. Signed-off-by: Justin Lai <justinlai0215@realtek.com> Link: https://patch.msgid.link/20240904032114.247117-2-justinlai0215@realtek.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
502cc061de
commit
a36e9f5cfe
340
drivers/net/ethernet/realtek/rtase/rtase.h
Normal file
340
drivers/net/ethernet/realtek/rtase/rtase.h
Normal file
@ -0,0 +1,340 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* rtase is the Linux device driver released for Realtek Automotive Switch
|
||||
* controllers with PCI-Express interface.
|
||||
*
|
||||
* Copyright(c) 2024 Realtek Semiconductor Corp.
|
||||
*/
|
||||
|
||||
#ifndef RTASE_H
|
||||
#define RTASE_H
|
||||
|
||||
#define RTASE_HW_VER_MASK 0x7C800000
|
||||
|
||||
#define RTASE_RX_DMA_BURST_256 4
|
||||
#define RTASE_TX_DMA_BURST_UNLIMITED 7
|
||||
|
||||
#define RTASE_RX_BUF_SIZE (PAGE_SIZE - \
|
||||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
#define RTASE_MAX_JUMBO_SIZE (RTASE_RX_BUF_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN)
|
||||
|
||||
/* 3 means InterFrameGap = the shortest one */
|
||||
#define RTASE_INTERFRAMEGAP 0x03
|
||||
|
||||
#define RTASE_REGS_SIZE 256
|
||||
#define RTASE_PCI_REGS_SIZE 0x100
|
||||
|
||||
#define RTASE_MULTICAST_FILTER_MASK GENMASK(30, 26)
|
||||
|
||||
#define RTASE_VLAN_FILTER_ENTRY_NUM 32
|
||||
#define RTASE_NUM_TX_QUEUE 8
|
||||
#define RTASE_NUM_RX_QUEUE 4
|
||||
|
||||
#define RTASE_TXQ_CTRL 1
|
||||
#define RTASE_FUNC_TXQ_NUM 1
|
||||
#define RTASE_FUNC_RXQ_NUM 1
|
||||
#define RTASE_INTERRUPT_NUM 1
|
||||
|
||||
#define RTASE_MITI_TIME_COUNT_MASK GENMASK(3, 0)
|
||||
#define RTASE_MITI_TIME_UNIT_MASK GENMASK(7, 4)
|
||||
#define RTASE_MITI_DEFAULT_TIME 128
|
||||
#define RTASE_MITI_MAX_TIME 491520
|
||||
#define RTASE_MITI_PKT_NUM_COUNT_MASK GENMASK(11, 8)
|
||||
#define RTASE_MITI_PKT_NUM_UNIT_MASK GENMASK(13, 12)
|
||||
#define RTASE_MITI_DEFAULT_PKT_NUM 64
|
||||
#define RTASE_MITI_MAX_PKT_NUM_IDX 3
|
||||
#define RTASE_MITI_MAX_PKT_NUM_UNIT 16
|
||||
#define RTASE_MITI_MAX_PKT_NUM 240
|
||||
#define RTASE_MITI_COUNT_BIT_NUM 4
|
||||
|
||||
#define RTASE_NUM_MSIX 4
|
||||
|
||||
#define RTASE_DWORD_MOD 16
|
||||
|
||||
/*****************************************************************************/
|
||||
enum rtase_registers {
|
||||
RTASE_MAC0 = 0x0000,
|
||||
RTASE_MAC4 = 0x0004,
|
||||
RTASE_MAR0 = 0x0008,
|
||||
RTASE_MAR1 = 0x000C,
|
||||
RTASE_DTCCR0 = 0x0010,
|
||||
RTASE_DTCCR4 = 0x0014,
|
||||
#define RTASE_COUNTER_RESET BIT(0)
|
||||
#define RTASE_COUNTER_DUMP BIT(3)
|
||||
|
||||
RTASE_FCR = 0x0018,
|
||||
#define RTASE_FCR_RXQ_MASK GENMASK(5, 4)
|
||||
|
||||
RTASE_LBK_CTRL = 0x001A,
|
||||
#define RTASE_LBK_ATLD BIT(1)
|
||||
#define RTASE_LBK_CLR BIT(0)
|
||||
|
||||
RTASE_TX_DESC_ADDR0 = 0x0020,
|
||||
RTASE_TX_DESC_ADDR4 = 0x0024,
|
||||
RTASE_TX_DESC_COMMAND = 0x0028,
|
||||
#define RTASE_TX_DESC_CMD_CS BIT(15)
|
||||
#define RTASE_TX_DESC_CMD_WE BIT(14)
|
||||
|
||||
RTASE_BOOT_CTL = 0x6004,
|
||||
RTASE_CLKSW_SET = 0x6018,
|
||||
|
||||
RTASE_CHIP_CMD = 0x0037,
|
||||
#define RTASE_STOP_REQ BIT(7)
|
||||
#define RTASE_STOP_REQ_DONE BIT(6)
|
||||
#define RTASE_RE BIT(3)
|
||||
#define RTASE_TE BIT(2)
|
||||
|
||||
RTASE_IMR0 = 0x0038,
|
||||
RTASE_ISR0 = 0x003C,
|
||||
#define RTASE_TOK7 BIT(30)
|
||||
#define RTASE_TOK6 BIT(28)
|
||||
#define RTASE_TOK5 BIT(26)
|
||||
#define RTASE_TOK4 BIT(24)
|
||||
#define RTASE_FOVW BIT(6)
|
||||
#define RTASE_RDU BIT(4)
|
||||
#define RTASE_TOK BIT(2)
|
||||
#define RTASE_ROK BIT(0)
|
||||
|
||||
RTASE_IMR1 = 0x0800,
|
||||
RTASE_ISR1 = 0x0802,
|
||||
#define RTASE_Q_TOK BIT(4)
|
||||
#define RTASE_Q_RDU BIT(1)
|
||||
#define RTASE_Q_ROK BIT(0)
|
||||
|
||||
RTASE_EPHY_ISR = 0x6014,
|
||||
RTASE_EPHY_IMR = 0x6016,
|
||||
|
||||
RTASE_TX_CONFIG_0 = 0x0040,
|
||||
#define RTASE_TX_INTER_FRAME_GAP_MASK GENMASK(25, 24)
|
||||
/* DMA burst value (0-7) is shift this many bits */
|
||||
#define RTASE_TX_DMA_MASK GENMASK(10, 8)
|
||||
|
||||
RTASE_RX_CONFIG_0 = 0x0044,
|
||||
#define RTASE_RX_SINGLE_FETCH BIT(14)
|
||||
#define RTASE_RX_SINGLE_TAG BIT(13)
|
||||
#define RTASE_RX_MX_DMA_MASK GENMASK(10, 8)
|
||||
#define RTASE_ACPT_FLOW BIT(7)
|
||||
#define RTASE_ACCEPT_ERR BIT(5)
|
||||
#define RTASE_ACCEPT_RUNT BIT(4)
|
||||
#define RTASE_ACCEPT_BROADCAST BIT(3)
|
||||
#define RTASE_ACCEPT_MULTICAST BIT(2)
|
||||
#define RTASE_ACCEPT_MYPHYS BIT(1)
|
||||
#define RTASE_ACCEPT_ALLPHYS BIT(0)
|
||||
#define RTASE_ACCEPT_MASK (RTASE_ACPT_FLOW | RTASE_ACCEPT_ERR | \
|
||||
RTASE_ACCEPT_RUNT | RTASE_ACCEPT_BROADCAST | \
|
||||
RTASE_ACCEPT_MULTICAST | RTASE_ACCEPT_MYPHYS | \
|
||||
RTASE_ACCEPT_ALLPHYS)
|
||||
|
||||
RTASE_RX_CONFIG_1 = 0x0046,
|
||||
#define RTASE_RX_MAX_FETCH_DESC_MASK GENMASK(15, 11)
|
||||
#define RTASE_RX_NEW_DESC_FORMAT_EN BIT(8)
|
||||
#define RTASE_OUTER_VLAN_DETAG_EN BIT(7)
|
||||
#define RTASE_INNER_VLAN_DETAG_EN BIT(6)
|
||||
#define RTASE_PCIE_NEW_FLOW BIT(2)
|
||||
#define RTASE_PCIE_RELOAD_EN BIT(0)
|
||||
|
||||
RTASE_EEM = 0x0050,
|
||||
#define RTASE_EEM_UNLOCK 0xC0
|
||||
|
||||
RTASE_TDFNR = 0x0057,
|
||||
RTASE_TPPOLL = 0x0090,
|
||||
RTASE_PDR = 0x00B0,
|
||||
RTASE_FIFOR = 0x00D3,
|
||||
#define RTASE_TX_FIFO_EMPTY BIT(5)
|
||||
#define RTASE_RX_FIFO_EMPTY BIT(4)
|
||||
|
||||
RTASE_RMS = 0x00DA,
|
||||
RTASE_CPLUS_CMD = 0x00E0,
|
||||
#define RTASE_FORCE_RXFLOW_EN BIT(11)
|
||||
#define RTASE_FORCE_TXFLOW_EN BIT(10)
|
||||
#define RTASE_RX_CHKSUM BIT(5)
|
||||
|
||||
RTASE_Q0_RX_DESC_ADDR0 = 0x00E4,
|
||||
RTASE_Q0_RX_DESC_ADDR4 = 0x00E8,
|
||||
RTASE_Q1_RX_DESC_ADDR0 = 0x4000,
|
||||
RTASE_Q1_RX_DESC_ADDR4 = 0x4004,
|
||||
RTASE_MTPS = 0x00EC,
|
||||
#define RTASE_TAG_NUM_SEL_MASK GENMASK(10, 8)
|
||||
|
||||
RTASE_MISC = 0x00F2,
|
||||
#define RTASE_RX_DV_GATE_EN BIT(3)
|
||||
|
||||
RTASE_TFUN_CTRL = 0x0400,
|
||||
#define RTASE_TX_NEW_DESC_FORMAT_EN BIT(0)
|
||||
|
||||
RTASE_TX_CONFIG_1 = 0x203E,
|
||||
#define RTASE_TC_MODE_MASK GENMASK(11, 10)
|
||||
|
||||
RTASE_TOKSEL = 0x2046,
|
||||
RTASE_RFIFONFULL = 0x4406,
|
||||
RTASE_INT_MITI_TX = 0x0A00,
|
||||
RTASE_INT_MITI_RX = 0x0A80,
|
||||
|
||||
RTASE_VLAN_ENTRY_0 = 0xAC80,
|
||||
};
|
||||
|
||||
enum rtase_desc_status_bit {
|
||||
RTASE_DESC_OWN = BIT(31), /* Descriptor is owned by NIC */
|
||||
RTASE_RING_END = BIT(30), /* End of descriptor ring */
|
||||
};
|
||||
|
||||
enum rtase_sw_flag_content {
|
||||
RTASE_SWF_MSI_ENABLED = BIT(1),
|
||||
RTASE_SWF_MSIX_ENABLED = BIT(2),
|
||||
};
|
||||
|
||||
#define RSVD_MASK 0x3FFFC000
|
||||
|
||||
struct rtase_tx_desc {
|
||||
__le32 opts1;
|
||||
__le32 opts2;
|
||||
__le64 addr;
|
||||
__le32 opts3;
|
||||
__le32 reserved1;
|
||||
__le32 reserved2;
|
||||
__le32 reserved3;
|
||||
} __packed;
|
||||
|
||||
/*------ offset 0 of tx descriptor ------*/
|
||||
#define RTASE_TX_FIRST_FRAG BIT(29) /* Tx First segment of a packet */
|
||||
#define RTASE_TX_LAST_FRAG BIT(28) /* Tx Final segment of a packet */
|
||||
#define RTASE_GIANT_SEND_V4 BIT(26) /* TCP Giant Send Offload V4 (GSOv4) */
|
||||
#define RTASE_GIANT_SEND_V6 BIT(25) /* TCP Giant Send Offload V6 (GSOv6) */
|
||||
#define RTASE_TX_VLAN_TAG BIT(17) /* Add VLAN tag */
|
||||
|
||||
/*------ offset 4 of tx descriptor ------*/
|
||||
#define RTASE_TX_UDPCS_C BIT(31) /* Calculate UDP/IP checksum */
|
||||
#define RTASE_TX_TCPCS_C BIT(30) /* Calculate TCP/IP checksum */
|
||||
#define RTASE_TX_IPCS_C BIT(29) /* Calculate IP checksum */
|
||||
#define RTASE_TX_IPV6F_C BIT(28) /* Indicate it is an IPv6 packet */
|
||||
|
||||
union rtase_rx_desc {
|
||||
struct {
|
||||
__le64 header_buf_addr;
|
||||
__le32 reserved1;
|
||||
__le32 opts_header_len;
|
||||
__le64 addr;
|
||||
__le32 reserved2;
|
||||
__le32 opts1;
|
||||
} __packed desc_cmd;
|
||||
|
||||
struct {
|
||||
__le32 reserved1;
|
||||
__le32 reserved2;
|
||||
__le32 rss;
|
||||
__le32 opts4;
|
||||
__le32 reserved3;
|
||||
__le32 opts3;
|
||||
__le32 opts2;
|
||||
__le32 opts1;
|
||||
} __packed desc_status;
|
||||
} __packed;
|
||||
|
||||
/*------ offset 28 of rx descriptor ------*/
|
||||
#define RTASE_RX_FIRST_FRAG BIT(25) /* Rx First segment of a packet */
|
||||
#define RTASE_RX_LAST_FRAG BIT(24) /* Rx Final segment of a packet */
|
||||
#define RTASE_RX_RES BIT(20)
|
||||
#define RTASE_RX_RUNT BIT(19)
|
||||
#define RTASE_RX_RWT BIT(18)
|
||||
#define RTASE_RX_CRC BIT(16)
|
||||
#define RTASE_RX_V6F BIT(31)
|
||||
#define RTASE_RX_V4F BIT(30)
|
||||
#define RTASE_RX_UDPT BIT(29)
|
||||
#define RTASE_RX_TCPT BIT(28)
|
||||
#define RTASE_RX_IPF BIT(26) /* IP checksum failed */
|
||||
#define RTASE_RX_UDPF BIT(25) /* UDP/IP checksum failed */
|
||||
#define RTASE_RX_TCPF BIT(24) /* TCP/IP checksum failed */
|
||||
#define RTASE_RX_VLAN_TAG BIT(16) /* VLAN tag available */
|
||||
|
||||
#define RTASE_NUM_DESC 1024
|
||||
#define RTASE_TX_BUDGET_DEFAULT 256
|
||||
#define RTASE_TX_RING_DESC_SIZE (RTASE_NUM_DESC * sizeof(struct rtase_tx_desc))
|
||||
#define RTASE_RX_RING_DESC_SIZE (RTASE_NUM_DESC * sizeof(union rtase_rx_desc))
|
||||
#define RTASE_TX_STOP_THRS (MAX_SKB_FRAGS + 1)
|
||||
#define RTASE_TX_START_THRS (2 * RTASE_TX_STOP_THRS)
|
||||
#define RTASE_VLAN_TAG_MASK GENMASK(15, 0)
|
||||
#define RTASE_RX_PKT_SIZE_MASK GENMASK(13, 0)
|
||||
|
||||
#define RTASE_IVEC_NAME_SIZE (IFNAMSIZ + 10)
|
||||
|
||||
struct rtase_int_vector {
|
||||
struct rtase_private *tp;
|
||||
unsigned int irq;
|
||||
char name[RTASE_IVEC_NAME_SIZE];
|
||||
u16 index;
|
||||
u16 imr_addr;
|
||||
u16 isr_addr;
|
||||
u32 imr;
|
||||
struct list_head ring_list;
|
||||
struct napi_struct napi;
|
||||
int (*poll)(struct napi_struct *napi, int budget);
|
||||
};
|
||||
|
||||
struct rtase_ring {
|
||||
struct rtase_int_vector *ivec;
|
||||
void *desc;
|
||||
dma_addr_t phy_addr;
|
||||
u32 cur_idx;
|
||||
u32 dirty_idx;
|
||||
u16 index;
|
||||
|
||||
struct sk_buff *skbuff[RTASE_NUM_DESC];
|
||||
void *data_buf[RTASE_NUM_DESC];
|
||||
union {
|
||||
u32 len[RTASE_NUM_DESC];
|
||||
dma_addr_t data_phy_addr[RTASE_NUM_DESC];
|
||||
} mis;
|
||||
|
||||
struct list_head ring_entry;
|
||||
int (*ring_handler)(struct rtase_ring *ring, int budget);
|
||||
u64 alloc_fail;
|
||||
};
|
||||
|
||||
struct rtase_stats {
|
||||
u64 tx_dropped;
|
||||
u64 rx_dropped;
|
||||
u64 multicast;
|
||||
u64 rx_errors;
|
||||
u64 rx_length_errors;
|
||||
u64 rx_crc_errors;
|
||||
};
|
||||
|
||||
struct rtase_private {
|
||||
void __iomem *mmio_addr;
|
||||
u32 sw_flag;
|
||||
|
||||
struct pci_dev *pdev;
|
||||
struct net_device *dev;
|
||||
u32 rx_buf_sz;
|
||||
|
||||
struct page_pool *page_pool;
|
||||
struct rtase_ring tx_ring[RTASE_NUM_TX_QUEUE];
|
||||
struct rtase_ring rx_ring[RTASE_NUM_RX_QUEUE];
|
||||
struct rtase_counters *tally_vaddr;
|
||||
dma_addr_t tally_paddr;
|
||||
|
||||
u32 vlan_filter_ctrl;
|
||||
u16 vlan_filter_vid[RTASE_VLAN_FILTER_ENTRY_NUM];
|
||||
|
||||
struct msix_entry msix_entry[RTASE_NUM_MSIX];
|
||||
struct rtase_int_vector int_vector[RTASE_NUM_MSIX];
|
||||
|
||||
struct rtase_stats stats;
|
||||
|
||||
u16 tx_queue_ctrl;
|
||||
u16 func_tx_queue_num;
|
||||
u16 func_rx_queue_num;
|
||||
u16 int_nums;
|
||||
u16 tx_int_mit;
|
||||
u16 rx_int_mit;
|
||||
};
|
||||
|
||||
#define RTASE_LSO_64K 64000
|
||||
|
||||
#define RTASE_NIC_MAX_PHYS_BUF_COUNT_LSO2 (16 * 4)
|
||||
|
||||
#define RTASE_TCPHO_MASK GENMASK(24, 18)
|
||||
|
||||
#define RTASE_MSS_MASK GENMASK(28, 18)
|
||||
|
||||
#endif /* RTASE_H */
|
638
drivers/net/ethernet/realtek/rtase/rtase_main.c
Normal file
638
drivers/net/ethernet/realtek/rtase/rtase_main.c
Normal file
@ -0,0 +1,638 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* rtase is the Linux device driver released for Realtek Automotive Switch
|
||||
* controllers with PCI-Express interface.
|
||||
*
|
||||
* Copyright(c) 2024 Realtek Semiconductor Corp.
|
||||
*
|
||||
* Below is a simplified block diagram of the chip and its relevant interfaces.
|
||||
*
|
||||
* *************************
|
||||
* * *
|
||||
* * CPU network device *
|
||||
* * *
|
||||
* * +-------------+ *
|
||||
* * | PCIE Host | *
|
||||
* ***********++************
|
||||
* ||
|
||||
* PCIE
|
||||
* ||
|
||||
* ********************++**********************
|
||||
* * | PCIE Endpoint | *
|
||||
* * +---------------+ *
|
||||
* * | GMAC | *
|
||||
* * +--++--+ Realtek *
|
||||
* * || RTL90xx Series *
|
||||
* * || *
|
||||
* * +-------------++----------------+ *
|
||||
* * | | MAC | | *
|
||||
* * | +-----+ | *
|
||||
* * | | *
|
||||
* * | Ethernet Switch Core | *
|
||||
* * | | *
|
||||
* * | +-----+ +-----+ | *
|
||||
* * | | MAC |...........| MAC | | *
|
||||
* * +---+-----+-----------+-----+---+ *
|
||||
* * | PHY |...........| PHY | *
|
||||
* * +--++-+ +--++-+ *
|
||||
* *************||****************||***********
|
||||
*
|
||||
* The block of the Realtek RTL90xx series is our entire chip architecture,
|
||||
* the GMAC is connected to the switch core, and there is no PHY in between.
|
||||
* In addition, this driver is mainly used to control GMAC, but does not
|
||||
* control the switch core, so it is not the same as DSA. Linux only plays
|
||||
* the role of a normal leaf node in this model.
|
||||
*/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <asm/irq.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <net/netdev_queues.h>
|
||||
#include <net/page_pool/helpers.h>
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
#include "rtase.h"
|
||||
|
||||
#define RTK_OPTS1_DEBUG_VALUE 0x0BADBEEF
|
||||
#define RTK_MAGIC_NUMBER 0x0BADBADBADBADBAD
|
||||
|
||||
static const struct pci_device_id rtase_pci_tbl[] = {
|
||||
{PCI_VDEVICE(REALTEK, 0x906A)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, rtase_pci_tbl);
|
||||
|
||||
MODULE_AUTHOR("Realtek ARD Software Team");
|
||||
MODULE_DESCRIPTION("Network Driver for the PCIe interface of Realtek Automotive Ethernet Switch");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
struct rtase_counters {
|
||||
__le64 tx_packets;
|
||||
__le64 rx_packets;
|
||||
__le64 tx_errors;
|
||||
__le32 rx_errors;
|
||||
__le16 rx_missed;
|
||||
__le16 align_errors;
|
||||
__le32 tx_one_collision;
|
||||
__le32 tx_multi_collision;
|
||||
__le64 rx_unicast;
|
||||
__le64 rx_broadcast;
|
||||
__le32 rx_multicast;
|
||||
__le16 tx_aborted;
|
||||
__le16 tx_underun;
|
||||
} __packed;
|
||||
|
||||
static void rtase_w8(const struct rtase_private *tp, u16 reg, u8 val8)
|
||||
{
|
||||
writeb(val8, tp->mmio_addr + reg);
|
||||
}
|
||||
|
||||
static void rtase_w16(const struct rtase_private *tp, u16 reg, u16 val16)
|
||||
{
|
||||
writew(val16, tp->mmio_addr + reg);
|
||||
}
|
||||
|
||||
static void rtase_w32(const struct rtase_private *tp, u16 reg, u32 val32)
|
||||
{
|
||||
writel(val32, tp->mmio_addr + reg);
|
||||
}
|
||||
|
||||
static u8 rtase_r8(const struct rtase_private *tp, u16 reg)
|
||||
{
|
||||
return readb(tp->mmio_addr + reg);
|
||||
}
|
||||
|
||||
static u16 rtase_r16(const struct rtase_private *tp, u16 reg)
|
||||
{
|
||||
return readw(tp->mmio_addr + reg);
|
||||
}
|
||||
|
||||
static u32 rtase_r32(const struct rtase_private *tp, u16 reg)
|
||||
{
|
||||
return readl(tp->mmio_addr + reg);
|
||||
}
|
||||
|
||||
static void rtase_tally_counter_clear(const struct rtase_private *tp)
|
||||
{
|
||||
u32 cmd = lower_32_bits(tp->tally_paddr);
|
||||
|
||||
rtase_w32(tp, RTASE_DTCCR4, upper_32_bits(tp->tally_paddr));
|
||||
rtase_w32(tp, RTASE_DTCCR0, cmd | RTASE_COUNTER_RESET);
|
||||
}
|
||||
|
||||
static void rtase_enable_eem_write(const struct rtase_private *tp)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
val = rtase_r8(tp, RTASE_EEM);
|
||||
rtase_w8(tp, RTASE_EEM, val | RTASE_EEM_UNLOCK);
|
||||
}
|
||||
|
||||
static void rtase_disable_eem_write(const struct rtase_private *tp)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
val = rtase_r8(tp, RTASE_EEM);
|
||||
rtase_w8(tp, RTASE_EEM, val & ~RTASE_EEM_UNLOCK);
|
||||
}
|
||||
|
||||
static void rtase_rar_set(const struct rtase_private *tp, const u8 *addr)
|
||||
{
|
||||
u32 rar_low, rar_high;
|
||||
|
||||
rar_low = (u32)addr[0] | ((u32)addr[1] << 8) |
|
||||
((u32)addr[2] << 16) | ((u32)addr[3] << 24);
|
||||
|
||||
rar_high = (u32)addr[4] | ((u32)addr[5] << 8);
|
||||
|
||||
rtase_enable_eem_write(tp);
|
||||
rtase_w32(tp, RTASE_MAC0, rar_low);
|
||||
rtase_w32(tp, RTASE_MAC4, rar_high);
|
||||
rtase_disable_eem_write(tp);
|
||||
rtase_w16(tp, RTASE_LBK_CTRL, RTASE_LBK_ATLD | RTASE_LBK_CLR);
|
||||
}
|
||||
|
||||
static void rtase_get_mac_address(struct net_device *dev)
|
||||
{
|
||||
struct rtase_private *tp = netdev_priv(dev);
|
||||
u8 mac_addr[ETH_ALEN] __aligned(2) = {};
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
mac_addr[i] = rtase_r8(tp, RTASE_MAC0 + i);
|
||||
|
||||
if (!is_valid_ether_addr(mac_addr)) {
|
||||
eth_hw_addr_random(dev);
|
||||
netdev_warn(dev, "Random ether addr %pM\n", dev->dev_addr);
|
||||
} else {
|
||||
eth_hw_addr_set(dev, mac_addr);
|
||||
ether_addr_copy(dev->perm_addr, dev->dev_addr);
|
||||
}
|
||||
|
||||
rtase_rar_set(tp, dev->dev_addr);
|
||||
}
|
||||
|
||||
static void rtase_reset_interrupt(struct pci_dev *pdev,
|
||||
const struct rtase_private *tp)
|
||||
{
|
||||
if (tp->sw_flag & RTASE_SWF_MSIX_ENABLED)
|
||||
pci_disable_msix(pdev);
|
||||
else
|
||||
pci_disable_msi(pdev);
|
||||
}
|
||||
|
||||
static int rtase_alloc_msix(struct pci_dev *pdev, struct rtase_private *tp)
|
||||
{
|
||||
int ret, irq;
|
||||
u16 i;
|
||||
|
||||
memset(tp->msix_entry, 0x0, RTASE_NUM_MSIX *
|
||||
sizeof(struct msix_entry));
|
||||
|
||||
for (i = 0; i < RTASE_NUM_MSIX; i++)
|
||||
tp->msix_entry[i].entry = i;
|
||||
|
||||
ret = pci_enable_msix_exact(pdev, tp->msix_entry, tp->int_nums);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < tp->int_nums; i++) {
|
||||
irq = pci_irq_vector(pdev, i);
|
||||
if (!irq) {
|
||||
pci_disable_msix(pdev);
|
||||
return irq;
|
||||
}
|
||||
|
||||
tp->int_vector[i].irq = irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtase_alloc_interrupt(struct pci_dev *pdev,
|
||||
struct rtase_private *tp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rtase_alloc_msix(pdev, tp);
|
||||
if (ret) {
|
||||
ret = pci_enable_msi(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to alloc interrupt.(MSI)\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
tp->sw_flag |= RTASE_SWF_MSI_ENABLED;
|
||||
} else {
|
||||
tp->sw_flag |= RTASE_SWF_MSIX_ENABLED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtase_init_hardware(const struct rtase_private *tp)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
for (i = 0; i < RTASE_VLAN_FILTER_ENTRY_NUM; i++)
|
||||
rtase_w32(tp, RTASE_VLAN_ENTRY_0 + i * 4, 0);
|
||||
}
|
||||
|
||||
static void rtase_init_int_vector(struct rtase_private *tp)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
/* interrupt vector 0 */
|
||||
tp->int_vector[0].tp = tp;
|
||||
tp->int_vector[0].index = 0;
|
||||
tp->int_vector[0].imr_addr = RTASE_IMR0;
|
||||
tp->int_vector[0].isr_addr = RTASE_ISR0;
|
||||
tp->int_vector[0].imr = RTASE_ROK | RTASE_RDU | RTASE_TOK |
|
||||
RTASE_TOK4 | RTASE_TOK5 | RTASE_TOK6 |
|
||||
RTASE_TOK7;
|
||||
tp->int_vector[0].poll = rtase_poll;
|
||||
|
||||
memset(tp->int_vector[0].name, 0x0, sizeof(tp->int_vector[0].name));
|
||||
INIT_LIST_HEAD(&tp->int_vector[0].ring_list);
|
||||
|
||||
netif_napi_add(tp->dev, &tp->int_vector[0].napi,
|
||||
tp->int_vector[0].poll);
|
||||
|
||||
/* interrupt vector 1 ~ 3 */
|
||||
for (i = 1; i < tp->int_nums; i++) {
|
||||
tp->int_vector[i].tp = tp;
|
||||
tp->int_vector[i].index = i;
|
||||
tp->int_vector[i].imr_addr = RTASE_IMR1 + (i - 1) * 4;
|
||||
tp->int_vector[i].isr_addr = RTASE_ISR1 + (i - 1) * 4;
|
||||
tp->int_vector[i].imr = RTASE_Q_ROK | RTASE_Q_RDU |
|
||||
RTASE_Q_TOK;
|
||||
tp->int_vector[i].poll = rtase_poll;
|
||||
|
||||
memset(tp->int_vector[i].name, 0x0,
|
||||
sizeof(tp->int_vector[0].name));
|
||||
INIT_LIST_HEAD(&tp->int_vector[i].ring_list);
|
||||
|
||||
netif_napi_add(tp->dev, &tp->int_vector[i].napi,
|
||||
tp->int_vector[i].poll);
|
||||
}
|
||||
}
|
||||
|
||||
static u16 rtase_calc_time_mitigation(u32 time_us)
|
||||
{
|
||||
u8 msb, time_count, time_unit;
|
||||
u16 int_miti;
|
||||
|
||||
time_us = min_t(int, time_us, RTASE_MITI_MAX_TIME);
|
||||
|
||||
msb = fls(time_us);
|
||||
if (msb >= RTASE_MITI_COUNT_BIT_NUM) {
|
||||
time_unit = msb - RTASE_MITI_COUNT_BIT_NUM;
|
||||
time_count = time_us >> (msb - RTASE_MITI_COUNT_BIT_NUM);
|
||||
} else {
|
||||
time_unit = 0;
|
||||
time_count = time_us;
|
||||
}
|
||||
|
||||
int_miti = u16_encode_bits(time_count, RTASE_MITI_TIME_COUNT_MASK) |
|
||||
u16_encode_bits(time_unit, RTASE_MITI_TIME_UNIT_MASK);
|
||||
|
||||
return int_miti;
|
||||
}
|
||||
|
||||
static u16 rtase_calc_packet_num_mitigation(u16 pkt_num)
|
||||
{
|
||||
u8 msb, pkt_num_count, pkt_num_unit;
|
||||
u16 int_miti;
|
||||
|
||||
pkt_num = min_t(int, pkt_num, RTASE_MITI_MAX_PKT_NUM);
|
||||
|
||||
if (pkt_num > 60) {
|
||||
pkt_num_unit = RTASE_MITI_MAX_PKT_NUM_IDX;
|
||||
pkt_num_count = pkt_num / RTASE_MITI_MAX_PKT_NUM_UNIT;
|
||||
} else {
|
||||
msb = fls(pkt_num);
|
||||
if (msb >= RTASE_MITI_COUNT_BIT_NUM) {
|
||||
pkt_num_unit = msb - RTASE_MITI_COUNT_BIT_NUM;
|
||||
pkt_num_count = pkt_num >> (msb -
|
||||
RTASE_MITI_COUNT_BIT_NUM);
|
||||
} else {
|
||||
pkt_num_unit = 0;
|
||||
pkt_num_count = pkt_num;
|
||||
}
|
||||
}
|
||||
|
||||
int_miti = u16_encode_bits(pkt_num_count,
|
||||
RTASE_MITI_PKT_NUM_COUNT_MASK) |
|
||||
u16_encode_bits(pkt_num_unit,
|
||||
RTASE_MITI_PKT_NUM_UNIT_MASK);
|
||||
|
||||
return int_miti;
|
||||
}
|
||||
|
||||
static void rtase_init_software_variable(struct pci_dev *pdev,
|
||||
struct rtase_private *tp)
|
||||
{
|
||||
u16 int_miti;
|
||||
|
||||
tp->tx_queue_ctrl = RTASE_TXQ_CTRL;
|
||||
tp->func_tx_queue_num = RTASE_FUNC_TXQ_NUM;
|
||||
tp->func_rx_queue_num = RTASE_FUNC_RXQ_NUM;
|
||||
tp->int_nums = RTASE_INTERRUPT_NUM;
|
||||
|
||||
int_miti = rtase_calc_time_mitigation(RTASE_MITI_DEFAULT_TIME) |
|
||||
rtase_calc_packet_num_mitigation(RTASE_MITI_DEFAULT_PKT_NUM);
|
||||
tp->tx_int_mit = int_miti;
|
||||
tp->rx_int_mit = int_miti;
|
||||
|
||||
tp->sw_flag = 0;
|
||||
|
||||
rtase_init_int_vector(tp);
|
||||
|
||||
/* MTU range: 60 - hw-specific max */
|
||||
tp->dev->min_mtu = ETH_ZLEN;
|
||||
tp->dev->max_mtu = RTASE_MAX_JUMBO_SIZE;
|
||||
}
|
||||
|
||||
static bool rtase_check_mac_version_valid(struct rtase_private *tp)
|
||||
{
|
||||
u32 hw_ver = rtase_r32(tp, RTASE_TX_CONFIG_0) & RTASE_HW_VER_MASK;
|
||||
bool known_ver = false;
|
||||
|
||||
switch (hw_ver) {
|
||||
case 0x00800000:
|
||||
case 0x04000000:
|
||||
case 0x04800000:
|
||||
known_ver = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return known_ver;
|
||||
}
|
||||
|
||||
static int rtase_init_board(struct pci_dev *pdev, struct net_device **dev_out,
|
||||
void __iomem **ioaddr_out)
|
||||
{
|
||||
struct net_device *dev;
|
||||
void __iomem *ioaddr;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* dev zeroed in alloc_etherdev */
|
||||
dev = alloc_etherdev_mq(sizeof(struct rtase_private),
|
||||
RTASE_FUNC_TXQ_NUM);
|
||||
if (!dev)
|
||||
goto err_out;
|
||||
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret < 0)
|
||||
goto err_out_free_dev;
|
||||
|
||||
/* make sure PCI base addr 1 is MMIO */
|
||||
if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
|
||||
ret = -ENODEV;
|
||||
goto err_out_disable;
|
||||
}
|
||||
|
||||
/* check for weird/broken PCI region reporting */
|
||||
if (pci_resource_len(pdev, 2) < RTASE_REGS_SIZE) {
|
||||
ret = -ENODEV;
|
||||
goto err_out_disable;
|
||||
}
|
||||
|
||||
ret = pci_request_regions(pdev, KBUILD_MODNAME);
|
||||
if (ret < 0)
|
||||
goto err_out_disable;
|
||||
|
||||
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
|
||||
dev_err(&pdev->dev, "no usable dma addressing method\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* ioremap MMIO region */
|
||||
ioaddr = ioremap(pci_resource_start(pdev, 2),
|
||||
pci_resource_len(pdev, 2));
|
||||
if (!ioaddr) {
|
||||
ret = -EIO;
|
||||
goto err_out_free_res;
|
||||
}
|
||||
|
||||
*ioaddr_out = ioaddr;
|
||||
*dev_out = dev;
|
||||
|
||||
return ret;
|
||||
|
||||
err_out_free_res:
|
||||
pci_release_regions(pdev);
|
||||
|
||||
err_out_disable:
|
||||
pci_disable_device(pdev);
|
||||
|
||||
err_out_free_dev:
|
||||
free_netdev(dev);
|
||||
|
||||
err_out:
|
||||
*ioaddr_out = NULL;
|
||||
*dev_out = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rtase_release_board(struct pci_dev *pdev, struct net_device *dev,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
const struct rtase_private *tp = netdev_priv(dev);
|
||||
|
||||
rtase_rar_set(tp, tp->dev->perm_addr);
|
||||
iounmap(ioaddr);
|
||||
|
||||
if (tp->sw_flag & RTASE_SWF_MSIX_ENABLED)
|
||||
pci_disable_msix(pdev);
|
||||
else
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
static int rtase_init_one(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct net_device *dev = NULL;
|
||||
struct rtase_int_vector *ivec;
|
||||
void __iomem *ioaddr = NULL;
|
||||
struct rtase_private *tp;
|
||||
int ret, i;
|
||||
|
||||
if (!pdev->is_physfn && pdev->is_virtfn) {
|
||||
dev_err(&pdev->dev,
|
||||
"This module does not support a virtual function.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "Automotive Switch Ethernet driver loaded\n");
|
||||
|
||||
ret = rtase_init_board(pdev, &dev, &ioaddr);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
tp = netdev_priv(dev);
|
||||
tp->mmio_addr = ioaddr;
|
||||
tp->dev = dev;
|
||||
tp->pdev = pdev;
|
||||
|
||||
/* identify chip attached to board */
|
||||
if (!rtase_check_mac_version_valid(tp))
|
||||
return dev_err_probe(&pdev->dev, -ENODEV,
|
||||
"unknown chip version, contact rtase maintainers (see MAINTAINERS file)\n");
|
||||
|
||||
rtase_init_software_variable(pdev, tp);
|
||||
rtase_init_hardware(tp);
|
||||
|
||||
ret = rtase_alloc_interrupt(pdev, tp);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "unable to alloc MSIX/MSI\n");
|
||||
goto err_out_1;
|
||||
}
|
||||
|
||||
rtase_init_netdev_ops(dev);
|
||||
|
||||
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
|
||||
|
||||
dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
|
||||
NETIF_F_IP_CSUM | NETIF_F_HIGHDMA |
|
||||
NETIF_F_RXCSUM | NETIF_F_SG |
|
||||
NETIF_F_TSO | NETIF_F_IPV6_CSUM |
|
||||
NETIF_F_TSO6;
|
||||
|
||||
dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
|
||||
NETIF_F_TSO | NETIF_F_RXCSUM |
|
||||
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
|
||||
NETIF_F_RXALL | NETIF_F_RXFCS |
|
||||
NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
|
||||
|
||||
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
|
||||
NETIF_F_HIGHDMA;
|
||||
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
|
||||
netif_set_tso_max_size(dev, RTASE_LSO_64K);
|
||||
netif_set_tso_max_segs(dev, RTASE_NIC_MAX_PHYS_BUF_COUNT_LSO2);
|
||||
|
||||
rtase_get_mac_address(dev);
|
||||
|
||||
tp->tally_vaddr = dma_alloc_coherent(&pdev->dev,
|
||||
sizeof(*tp->tally_vaddr),
|
||||
&tp->tally_paddr,
|
||||
GFP_KERNEL);
|
||||
if (!tp->tally_vaddr) {
|
||||
ret = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
rtase_tally_counter_clear(tp);
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
netif_carrier_off(dev);
|
||||
|
||||
ret = register_netdev(dev);
|
||||
if (ret != 0)
|
||||
goto err_out;
|
||||
|
||||
netdev_dbg(dev, "%pM, IRQ %d\n", dev->dev_addr, dev->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
if (tp->tally_vaddr) {
|
||||
dma_free_coherent(&pdev->dev,
|
||||
sizeof(*tp->tally_vaddr),
|
||||
tp->tally_vaddr,
|
||||
tp->tally_paddr);
|
||||
|
||||
tp->tally_vaddr = NULL;
|
||||
}
|
||||
|
||||
err_out_1:
|
||||
for (i = 0; i < tp->int_nums; i++) {
|
||||
ivec = &tp->int_vector[i];
|
||||
netif_napi_del(&ivec->napi);
|
||||
}
|
||||
|
||||
rtase_release_board(pdev, dev, ioaddr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rtase_remove_one(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtase_private *tp = netdev_priv(dev);
|
||||
struct rtase_int_vector *ivec;
|
||||
u32 i;
|
||||
|
||||
unregister_netdev(dev);
|
||||
|
||||
for (i = 0; i < tp->int_nums; i++) {
|
||||
ivec = &tp->int_vector[i];
|
||||
netif_napi_del(&ivec->napi);
|
||||
}
|
||||
|
||||
rtase_reset_interrupt(pdev, tp);
|
||||
if (tp->tally_vaddr) {
|
||||
dma_free_coherent(&pdev->dev,
|
||||
sizeof(*tp->tally_vaddr),
|
||||
tp->tally_vaddr,
|
||||
tp->tally_paddr);
|
||||
tp->tally_vaddr = NULL;
|
||||
}
|
||||
|
||||
rtase_release_board(pdev, dev, tp->mmio_addr);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
static void rtase_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
const struct rtase_private *tp;
|
||||
|
||||
tp = netdev_priv(dev);
|
||||
|
||||
if (netif_running(dev))
|
||||
rtase_close(dev);
|
||||
|
||||
rtase_reset_interrupt(pdev, tp);
|
||||
}
|
||||
|
||||
static struct pci_driver rtase_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = rtase_pci_tbl,
|
||||
.probe = rtase_init_one,
|
||||
.remove = rtase_remove_one,
|
||||
.shutdown = rtase_shutdown,
|
||||
};
|
||||
|
||||
module_pci_driver(rtase_pci_driver);
|
Loading…
Reference in New Issue
Block a user