Merge branch 'add-functions-for-txgbe-aml-devices'

Jiawen Wu says:

====================
Support phylink and link/gpio irqs for AML 25G/10G devices, and complete
PTP and SRIOV.
====================

Link: https://patch.msgid.link/
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2025-05-26 17:25:45 +02:00
commit e272bbc9bf
18 changed files with 833 additions and 115 deletions

View File

@ -219,7 +219,7 @@ int wx_nway_reset(struct net_device *netdev)
{
struct wx *wx = netdev_priv(netdev);
if (wx->mac.type == wx_mac_aml)
if (wx->mac.type == wx_mac_aml40)
return -EOPNOTSUPP;
return phylink_ethtool_nway_reset(wx->phylink);
@ -231,9 +231,6 @@ int wx_get_link_ksettings(struct net_device *netdev,
{
struct wx *wx = netdev_priv(netdev);
if (wx->mac.type == wx_mac_aml)
return -EOPNOTSUPP;
return phylink_ethtool_ksettings_get(wx->phylink, cmd);
}
EXPORT_SYMBOL(wx_get_link_ksettings);
@ -243,7 +240,7 @@ int wx_set_link_ksettings(struct net_device *netdev,
{
struct wx *wx = netdev_priv(netdev);
if (wx->mac.type == wx_mac_aml)
if (wx->mac.type == wx_mac_aml40)
return -EOPNOTSUPP;
return phylink_ethtool_ksettings_set(wx->phylink, cmd);
@ -255,7 +252,7 @@ void wx_get_pauseparam(struct net_device *netdev,
{
struct wx *wx = netdev_priv(netdev);
if (wx->mac.type == wx_mac_aml)
if (wx->mac.type == wx_mac_aml40)
return;
phylink_ethtool_get_pauseparam(wx->phylink, pause);
@ -267,7 +264,7 @@ int wx_set_pauseparam(struct net_device *netdev,
{
struct wx *wx = netdev_priv(netdev);
if (wx->mac.type == wx_mac_aml)
if (wx->mac.type == wx_mac_aml40)
return -EOPNOTSUPP;
return phylink_ethtool_set_pauseparam(wx->phylink, pause);
@ -345,6 +342,7 @@ int wx_set_coalesce(struct net_device *netdev,
max_eitr = WX_SP_MAX_EITR;
break;
case wx_mac_aml:
case wx_mac_aml40:
max_eitr = WX_AML_MAX_EITR;
break;
default:
@ -375,6 +373,7 @@ int wx_set_coalesce(struct net_device *netdev,
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
case wx_mac_aml40:
tx_itr_param = WX_12K_ITR;
break;
default:
@ -413,15 +412,10 @@ static unsigned int wx_max_channels(struct wx *wx)
max_combined = 1;
} else {
/* support up to max allowed queues with RSS */
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
max_combined = 63;
break;
default:
else
max_combined = 8;
break;
}
}
return max_combined;

View File

@ -113,15 +113,10 @@ static void wx_intr_disable(struct wx *wx, u64 qmask)
if (mask)
wr32(wx, WX_PX_IMS(0), mask);
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
mask = (qmask >> 32);
if (mask)
wr32(wx, WX_PX_IMS(1), mask);
break;
default:
break;
}
}
@ -133,15 +128,10 @@ void wx_intr_enable(struct wx *wx, u64 qmask)
if (mask)
wr32(wx, WX_PX_IMC(0), mask);
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
mask = (qmask >> 32);
if (mask)
wr32(wx, WX_PX_IMC(1), mask);
break;
default:
break;
}
}
EXPORT_SYMBOL(wx_intr_enable);
@ -705,6 +695,7 @@ void wx_init_eeprom_params(struct wx *wx)
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
case wx_mac_aml40:
if (wx_read_ee_hostif(wx, WX_SW_REGION_PTR, &data)) {
wx_err(wx, "NVM Read Error\n");
return;
@ -774,14 +765,8 @@ static int wx_set_rar(struct wx *wx, u32 index, u8 *addr, u64 pools,
/* setup VMDq pool mapping */
wr32(wx, WX_PSR_MAC_SWC_VM_L, pools & 0xFFFFFFFF);
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
wr32(wx, WX_PSR_MAC_SWC_VM_H, pools >> 32);
break;
default:
break;
}
/* HW expects these in little endian so we reverse the byte
* order from network order (big endian) to little endian
@ -919,14 +904,9 @@ void wx_init_rx_addrs(struct wx *wx)
wx_set_rar(wx, 0, wx->mac.addr, 0, WX_PSR_MAC_SWC_AD_H_AV);
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
/* clear VMDq pool/queue selection for RAR 0 */
wx_clear_vmdq(wx, 0, WX_CLEAR_VMDQ_ALL);
break;
default:
break;
}
}
@ -1512,7 +1492,7 @@ static void wx_configure_virtualization(struct wx *wx)
wr32m(wx, WX_PSR_VM_L2CTL(pool),
WX_PSR_VM_L2CTL_AUPE, WX_PSR_VM_L2CTL_AUPE);
if (wx->mac.type == wx_mac_em) {
if (!test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
vf_shift = BIT(VMDQ_P(0));
/* Enable only the PF pools for Tx/Rx */
wr32(wx, WX_RDM_VF_RE(0), vf_shift);
@ -1543,7 +1523,7 @@ static void wx_configure_port(struct wx *wx)
{
u32 value, i;
if (wx->mac.type == wx_mac_em) {
if (!test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
value = (wx->num_vfs == 0) ?
WX_CFG_PORT_CTL_NUM_VT_NONE :
WX_CFG_PORT_CTL_NUM_VT_8;
@ -2074,7 +2054,7 @@ static void wx_setup_psrtype(struct wx *wx)
WX_RDB_PL_CFG_TUN_OUTL2HDR |
WX_RDB_PL_CFG_TUN_TUNHDR;
if (wx->mac.type == wx_mac_em) {
if (!test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
for_each_set_bit(pool, &wx->fwd_bitmask, 8)
wr32(wx, WX_RDB_PL_CFG(VMDQ_P(pool)), psrtype);
} else {
@ -2272,10 +2252,8 @@ int wx_stop_adapter(struct wx *wx)
}
EXPORT_SYMBOL(wx_stop_adapter);
void wx_reset_misc(struct wx *wx)
void wx_reset_mac(struct wx *wx)
{
int i;
/* receive packets that size > 2048 */
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_JE, WX_MAC_RX_CFG_JE);
@ -2287,6 +2265,14 @@ void wx_reset_misc(struct wx *wx)
WX_MAC_RX_FLOW_CTRL_RFE, WX_MAC_RX_FLOW_CTRL_RFE);
wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
}
EXPORT_SYMBOL(wx_reset_mac);
void wx_reset_misc(struct wx *wx)
{
int i;
wx_reset_mac(wx);
wr32m(wx, WX_MIS_RST_ST,
WX_MIS_RST_ST_RST_INIT, 0x1E00);

View File

@ -42,6 +42,7 @@ void wx_configure(struct wx *wx);
void wx_start_hw(struct wx *wx);
int wx_disable_pcie_master(struct wx *wx);
int wx_stop_adapter(struct wx *wx);
void wx_reset_mac(struct wx *wx);
void wx_reset_misc(struct wx *wx);
int wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count);
int wx_sw_init(struct wx *wx);

View File

@ -5,6 +5,7 @@
#include <net/ip6_checksum.h>
#include <net/page_pool/helpers.h>
#include <net/inet_ecn.h>
#include <linux/workqueue.h>
#include <linux/iopoll.h>
#include <linux/sctp.h>
#include <linux/pci.h>
@ -1633,7 +1634,7 @@ static bool wx_set_vmdq_queues(struct wx *wx)
/* Add starting offset to total pool count */
vmdq_i += wx->ring_feature[RING_F_VMDQ].offset;
if (wx->mac.type == wx_mac_sp) {
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
/* double check we are limited to maximum pools */
vmdq_i = min_t(u16, 64, vmdq_i);
@ -1693,7 +1694,7 @@ static void wx_set_rss_queues(struct wx *wx)
/* set mask for 16 queue limit of RSS */
f = &wx->ring_feature[RING_F_RSS];
if (wx->mac.type == wx_mac_sp)
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
f->mask = WX_RSS_64Q_MASK;
else
f->mask = WX_RSS_8Q_MASK;
@ -1853,7 +1854,7 @@ static bool wx_cache_ring_vmdq(struct wx *wx)
if (!test_bit(WX_FLAG_VMDQ_ENABLED, wx->flags))
return false;
if (wx->mac.type == wx_mac_sp) {
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
/* start at VMDq register offset for SR-IOV enabled setups */
reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
for (i = 0; i < wx->num_rx_queues; i++, reg_idx++) {
@ -1959,6 +1960,7 @@ static int wx_alloc_q_vector(struct wx *wx,
switch (wx->mac.type) {
case wx_mac_sp:
case wx_mac_aml:
case wx_mac_aml40:
default_itr = WX_12K_ITR;
break;
default:
@ -2327,6 +2329,7 @@ void wx_write_eitr(struct wx_q_vector *q_vector)
itr_reg = q_vector->itr & WX_SP_MAX_EITR;
break;
case wx_mac_aml:
case wx_mac_aml40:
itr_reg = (q_vector->itr >> 3) & WX_AML_MAX_EITR;
break;
default:
@ -2354,10 +2357,10 @@ void wx_configure_vectors(struct wx *wx)
if (pdev->msix_enabled) {
/* Populate MSIX to EITR Select */
if (wx->mac.type == wx_mac_sp) {
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
if (wx->num_vfs >= 32)
eitrsel = BIT(wx->num_vfs % 32) - 1;
} else if (wx->mac.type == wx_mac_em) {
} else {
for (i = 0; i < wx->num_vfs; i++)
eitrsel |= BIT(i);
}
@ -3093,5 +3096,35 @@ void wx_set_ring(struct wx *wx, u32 new_tx_count,
}
EXPORT_SYMBOL(wx_set_ring);
void wx_service_event_schedule(struct wx *wx)
{
if (!test_and_set_bit(WX_STATE_SERVICE_SCHED, wx->state))
queue_work(system_power_efficient_wq, &wx->service_task);
}
EXPORT_SYMBOL(wx_service_event_schedule);
void wx_service_event_complete(struct wx *wx)
{
if (WARN_ON(!test_bit(WX_STATE_SERVICE_SCHED, wx->state)))
return;
/* flush memory to make sure state is correct before next watchdog */
smp_mb__before_atomic();
clear_bit(WX_STATE_SERVICE_SCHED, wx->state);
}
EXPORT_SYMBOL(wx_service_event_complete);
void wx_service_timer(struct timer_list *t)
{
struct wx *wx = from_timer(wx, t, service_timer);
unsigned long next_event_offset = HZ * 2;
/* Reset the timer */
mod_timer(&wx->service_timer, next_event_offset + jiffies);
wx_service_event_schedule(wx);
}
EXPORT_SYMBOL(wx_service_timer);
MODULE_DESCRIPTION("Common library for Wangxun(R) Ethernet drivers.");
MODULE_LICENSE("GPL");

View File

@ -38,5 +38,8 @@ netdev_features_t wx_features_check(struct sk_buff *skb,
netdev_features_t features);
void wx_set_ring(struct wx *wx, u32 new_tx_count,
u32 new_rx_count, struct wx_ring *temp_ring);
void wx_service_event_schedule(struct wx *wx);
void wx_service_event_complete(struct wx *wx);
void wx_service_timer(struct timer_list *t);
#endif /* _WX_LIB_H_ */

View File

@ -15,12 +15,14 @@
#define WX_INCVAL_100 0xA00000
#define WX_INCVAL_10 0xC7F380
#define WX_INCVAL_EM 0x2000000
#define WX_INCVAL_AML 0xA00000
#define WX_INCVAL_SHIFT_10GB 20
#define WX_INCVAL_SHIFT_1GB 18
#define WX_INCVAL_SHIFT_100 15
#define WX_INCVAL_SHIFT_10 12
#define WX_INCVAL_SHIFT_EM 22
#define WX_INCVAL_SHIFT_AML 21
#define WX_OVERFLOW_PERIOD (HZ * 30)
#define WX_PTP_TX_TIMEOUT (HZ)
@ -504,15 +506,27 @@ static long wx_ptp_create_clock(struct wx *wx)
wx->ptp_caps.gettimex64 = wx_ptp_gettimex64;
wx->ptp_caps.settime64 = wx_ptp_settime64;
wx->ptp_caps.do_aux_work = wx_ptp_do_aux_work;
if (wx->mac.type == wx_mac_em) {
switch (wx->mac.type) {
case wx_mac_aml:
case wx_mac_aml40:
wx->ptp_caps.max_adj = 250000000;
wx->ptp_caps.n_per_out = 1;
wx->ptp_setup_sdp = wx_ptp_setup_sdp;
wx->ptp_caps.enable = wx_ptp_feature_enable;
break;
case wx_mac_sp:
wx->ptp_caps.max_adj = 250000000;
wx->ptp_caps.n_per_out = 0;
wx->ptp_setup_sdp = NULL;
break;
case wx_mac_em:
wx->ptp_caps.max_adj = 500000000;
wx->ptp_caps.n_per_out = 1;
wx->ptp_setup_sdp = wx_ptp_setup_sdp;
wx->ptp_caps.enable = wx_ptp_feature_enable;
} else {
wx->ptp_caps.max_adj = 250000000;
wx->ptp_caps.n_per_out = 0;
wx->ptp_setup_sdp = NULL;
break;
default:
return -EOPNOTSUPP;
}
wx->ptp_clock = ptp_clock_register(&wx->ptp_caps, &wx->pdev->dev);
@ -647,10 +661,18 @@ static u64 wx_ptp_read(const struct cyclecounter *hw_cc)
static void wx_ptp_link_speed_adjust(struct wx *wx, u32 *shift, u32 *incval)
{
if (wx->mac.type == wx_mac_em) {
switch (wx->mac.type) {
case wx_mac_aml:
case wx_mac_aml40:
*shift = WX_INCVAL_SHIFT_AML;
*incval = WX_INCVAL_AML;
return;
case wx_mac_em:
*shift = WX_INCVAL_SHIFT_EM;
*incval = WX_INCVAL_EM;
return;
default:
break;
}
switch (wx->speed) {

View File

@ -106,7 +106,7 @@ static int __wx_enable_sriov(struct wx *wx, u8 num_vfs)
wx->vfinfo[i].xcast_mode = WXVF_XCAST_MODE_NONE;
}
if (wx->mac.type == wx_mac_em) {
if (!test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
value = WX_CFG_PORT_CTL_NUM_VT_8;
} else {
if (num_vfs < 32)
@ -599,10 +599,10 @@ static int wx_set_vf_vlan_msg(struct wx *wx, u32 *msgbuf, u16 vf)
if (VMDQ_P(0) < 32) {
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L);
bits &= ~BIT(VMDQ_P(0));
if (wx->mac.type != wx_mac_em)
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_H);
} else {
if (wx->mac.type != wx_mac_em)
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H);
bits &= ~BIT(VMDQ_P(0) % 32);
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_L);
@ -848,7 +848,7 @@ void wx_disable_vf_rx_tx(struct wx *wx)
{
wr32(wx, WX_TDM_VFTE_CLR(0), U32_MAX);
wr32(wx, WX_RDM_VFRE_CLR(0), U32_MAX);
if (wx->mac.type != wx_mac_em) {
if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
wr32(wx, WX_TDM_VFTE_CLR(1), U32_MAX);
wr32(wx, WX_RDM_VFRE_CLR(1), U32_MAX);
}

View File

@ -838,13 +838,14 @@ enum wx_mac_type {
wx_mac_sp,
wx_mac_em,
wx_mac_aml,
wx_mac_aml40,
};
enum sp_media_type {
sp_media_unknown = 0,
sp_media_fiber,
sp_media_copper,
sp_media_backplane
enum wx_media_type {
wx_media_unknown = 0,
wx_media_fiber,
wx_media_copper,
wx_media_backplane
};
enum em_mac_type {
@ -1153,6 +1154,7 @@ enum wx_state {
WX_STATE_SWFW_BUSY,
WX_STATE_PTP_RUNNING,
WX_STATE_PTP_TX_IN_PROGRESS,
WX_STATE_SERVICE_SCHED,
WX_STATE_NBITS /* must be last */
};
@ -1184,6 +1186,7 @@ struct vf_macvlans {
};
enum wx_pf_flags {
WX_FLAG_MULTI_64_FUNC,
WX_FLAG_SWFW_RING,
WX_FLAG_VMDQ_ENABLED,
WX_FLAG_VLAN_PROMISC,
@ -1195,6 +1198,8 @@ enum wx_pf_flags {
WX_FLAG_RX_HWTSTAMP_ENABLED,
WX_FLAG_RX_HWTSTAMP_IN_REGISTER,
WX_FLAG_PTP_PPS_ENABLED,
WX_FLAG_NEED_LINK_CONFIG,
WX_FLAG_NEED_SFP_RESET,
WX_PF_FLAGS_NBITS /* must be last */
};
@ -1211,7 +1216,7 @@ struct wx {
struct wx_mbx_info mbx;
struct wx_mac_info mac;
enum em_mac_type mac_type;
enum sp_media_type media_type;
enum wx_media_type media_type;
struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl;
struct wx_fc_info fc;
@ -1233,6 +1238,8 @@ struct wx {
/* PHY stuff */
bool notify_down;
int adv_speed;
int adv_duplex;
unsigned int link;
int speed;
int duplex;
@ -1330,6 +1337,9 @@ struct wx {
struct ptp_clock_info ptp_caps;
struct kernel_hwtstamp_config tstamp_config;
struct sk_buff *ptp_tx_skb;
struct timer_list service_timer;
struct work_struct service_task;
};
#define WX_INTR_ALL (~0ULL)

View File

@ -11,4 +11,5 @@ txgbe-objs := txgbe_main.o \
txgbe_phy.o \
txgbe_irq.o \
txgbe_fdir.o \
txgbe_ethtool.o
txgbe_ethtool.o \
txgbe_aml.o

View File

@ -0,0 +1,385 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
#include <linux/phylink.h>
#include <linux/iopoll.h>
#include <linux/pci.h>
#include <linux/phy.h>
#include "../libwx/wx_type.h"
#include "../libwx/wx_lib.h"
#include "../libwx/wx_ptp.h"
#include "../libwx/wx_hw.h"
#include "../libwx/wx_sriov.h"
#include "txgbe_type.h"
#include "txgbe_aml.h"
#include "txgbe_hw.h"
void txgbe_gpio_init_aml(struct wx *wx)
{
u32 status;
wr32(wx, WX_GPIO_INTTYPE_LEVEL, TXGBE_GPIOBIT_2 | TXGBE_GPIOBIT_3);
wr32(wx, WX_GPIO_INTEN, TXGBE_GPIOBIT_2 | TXGBE_GPIOBIT_3);
status = rd32(wx, WX_GPIO_INTSTATUS);
for (int i = 0; i < 6; i++) {
if (status & BIT(i))
wr32(wx, WX_GPIO_EOI, BIT(i));
}
}
irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data)
{
struct txgbe *txgbe = data;
struct wx *wx = txgbe->wx;
u32 status;
wr32(wx, WX_GPIO_INTMASK, 0xFF);
status = rd32(wx, WX_GPIO_INTSTATUS);
if (status & TXGBE_GPIOBIT_2) {
set_bit(WX_FLAG_NEED_SFP_RESET, wx->flags);
wr32(wx, WX_GPIO_EOI, TXGBE_GPIOBIT_2);
wx_service_event_schedule(wx);
}
if (status & TXGBE_GPIOBIT_3) {
set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
wx_service_event_schedule(wx);
wr32(wx, WX_GPIO_EOI, TXGBE_GPIOBIT_3);
}
wr32(wx, WX_GPIO_INTMASK, 0);
return IRQ_HANDLED;
}
int txgbe_test_hostif(struct wx *wx)
{
struct txgbe_hic_ephy_getlink buffer;
if (wx->mac.type != wx_mac_aml)
return 0;
buffer.hdr.cmd = FW_PHY_GET_LINK_CMD;
buffer.hdr.buf_len = sizeof(struct txgbe_hic_ephy_getlink) -
sizeof(struct wx_hic_hdr);
buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
return wx_host_interface_command(wx, (u32 *)&buffer, sizeof(buffer),
WX_HI_COMMAND_TIMEOUT, true);
}
static int txgbe_identify_sfp_hostif(struct wx *wx, struct txgbe_hic_i2c_read *buffer)
{
buffer->hdr.cmd = FW_READ_SFP_INFO_CMD;
buffer->hdr.buf_len = sizeof(struct txgbe_hic_i2c_read) -
sizeof(struct wx_hic_hdr);
buffer->hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
return wx_host_interface_command(wx, (u32 *)buffer,
sizeof(struct txgbe_hic_i2c_read),
WX_HI_COMMAND_TIMEOUT, true);
}
static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int duplex)
{
struct txgbe_hic_ephy_setlink buffer;
buffer.hdr.cmd = FW_PHY_SET_LINK_CMD;
buffer.hdr.buf_len = sizeof(struct txgbe_hic_ephy_setlink) -
sizeof(struct wx_hic_hdr);
buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
switch (speed) {
case SPEED_25000:
buffer.speed = TXGBE_LINK_SPEED_25GB_FULL;
break;
case SPEED_10000:
buffer.speed = TXGBE_LINK_SPEED_10GB_FULL;
break;
}
buffer.fec_mode = TXGBE_PHY_FEC_AUTO;
buffer.autoneg = autoneg;
buffer.duplex = duplex;
return wx_host_interface_command(wx, (u32 *)&buffer, sizeof(buffer),
WX_HI_COMMAND_TIMEOUT, true);
}
static void txgbe_get_link_capabilities(struct wx *wx)
{
struct txgbe *txgbe = wx->priv;
if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->sfp_interfaces))
wx->adv_speed = SPEED_25000;
else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->sfp_interfaces))
wx->adv_speed = SPEED_10000;
else
wx->adv_speed = SPEED_UNKNOWN;
wx->adv_duplex = wx->adv_speed == SPEED_UNKNOWN ?
DUPLEX_HALF : DUPLEX_FULL;
}
static void txgbe_get_phy_link(struct wx *wx, int *speed)
{
u32 status;
status = rd32(wx, TXGBE_CFG_PORT_ST);
if (!(status & TXGBE_CFG_PORT_ST_LINK_UP))
*speed = SPEED_UNKNOWN;
else if (status & TXGBE_CFG_PORT_ST_LINK_AML_25G)
*speed = SPEED_25000;
else if (status & TXGBE_CFG_PORT_ST_LINK_AML_10G)
*speed = SPEED_10000;
else
*speed = SPEED_UNKNOWN;
}
int txgbe_set_phy_link(struct wx *wx)
{
int speed, err;
u32 gpio;
/* Check RX signal */
gpio = rd32(wx, WX_GPIO_EXT);
if (gpio & TXGBE_GPIOBIT_3)
return -ENODEV;
txgbe_get_link_capabilities(wx);
if (wx->adv_speed == SPEED_UNKNOWN)
return -ENODEV;
txgbe_get_phy_link(wx, &speed);
if (speed == wx->adv_speed)
return 0;
err = txgbe_set_phy_link_hostif(wx, wx->adv_speed, 0, wx->adv_duplex);
if (err) {
wx_err(wx, "Failed to setup link\n");
return err;
}
return 0;
}
static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
DECLARE_PHY_INTERFACE_MASK(interfaces);
struct txgbe *txgbe = wx->priv;
if (id->com_25g_code & (TXGBE_SFF_25GBASESR_CAPABLE |
TXGBE_SFF_25GBASEER_CAPABLE |
TXGBE_SFF_25GBASELR_CAPABLE)) {
phylink_set(modes, 25000baseSR_Full);
__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
}
if (id->com_10g_code & TXGBE_SFF_10GBASESR_CAPABLE) {
phylink_set(modes, 10000baseSR_Full);
__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
}
if (id->com_10g_code & TXGBE_SFF_10GBASELR_CAPABLE) {
phylink_set(modes, 10000baseLR_Full);
__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
}
if (phy_interface_empty(interfaces)) {
wx_err(wx, "unsupported SFP module\n");
return -EINVAL;
}
phylink_set(modes, Pause);
phylink_set(modes, Asym_Pause);
phylink_set(modes, FIBRE);
txgbe->link_port = PORT_FIBRE;
if (!linkmode_equal(txgbe->sfp_support, modes)) {
linkmode_copy(txgbe->sfp_support, modes);
phy_interface_and(txgbe->sfp_interfaces,
wx->phylink_config.supported_interfaces,
interfaces);
linkmode_copy(txgbe->advertising, modes);
set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
}
return 0;
}
int txgbe_identify_sfp(struct wx *wx)
{
struct txgbe_hic_i2c_read buffer;
struct txgbe_sfp_id *id;
int err = 0;
u32 gpio;
gpio = rd32(wx, WX_GPIO_EXT);
if (gpio & TXGBE_GPIOBIT_2)
return -ENODEV;
err = txgbe_identify_sfp_hostif(wx, &buffer);
if (err) {
wx_err(wx, "Failed to identify SFP module\n");
return err;
}
id = &buffer.id;
if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP) {
wx_err(wx, "Invalid SFP module\n");
return -ENODEV;
}
err = txgbe_sfp_to_linkmodes(wx, id);
if (err)
return err;
if (gpio & TXGBE_GPIOBIT_3)
set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
return 0;
}
void txgbe_setup_link(struct wx *wx)
{
struct txgbe *txgbe = wx->priv;
phy_interface_zero(txgbe->sfp_interfaces);
linkmode_zero(txgbe->sfp_support);
txgbe_identify_sfp(wx);
}
static void txgbe_get_link_state(struct phylink_config *config,
struct phylink_link_state *state)
{
struct wx *wx = phylink_to_wx(config);
int speed;
txgbe_get_phy_link(wx, &speed);
state->link = speed != SPEED_UNKNOWN;
state->speed = speed;
state->duplex = state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN;
}
static void txgbe_reconfig_mac(struct wx *wx)
{
u32 wdg, fc;
wdg = rd32(wx, WX_MAC_WDG_TIMEOUT);
fc = rd32(wx, WX_MAC_RX_FLOW_CTRL);
wr32(wx, WX_MIS_RST, TXGBE_MIS_RST_MAC_RST(wx->bus.func));
/* wait for MAC reset complete */
usleep_range(1000, 1500);
wr32m(wx, TXGBE_MAC_MISC_CTL, TXGBE_MAC_MISC_CTL_LINK_STS_MOD,
TXGBE_MAC_MISC_CTL_LINK_BOTH);
wx_reset_mac(wx);
wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
wr32(wx, WX_MAC_RX_FLOW_CTRL, fc);
}
static void txgbe_mac_link_up_aml(struct phylink_config *config,
struct phy_device *phy,
unsigned int mode,
phy_interface_t interface,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct wx *wx = phylink_to_wx(config);
u32 txcfg;
wx_fc_enable(wx, tx_pause, rx_pause);
txgbe_reconfig_mac(wx);
txcfg = rd32(wx, TXGBE_AML_MAC_TX_CFG);
txcfg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;
switch (speed) {
case SPEED_25000:
txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_25G;
break;
case SPEED_10000:
txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_10G;
break;
default:
break;
}
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
wr32(wx, TXGBE_AML_MAC_TX_CFG, txcfg | TXGBE_AML_MAC_TX_CFG_TE);
wx->speed = speed;
wx->last_rx_ptp_check = jiffies;
if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
wx_ptp_reset_cyclecounter(wx);
/* ping all the active vfs to let them know we are going up */
wx_ping_all_vfs_with_link_status(wx, true);
}
static void txgbe_mac_link_down_aml(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct wx *wx = phylink_to_wx(config);
wr32m(wx, TXGBE_AML_MAC_TX_CFG, TXGBE_AML_MAC_TX_CFG_TE, 0);
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
wx->speed = SPEED_UNKNOWN;
if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
wx_ptp_reset_cyclecounter(wx);
/* ping all the active vfs to let them know we are going down */
wx_ping_all_vfs_with_link_status(wx, false);
}
static void txgbe_mac_config_aml(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
}
static const struct phylink_mac_ops txgbe_mac_ops_aml = {
.mac_config = txgbe_mac_config_aml,
.mac_link_down = txgbe_mac_link_down_aml,
.mac_link_up = txgbe_mac_link_up_aml,
};
int txgbe_phylink_init_aml(struct txgbe *txgbe)
{
struct phylink_link_state state;
struct phylink_config *config;
struct wx *wx = txgbe->wx;
phy_interface_t phy_mode;
struct phylink *phylink;
int err;
config = &wx->phylink_config;
config->dev = &wx->netdev->dev;
config->type = PHYLINK_NETDEV;
config->mac_capabilities = MAC_25000FD | MAC_10000FD |
MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
config->get_fixed_state = txgbe_get_link_state;
phy_mode = PHY_INTERFACE_MODE_25GBASER;
__set_bit(PHY_INTERFACE_MODE_25GBASER, config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
phylink = phylink_create(config, NULL, phy_mode, &txgbe_mac_ops_aml);
if (IS_ERR(phylink))
return PTR_ERR(phylink);
state.speed = SPEED_25000;
state.duplex = DUPLEX_FULL;
err = phylink_set_fixed_link(phylink, &state);
if (err) {
wx_err(wx, "Failed to set fixed link\n");
return err;
}
wx->phylink = phylink;
return 0;
}

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
#ifndef _TXGBE_AML_H_
#define _TXGBE_AML_H_
void txgbe_gpio_init_aml(struct wx *wx);
irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data);
int txgbe_test_hostif(struct wx *wx);
int txgbe_set_phy_link(struct wx *wx);
int txgbe_identify_sfp(struct wx *wx);
void txgbe_setup_link(struct wx *wx);
int txgbe_phylink_init_aml(struct txgbe *txgbe);
#endif /* _TXGBE_AML_H_ */

View File

@ -12,6 +12,31 @@
#include "txgbe_fdir.h"
#include "txgbe_ethtool.h"
int txgbe_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd)
{
struct wx *wx = netdev_priv(netdev);
struct txgbe *txgbe = wx->priv;
int err;
if (wx->mac.type == wx_mac_aml40)
return -EOPNOTSUPP;
err = wx_get_link_ksettings(netdev, cmd);
if (err)
return err;
if (wx->mac.type == wx_mac_sp)
return 0;
cmd->base.port = txgbe->link_port;
cmd->base.autoneg = AUTONEG_DISABLE;
linkmode_copy(cmd->link_modes.supported, txgbe->sfp_support);
linkmode_copy(cmd->link_modes.advertising, txgbe->advertising);
return 0;
}
static int txgbe_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@ -510,7 +535,7 @@ static const struct ethtool_ops txgbe_ethtool_ops = {
.get_drvinfo = wx_get_drvinfo,
.nway_reset = wx_nway_reset,
.get_link = ethtool_op_get_link,
.get_link_ksettings = wx_get_link_ksettings,
.get_link_ksettings = txgbe_get_link_ksettings,
.set_link_ksettings = wx_set_link_ksettings,
.get_sset_count = wx_get_sset_count,
.get_strings = wx_get_strings,

View File

@ -4,6 +4,8 @@
#ifndef _TXGBE_ETHTOOL_H_
#define _TXGBE_ETHTOOL_H_
int txgbe_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd);
void txgbe_set_ethtool_ops(struct net_device *netdev);
#endif /* _TXGBE_ETHTOOL_H_ */

View File

@ -188,7 +188,7 @@ int txgbe_reset_hw(struct wx *wx)
if (status != 0)
return status;
if (wx->media_type != sp_media_copper) {
if (wx->media_type != wx_media_copper) {
u32 val;
val = WX_MIS_RST_LAN_RST(wx->bus.func);
@ -218,7 +218,7 @@ int txgbe_reset_hw(struct wx *wx)
* clear the multicast table. Also reset num_rar_entries to 128,
* since we modify this value when programming the SAN MAC address.
*/
wx->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES;
wx->mac.num_rar_entries = TXGBE_RAR_ENTRIES;
wx_init_rx_addrs(wx);
pci_set_master(wx->pdev);

View File

@ -6,11 +6,13 @@
#include "../libwx/wx_type.h"
#include "../libwx/wx_lib.h"
#include "../libwx/wx_ptp.h"
#include "../libwx/wx_hw.h"
#include "../libwx/wx_sriov.h"
#include "txgbe_type.h"
#include "txgbe_phy.h"
#include "txgbe_irq.h"
#include "txgbe_aml.h"
/**
* txgbe_irq_enable - Enable default interrupt generation settings
@ -19,7 +21,14 @@
**/
void txgbe_irq_enable(struct wx *wx, bool queues)
{
wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK);
u32 misc_ien = TXGBE_PX_MISC_IEN_MASK;
if (wx->mac.type == wx_mac_aml) {
misc_ien |= TXGBE_PX_MISC_GPIO;
txgbe_gpio_init_aml(wx);
}
wr32(wx, WX_PX_MISC_IEN, misc_ien);
/* unmask interrupt */
wx_intr_enable(wx, TXGBE_INTR_MISC);
@ -81,6 +90,14 @@ static int txgbe_request_link_irq(struct txgbe *txgbe)
IRQF_ONESHOT, "txgbe-link-irq", txgbe);
}
static int txgbe_request_gpio_irq(struct txgbe *txgbe)
{
txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO);
return request_threaded_irq(txgbe->gpio_irq, NULL,
txgbe_gpio_irq_handler_aml,
IRQF_ONESHOT, "txgbe-gpio-irq", txgbe);
}
static const struct irq_chip txgbe_irq_chip = {
.name = "txgbe-misc-irq",
};
@ -157,6 +174,15 @@ static irqreturn_t txgbe_misc_irq_thread_fn(int irq, void *data)
handle_nested_irq(sub_irq);
nhandled++;
}
if (eicr & TXGBE_PX_MISC_GPIO) {
sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO);
handle_nested_irq(sub_irq);
nhandled++;
}
if (unlikely(eicr & TXGBE_PX_MISC_IC_TIMESYNC)) {
wx_ptp_check_pps_event(wx);
nhandled++;
}
wx_intr_enable(wx, TXGBE_INTR_MISC);
return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
@ -176,9 +202,12 @@ static void txgbe_del_irq_domain(struct txgbe *txgbe)
void txgbe_free_misc_irq(struct txgbe *txgbe)
{
if (txgbe->wx->mac.type == wx_mac_aml)
if (txgbe->wx->mac.type == wx_mac_aml40)
return;
if (txgbe->wx->mac.type == wx_mac_aml)
free_irq(txgbe->gpio_irq, txgbe);
free_irq(txgbe->link_irq, txgbe);
free_irq(txgbe->misc.irq, txgbe);
txgbe_del_irq_domain(txgbe);
@ -190,7 +219,7 @@ int txgbe_setup_misc_irq(struct txgbe *txgbe)
struct wx *wx = txgbe->wx;
int hwirq, err;
if (wx->mac.type == wx_mac_aml)
if (wx->mac.type == wx_mac_aml40)
goto skip_sp_irq;
txgbe->misc.nirqs = TXGBE_IRQ_MAX;
@ -222,11 +251,20 @@ int txgbe_setup_misc_irq(struct txgbe *txgbe)
if (err)
goto free_msic_irq;
if (wx->mac.type == wx_mac_sp)
goto skip_sp_irq;
err = txgbe_request_gpio_irq(txgbe);
if (err)
goto free_link_irq;
skip_sp_irq:
wx->misc_irq_domain = true;
return 0;
free_link_irq:
free_irq(txgbe->link_irq, txgbe);
free_msic_irq:
free_irq(txgbe->misc.irq, txgbe);
del_misc_irq:

View File

@ -21,6 +21,7 @@
#include "txgbe_type.h"
#include "txgbe_hw.h"
#include "txgbe_phy.h"
#include "txgbe_aml.h"
#include "txgbe_irq.h"
#include "txgbe_fdir.h"
#include "txgbe_ethtool.h"
@ -88,9 +89,62 @@ static int txgbe_enumerate_functions(struct wx *wx)
return physfns;
}
static void txgbe_sfp_detection_subtask(struct wx *wx)
{
int err;
if (!test_bit(WX_FLAG_NEED_SFP_RESET, wx->flags))
return;
/* wait for SFP module ready */
msleep(200);
err = txgbe_identify_sfp(wx);
if (err)
return;
clear_bit(WX_FLAG_NEED_SFP_RESET, wx->flags);
}
static void txgbe_link_config_subtask(struct wx *wx)
{
int err;
if (!test_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags))
return;
err = txgbe_set_phy_link(wx);
if (err)
return;
clear_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
}
/**
* txgbe_service_task - manages and runs subtasks
* @work: pointer to work_struct containing our data
**/
static void txgbe_service_task(struct work_struct *work)
{
struct wx *wx = container_of(work, struct wx, service_task);
txgbe_sfp_detection_subtask(wx);
txgbe_link_config_subtask(wx);
wx_service_event_complete(wx);
}
static void txgbe_init_service(struct wx *wx)
{
timer_setup(&wx->service_timer, wx_service_timer, 0);
INIT_WORK(&wx->service_task, txgbe_service_task);
clear_bit(WX_STATE_SERVICE_SCHED, wx->state);
}
static void txgbe_up_complete(struct wx *wx)
{
struct net_device *netdev = wx->netdev;
u32 reg;
wx_control_hw(wx, true);
wx_configure_vectors(wx);
@ -99,17 +153,26 @@ static void txgbe_up_complete(struct wx *wx)
smp_mb__before_atomic();
wx_napi_enable_all(wx);
if (wx->mac.type == wx_mac_aml) {
u32 reg;
switch (wx->mac.type) {
case wx_mac_aml40:
reg = rd32(wx, TXGBE_AML_MAC_TX_CFG);
reg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;
reg |= TXGBE_AML_MAC_TX_CFG_SPEED_25G;
reg |= TXGBE_AML_MAC_TX_CFG_SPEED_40G;
wr32(wx, WX_MAC_TX_CFG, reg);
txgbe_enable_sec_tx_path(wx);
netif_carrier_on(wx->netdev);
} else {
break;
case wx_mac_aml:
/* Enable TX laser */
wr32m(wx, WX_GPIO_DR, TXGBE_GPIOBIT_1, 0);
txgbe_setup_link(wx);
phylink_start(wx->phylink);
break;
case wx_mac_sp:
phylink_start(wx->phylink);
break;
default:
break;
}
/* clear any pending interrupts, may auto mask */
@ -120,6 +183,7 @@ static void txgbe_up_complete(struct wx *wx)
/* enable transmits */
netif_tx_start_all_queues(netdev);
mod_timer(&wx->service_timer, jiffies);
/* Set PF Reset Done bit so PF/VF Mail Ops can work */
wr32m(wx, WX_CFG_PORT_CTL, WX_CFG_PORT_CTL_PFRSTD,
@ -168,6 +232,8 @@ static void txgbe_disable_device(struct wx *wx)
wx_irq_disable(wx);
wx_napi_disable_all(wx);
timer_delete_sync(&wx->service_timer);
if (wx->bus.func < 2)
wr32m(wx, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wx->bus.func), 0);
else
@ -207,10 +273,22 @@ void txgbe_down(struct wx *wx)
{
txgbe_disable_device(wx);
txgbe_reset(wx);
if (wx->mac.type == wx_mac_aml)
switch (wx->mac.type) {
case wx_mac_aml40:
netif_carrier_off(wx->netdev);
else
break;
case wx_mac_aml:
phylink_stop(wx->phylink);
/* Disable TX laser */
wr32m(wx, WX_GPIO_DR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
break;
case wx_mac_sp:
phylink_stop(wx->phylink);
break;
default:
break;
}
wx_clean_all_tx_rings(wx);
wx_clean_all_rx_rings(wx);
@ -240,9 +318,11 @@ static void txgbe_init_type_code(struct wx *wx)
case TXGBE_DEV_ID_AML5110:
case TXGBE_DEV_ID_AML5025:
case TXGBE_DEV_ID_AML5125:
wx->mac.type = wx_mac_aml;
break;
case TXGBE_DEV_ID_AML5040:
case TXGBE_DEV_ID_AML5140:
wx->mac.type = wx_mac_aml;
wx->mac.type = wx_mac_aml40;
break;
default:
wx->mac.type = wx_mac_unknown;
@ -251,25 +331,25 @@ static void txgbe_init_type_code(struct wx *wx)
switch (device_type) {
case TXGBE_ID_SFP:
wx->media_type = sp_media_fiber;
wx->media_type = wx_media_fiber;
break;
case TXGBE_ID_XAUI:
case TXGBE_ID_SGMII:
wx->media_type = sp_media_copper;
wx->media_type = wx_media_copper;
break;
case TXGBE_ID_KR_KX_KX4:
case TXGBE_ID_MAC_XAUI:
case TXGBE_ID_MAC_SGMII:
wx->media_type = sp_media_backplane;
wx->media_type = wx_media_backplane;
break;
case TXGBE_ID_SFI_XAUI:
if (wx->bus.func == 0)
wx->media_type = sp_media_fiber;
wx->media_type = wx_media_fiber;
else
wx->media_type = sp_media_copper;
wx->media_type = wx_media_copper;
break;
default:
wx->media_type = sp_media_unknown;
wx->media_type = wx_media_unknown;
break;
}
}
@ -283,13 +363,13 @@ static int txgbe_sw_init(struct wx *wx)
u16 msix_count = 0;
int err;
wx->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES;
wx->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES;
wx->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES;
wx->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE;
wx->mac.vft_size = TXGBE_SP_VFT_TBL_SIZE;
wx->mac.rx_pb_size = TXGBE_SP_RX_PB_SIZE;
wx->mac.tx_pb_size = TXGBE_SP_TDB_PB_SZ;
wx->mac.num_rar_entries = TXGBE_RAR_ENTRIES;
wx->mac.max_tx_queues = TXGBE_MAX_TXQ;
wx->mac.max_rx_queues = TXGBE_MAX_RXQ;
wx->mac.mcft_size = TXGBE_MC_TBL_SIZE;
wx->mac.vft_size = TXGBE_VFT_TBL_SIZE;
wx->mac.rx_pb_size = TXGBE_RX_PB_SIZE;
wx->mac.tx_pb_size = TXGBE_TDB_PB_SZ;
/* PCI config space info */
err = wx_sw_init(wx);
@ -318,6 +398,7 @@ static int txgbe_sw_init(struct wx *wx)
wx->configure_fdir = txgbe_configure_fdir;
set_bit(WX_FLAG_RSC_CAPABLE, wx->flags);
set_bit(WX_FLAG_MULTI_64_FUNC, wx->flags);
/* enable itr by default in dynamic mode */
wx->rx_itr_setting = 1;
@ -340,6 +421,7 @@ static int txgbe_sw_init(struct wx *wx)
case wx_mac_sp:
break;
case wx_mac_aml:
case wx_mac_aml40:
set_bit(WX_FLAG_SWFW_RING, wx->flags);
wx->swfw_index = 0;
break;
@ -735,9 +817,11 @@ static int txgbe_probe(struct pci_dev *pdev,
eth_hw_addr_set(netdev, wx->mac.perm_addr);
wx_mac_set_default_filter(wx, wx->mac.perm_addr);
txgbe_init_service(wx);
err = wx_init_interrupt_scheme(wx);
if (err)
goto err_free_mac_table;
goto err_cancel_service;
/* Save off EEPROM version number and Option Rom version which
* together make a unique identify for the eeprom
@ -780,6 +864,13 @@ static int txgbe_probe(struct pci_dev *pdev,
if (etrack_id < 0x20010)
dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
err = txgbe_test_hostif(wx);
if (err != 0) {
dev_err(&pdev->dev, "Mismatched Firmware version\n");
err = -EIO;
goto err_release_hw;
}
txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
if (!txgbe) {
err = -ENOMEM;
@ -830,6 +921,9 @@ static int txgbe_probe(struct pci_dev *pdev,
err_release_hw:
wx_clear_interrupt_scheme(wx);
wx_control_hw(wx, false);
err_cancel_service:
timer_delete_sync(&wx->service_timer);
cancel_work_sync(&wx->service_task);
err_free_mac_table:
kfree(wx->rss_key);
kfree(wx->mac_table);
@ -856,6 +950,8 @@ static void txgbe_remove(struct pci_dev *pdev)
struct txgbe *txgbe = wx->priv;
struct net_device *netdev;
cancel_work_sync(&wx->service_task);
netdev = wx->netdev;
wx_disable_sriov(wx);
unregister_netdev(netdev);

View File

@ -20,6 +20,7 @@
#include "../libwx/wx_mbx.h"
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_aml.h"
#include "txgbe_phy.h"
#include "txgbe_hw.h"
@ -165,7 +166,7 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
struct wx *wx = phylink_to_wx(config);
struct txgbe *txgbe = wx->priv;
if (wx->media_type != sp_media_copper)
if (wx->media_type != wx_media_copper)
return txgbe->pcs;
return NULL;
@ -278,7 +279,7 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
if (wx->media_type == sp_media_copper) {
if (wx->media_type == wx_media_copper) {
phy_mode = PHY_INTERFACE_MODE_XAUI;
__set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
} else {
@ -318,7 +319,10 @@ irqreturn_t txgbe_link_irq_handler(int irq, void *data)
status = rd32(wx, TXGBE_CFG_PORT_ST);
up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP);
phylink_pcs_change(txgbe->pcs, up);
if (txgbe->pcs)
phylink_pcs_change(txgbe->pcs, up);
else
phylink_mac_change(wx->phylink, up);
return IRQ_HANDLED;
}
@ -573,11 +577,18 @@ int txgbe_init_phy(struct txgbe *txgbe)
struct wx *wx = txgbe->wx;
int ret;
if (wx->mac.type == wx_mac_aml)
switch (wx->mac.type) {
case wx_mac_aml40:
return 0;
if (txgbe->wx->media_type == sp_media_copper)
return txgbe_ext_phy_init(txgbe);
case wx_mac_aml:
return txgbe_phylink_init_aml(txgbe);
case wx_mac_sp:
if (wx->media_type == wx_media_copper)
return txgbe_ext_phy_init(txgbe);
break;
default:
break;
}
ret = txgbe_swnodes_register(txgbe);
if (ret) {
@ -640,13 +651,21 @@ int txgbe_init_phy(struct txgbe *txgbe)
void txgbe_remove_phy(struct txgbe *txgbe)
{
if (txgbe->wx->mac.type == wx_mac_aml)
switch (txgbe->wx->mac.type) {
case wx_mac_aml40:
return;
if (txgbe->wx->media_type == sp_media_copper) {
phylink_disconnect_phy(txgbe->wx->phylink);
case wx_mac_aml:
phylink_destroy(txgbe->wx->phylink);
return;
case wx_mac_sp:
if (txgbe->wx->media_type == wx_media_copper) {
phylink_disconnect_phy(txgbe->wx->phylink);
phylink_destroy(txgbe->wx->phylink);
return;
}
break;
default:
break;
}
platform_device_unregister(txgbe->sfp_dev);

View File

@ -6,6 +6,8 @@
#include <linux/property.h>
#include <linux/irq.h>
#include <linux/phy.h>
#include "../libwx/wx_type.h"
/* Device IDs */
#define TXGBE_DEV_ID_SP1000 0x1001
@ -50,6 +52,8 @@
/**************** SP Registers ****************************/
/* chip control Registers */
#define TXGBE_MIS_RST 0x1000C
#define TXGBE_MIS_RST_MAC_RST(_i) BIT(20 - (_i) * 3)
#define TXGBE_MIS_PRB_CTL 0x10010
#define TXGBE_MIS_PRB_CTL_LAN_UP(_i) BIT(1 - (_i))
/* FMGR Registers */
@ -62,6 +66,11 @@
#define TXGBE_TS_CTL 0x10300
#define TXGBE_TS_CTL_EVAL_MD BIT(31)
/* MAC Misc Registers */
#define TXGBE_MAC_MISC_CTL 0x11F00
#define TXGBE_MAC_MISC_CTL_LINK_STS_MOD BIT(0)
#define TXGBE_MAC_MISC_CTL_LINK_PCS FIELD_PREP(BIT(0), 0)
#define TXGBE_MAC_MISC_CTL_LINK_BOTH FIELD_PREP(BIT(0), 1)
/* GPIO register bit */
#define TXGBE_GPIOBIT_0 BIT(0) /* I:tx fault */
#define TXGBE_GPIOBIT_1 BIT(1) /* O:tx disabled */
@ -73,6 +82,7 @@
/* Extended Interrupt Enable Set */
#define TXGBE_PX_MISC_ETH_LKDN BIT(8)
#define TXGBE_PX_MISC_DEV_RST BIT(10)
#define TXGBE_PX_MISC_IC_TIMESYNC BIT(11)
#define TXGBE_PX_MISC_ETH_EVENT BIT(17)
#define TXGBE_PX_MISC_ETH_LK BIT(18)
#define TXGBE_PX_MISC_ETH_AN BIT(19)
@ -83,11 +93,13 @@
(TXGBE_PX_MISC_ETH_LKDN | TXGBE_PX_MISC_DEV_RST | \
TXGBE_PX_MISC_ETH_EVENT | TXGBE_PX_MISC_ETH_LK | \
TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR | \
TXGBE_PX_MISC_IC_VF_MBOX)
TXGBE_PX_MISC_IC_VF_MBOX | TXGBE_PX_MISC_IC_TIMESYNC)
/* Port cfg registers */
#define TXGBE_CFG_PORT_ST 0x14404
#define TXGBE_CFG_PORT_ST_LINK_UP BIT(0)
#define TXGBE_CFG_PORT_ST_LINK_AML_25G BIT(3)
#define TXGBE_CFG_PORT_ST_LINK_AML_10G BIT(4)
#define TXGBE_CFG_VXLAN 0x14410
#define TXGBE_CFG_VXLAN_GPE 0x14414
#define TXGBE_CFG_GENEVE 0x14418
@ -151,8 +163,11 @@
/*************************** Amber Lite Registers ****************************/
#define TXGBE_PX_PF_BME 0x4B8
#define TXGBE_AML_MAC_TX_CFG 0x11000
#define TXGBE_AML_MAC_TX_CFG_TE BIT(0)
#define TXGBE_AML_MAC_TX_CFG_SPEED_MASK GENMASK(30, 27)
#define TXGBE_AML_MAC_TX_CFG_SPEED_25G BIT(28)
#define TXGBE_AML_MAC_TX_CFG_SPEED_40G FIELD_PREP(GENMASK(30, 27), 0)
#define TXGBE_AML_MAC_TX_CFG_SPEED_25G FIELD_PREP(GENMASK(30, 27), 2)
#define TXGBE_AML_MAC_TX_CFG_SPEED_10G FIELD_PREP(GENMASK(30, 27), 8)
#define TXGBE_RDM_RSC_CTL 0x1200C
#define TXGBE_RDM_RSC_CTL_FREE_CTL BIT(7)
@ -173,13 +188,13 @@
#define TXGBE_MAX_RX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1)
#define TXGBE_MAX_TX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1)
#define TXGBE_SP_MAX_TX_QUEUES 128
#define TXGBE_SP_MAX_RX_QUEUES 128
#define TXGBE_SP_RAR_ENTRIES 128
#define TXGBE_SP_MC_TBL_SIZE 128
#define TXGBE_SP_VFT_TBL_SIZE 128
#define TXGBE_SP_RX_PB_SIZE 512
#define TXGBE_SP_TDB_PB_SZ (160 * 1024) /* 160KB Packet Buffer */
#define TXGBE_MAX_TXQ 128
#define TXGBE_MAX_RXQ 128
#define TXGBE_RAR_ENTRIES 128
#define TXGBE_MC_TBL_SIZE 128
#define TXGBE_VFT_TBL_SIZE 128
#define TXGBE_RX_PB_SIZE 512
#define TXGBE_TDB_PB_SZ (160 * 1024) /* 160KB Packet Buffer */
#define TXGBE_MAX_VFS_DRV_LIMIT 63
@ -299,6 +314,72 @@ void txgbe_up(struct wx *wx);
int txgbe_setup_tc(struct net_device *dev, u8 tc);
void txgbe_do_reset(struct net_device *netdev);
#define TXGBE_LINK_SPEED_10GB_FULL 4
#define TXGBE_LINK_SPEED_25GB_FULL 0x10
#define TXGBE_SFF_IDENTIFIER_SFP 0x3
#define TXGBE_SFF_DA_PASSIVE_CABLE 0x4
#define TXGBE_SFF_DA_ACTIVE_CABLE 0x8
#define TXGBE_SFF_DA_SPEC_ACTIVE_LIMIT 0x4
#define TXGBE_SFF_FCPI4_LIMITING 0x3
#define TXGBE_SFF_10GBASESR_CAPABLE 0x10
#define TXGBE_SFF_10GBASELR_CAPABLE 0x20
#define TXGBE_SFF_25GBASESR_CAPABLE 0x2
#define TXGBE_SFF_25GBASELR_CAPABLE 0x3
#define TXGBE_SFF_25GBASEER_CAPABLE 0x4
#define TXGBE_SFF_25GBASECR_91FEC 0xB
#define TXGBE_SFF_25GBASECR_74FEC 0xC
#define TXGBE_SFF_25GBASECR_NOFEC 0xD
#define TXGBE_PHY_FEC_RS BIT(0)
#define TXGBE_PHY_FEC_BASER BIT(1)
#define TXGBE_PHY_FEC_OFF BIT(2)
#define TXGBE_PHY_FEC_AUTO (TXGBE_PHY_FEC_OFF | \
TXGBE_PHY_FEC_BASER |\
TXGBE_PHY_FEC_RS)
#define FW_PHY_GET_LINK_CMD 0xC0
#define FW_PHY_SET_LINK_CMD 0xC1
#define FW_READ_SFP_INFO_CMD 0xC5
struct txgbe_sfp_id {
u8 identifier; /* A0H 0x00 */
u8 com_1g_code; /* A0H 0x06 */
u8 com_10g_code; /* A0H 0x03 */
u8 com_25g_code; /* A0H 0x24 */
u8 cable_spec; /* A0H 0x3C */
u8 cable_tech; /* A0H 0x08 */
u8 vendor_oui0; /* A0H 0x25 */
u8 vendor_oui1; /* A0H 0x26 */
u8 vendor_oui2; /* A0H 0x27 */
u8 reserved[3];
};
struct txgbe_hic_i2c_read {
struct wx_hic_hdr hdr;
struct txgbe_sfp_id id;
};
struct txgbe_hic_ephy_setlink {
struct wx_hic_hdr hdr;
u8 speed;
u8 duplex;
u8 autoneg;
u8 fec_mode;
u8 resv[4];
};
struct txgbe_hic_ephy_getlink {
struct wx_hic_hdr hdr;
u8 speed;
u8 duplex;
u8 autoneg;
u8 flow_ctl;
u8 power;
u8 fec_mode;
u8 resv[6];
};
#define NODE_PROP(_NAME, _PROP) \
(const struct software_node) { \
.name = _NAME, \
@ -336,6 +417,7 @@ struct txgbe_nodes {
enum txgbe_misc_irqs {
TXGBE_IRQ_LINK = 0,
TXGBE_IRQ_GPIO,
TXGBE_IRQ_MAX
};
@ -357,6 +439,7 @@ struct txgbe {
struct clk *clk;
struct gpio_chip *gpio;
unsigned int link_irq;
unsigned int gpio_irq;
u32 eicr;
/* flow director */
@ -364,6 +447,11 @@ struct txgbe {
union txgbe_atr_input fdir_mask;
int fdir_filter_count;
spinlock_t fdir_perfect_lock; /* spinlock for FDIR */
DECLARE_PHY_INTERFACE_MASK(sfp_interfaces);
__ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
u8 link_port;
};
#endif /* _TXGBE_TYPE_H_ */