From c52d4b898901f697c3b0b1bc2c61480b70dcc976 Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 8 Apr 2025 17:15:53 +0800 Subject: net: libwx: Redesign flow when sriov is enabled Reallocate queue and int resources when sriov is enabled. Redefine macro VMDQ to make it work in VT mode. Signed-off-by: Mengyuan Lou Link: https://patch.msgid.link/64B616774ABE3C5A+20250408091556.9640-4-mengyuanlou@net-swift.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 128 +++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) (limited to 'drivers/net/ethernet/wangxun/libwx/wx_lib.c') diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 00b0b318df27..59d904f23764 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1618,6 +1618,65 @@ void wx_napi_disable_all(struct wx *wx) } EXPORT_SYMBOL(wx_napi_disable_all); +static bool wx_set_vmdq_queues(struct wx *wx) +{ + u16 vmdq_i = wx->ring_feature[RING_F_VMDQ].limit; + u16 rss_i = wx->ring_feature[RING_F_RSS].limit; + u16 rss_m = WX_RSS_DISABLED_MASK; + u16 vmdq_m = 0; + + /* only proceed if VMDq is enabled */ + if (!test_bit(WX_FLAG_VMDQ_ENABLED, wx->flags)) + return false; + /* Add starting offset to total pool count */ + vmdq_i += wx->ring_feature[RING_F_VMDQ].offset; + + if (wx->mac.type == wx_mac_sp) { + /* double check we are limited to maximum pools */ + vmdq_i = min_t(u16, 64, vmdq_i); + + /* 64 pool mode with 2 queues per pool, or + * 16/32/64 pool mode with 1 queue per pool + */ + if (vmdq_i > 32 || rss_i < 4) { + vmdq_m = WX_VMDQ_2Q_MASK; + rss_m = WX_RSS_2Q_MASK; + rss_i = min_t(u16, rss_i, 2); + /* 32 pool mode with 4 queues per pool */ + } else { + vmdq_m = WX_VMDQ_4Q_MASK; + rss_m = WX_RSS_4Q_MASK; + rss_i = 4; + } + } else { + /* double check we are limited to maximum pools */ + vmdq_i = min_t(u16, 8, vmdq_i); + + /* when VMDQ on, disable RSS */ + rss_i = 1; + } + + /* remove the starting offset from the pool count */ + vmdq_i -= wx->ring_feature[RING_F_VMDQ].offset; + + /* save features for later use */ + wx->ring_feature[RING_F_VMDQ].indices = vmdq_i; + wx->ring_feature[RING_F_VMDQ].mask = vmdq_m; + + /* limit RSS based on user input and save for later use */ + wx->ring_feature[RING_F_RSS].indices = rss_i; + wx->ring_feature[RING_F_RSS].mask = rss_m; + + wx->queues_per_pool = rss_i;/*maybe same to num_rx_queues_per_pool*/ + wx->num_rx_pools = vmdq_i; + wx->num_rx_queues_per_pool = rss_i; + + wx->num_rx_queues = vmdq_i * rss_i; + wx->num_tx_queues = vmdq_i * rss_i; + + return true; +} + /** * wx_set_rss_queues: Allocate queues for RSS * @wx: board private structure to initialize @@ -1632,6 +1691,10 @@ 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) + f->mask = WX_RSS_64Q_MASK; + else + f->mask = WX_RSS_8Q_MASK; f->indices = f->limit; if (!(test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags))) @@ -1664,6 +1727,9 @@ static void wx_set_num_queues(struct wx *wx) wx->num_tx_queues = 1; wx->queues_per_pool = 1; + if (wx_set_vmdq_queues(wx)) + return; + wx_set_rss_queues(wx); } @@ -1744,6 +1810,10 @@ static int wx_set_interrupt_capability(struct wx *wx) if (ret == 0 || (ret == -ENOMEM)) return ret; + /* Disable VMDq support */ + dev_warn(&wx->pdev->dev, "Disabling VMQQ support\n"); + clear_bit(WX_FLAG_VMDQ_ENABLED, wx->flags); + /* Disable RSS */ dev_warn(&wx->pdev->dev, "Disabling RSS support\n"); wx->ring_feature[RING_F_RSS].limit = 1; @@ -1770,6 +1840,49 @@ static int wx_set_interrupt_capability(struct wx *wx) return 0; } +static bool wx_cache_ring_vmdq(struct wx *wx) +{ + struct wx_ring_feature *vmdq = &wx->ring_feature[RING_F_VMDQ]; + struct wx_ring_feature *rss = &wx->ring_feature[RING_F_RSS]; + u16 reg_idx; + int i; + + /* only proceed if VMDq is enabled */ + if (!test_bit(WX_FLAG_VMDQ_ENABLED, wx->flags)) + return false; + + if (wx->mac.type == wx_mac_sp) { + /* 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++) { + /* If we are greater than indices move to next pool */ + if ((reg_idx & ~vmdq->mask) >= rss->indices) + reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask); + wx->rx_ring[i]->reg_idx = reg_idx; + } + reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask); + for (i = 0; i < wx->num_tx_queues; i++, reg_idx++) { + /* If we are greater than indices move to next pool */ + if ((reg_idx & rss->mask) >= rss->indices) + reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask); + wx->tx_ring[i]->reg_idx = reg_idx; + } + } else { + /* start at VMDq register offset for SR-IOV enabled setups */ + reg_idx = vmdq->offset; + for (i = 0; i < wx->num_rx_queues; i++) + /* If we are greater than indices move to next pool */ + wx->rx_ring[i]->reg_idx = reg_idx + i; + + reg_idx = vmdq->offset; + for (i = 0; i < wx->num_tx_queues; i++) + /* If we are greater than indices move to next pool */ + wx->tx_ring[i]->reg_idx = reg_idx + i; + } + + return true; +} + /** * wx_cache_ring_rss - Descriptor ring to register mapping for RSS * @wx: board private structure to initialize @@ -1781,6 +1894,9 @@ static void wx_cache_ring_rss(struct wx *wx) { u16 i; + if (wx_cache_ring_vmdq(wx)) + return; + for (i = 0; i < wx->num_rx_queues; i++) wx->rx_ring[i]->reg_idx = i; @@ -2179,7 +2295,8 @@ static void wx_set_ivar(struct wx *wx, s8 direction, wr32(wx, WX_PX_MISC_IVAR, ivar); } else { /* tx or rx causes */ - msix_vector += 1; /* offset for queue vectors */ + if (!(wx->mac.type == wx_mac_em && wx->num_vfs == 7)) + msix_vector += 1; /* offset for queue vectors */ msix_vector |= WX_PX_IVAR_ALLOC_VAL; index = ((16 * (queue & 1)) + (8 * direction)); ivar = rd32(wx, WX_PX_IVAR(queue >> 1)); @@ -2231,10 +2348,17 @@ void wx_configure_vectors(struct wx *wx) { struct pci_dev *pdev = wx->pdev; u32 eitrsel = 0; - u16 v_idx; + u16 v_idx, i; if (pdev->msix_enabled) { /* Populate MSIX to EITR Select */ + if (wx->mac.type == wx_mac_sp) { + if (wx->num_vfs >= 32) + eitrsel = BIT(wx->num_vfs % 32) - 1; + } else if (wx->mac.type == wx_mac_em) { + for (i = 0; i < wx->num_vfs; i++) + eitrsel |= BIT(i); + } wr32(wx, WX_PX_ITRSEL, eitrsel); /* use EIAM to auto-mask when MSI-X interrupt is asserted * this saves a register write for every interrupt -- cgit v1.2.3 From 3b05aa997c491487c8d4b0033cca76a15760a930 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Mon, 21 Apr 2025 10:29:56 +0800 Subject: net: wangxun: restrict feature flags for tunnel packets Implement ndo_features_check to restrict Tx checksum offload flags, since there are some inner layer length and protocols unsupported. Signed-off-by: Jiawen Wu Reviewed-by: Michal Kubiak Link: https://patch.msgid.link/20250421022956.508018-3-jiawenwu@trustnetic.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 27 +++++++++++++++++++++++++ drivers/net/ethernet/wangxun/libwx/wx_lib.h | 3 +++ drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 1 + drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 1 + 4 files changed, 32 insertions(+) (limited to 'drivers/net/ethernet/wangxun/libwx/wx_lib.c') diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 18422b940dbe..2a808afeb414 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -3000,6 +3000,33 @@ netdev_features_t wx_fix_features(struct net_device *netdev, } EXPORT_SYMBOL(wx_fix_features); +#define WX_MAX_TUNNEL_HDR_LEN 80 +netdev_features_t wx_features_check(struct sk_buff *skb, + struct net_device *netdev, + netdev_features_t features) +{ + struct wx *wx = netdev_priv(netdev); + + if (!skb->encapsulation) + return features; + + if (wx->mac.type == wx_mac_em) + return features & ~NETIF_F_CSUM_MASK; + + if (unlikely(skb_inner_mac_header(skb) - skb_transport_header(skb) > + WX_MAX_TUNNEL_HDR_LEN)) + return features & ~NETIF_F_CSUM_MASK; + + if (skb->inner_protocol_type == ENCAP_TYPE_ETHER && + skb->inner_protocol != htons(ETH_P_IP) && + skb->inner_protocol != htons(ETH_P_IPV6) && + skb->inner_protocol != htons(ETH_P_TEB)) + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); + + return features; +} +EXPORT_SYMBOL(wx_features_check); + void wx_set_ring(struct wx *wx, u32 new_tx_count, u32 new_rx_count, struct wx_ring *temp_ring) { diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_lib.h index fdeb0c315b75..919f49999308 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.h @@ -33,6 +33,9 @@ void wx_get_stats64(struct net_device *netdev, int wx_set_features(struct net_device *netdev, netdev_features_t features); netdev_features_t wx_fix_features(struct net_device *netdev, netdev_features_t features); +netdev_features_t wx_features_check(struct sk_buff *skb, + struct net_device *netdev, + netdev_features_t features); void wx_set_ring(struct wx *wx, u32 new_tx_count, u32 new_rx_count, struct wx_ring *temp_ring); diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c index 9c18203c8ce1..b5022c49dc5e 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c @@ -587,6 +587,7 @@ static const struct net_device_ops ngbe_netdev_ops = { .ndo_set_rx_mode = wx_set_rx_mode, .ndo_set_features = wx_set_features, .ndo_fix_features = wx_fix_features, + .ndo_features_check = wx_features_check, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = wx_set_mac, .ndo_get_stats64 = wx_get_stats64, diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index dcfccc6d963a..f57d84628e07 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -579,6 +579,7 @@ static const struct net_device_ops txgbe_netdev_ops = { .ndo_set_rx_mode = wx_set_rx_mode, .ndo_set_features = wx_set_features, .ndo_fix_features = wx_fix_features, + .ndo_features_check = wx_features_check, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = wx_set_mac, .ndo_get_stats64 = wx_get_stats64, -- cgit v1.2.3 From 78cafb1bb7e9b3c27d36b0c8670494ab2b8dc1da Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Wed, 21 May 2025 14:43:55 +0800 Subject: net: wangxun: Use specific flag bit to simplify the code Most of the different code that requires MAC type in the common library is due to NGBE only supports a few queues and pools, unlike TXGBE, which supports 128 queues and 64 pools. This difference accounts for most of the hardware configuration differences in the driver code. So add a flag bit "WX_FLAG_MULTI_64_FUNC" for them to clean-up the driver code. Signed-off-by: Jiawen Wu Reviewed-by: Simon Horman Link: https://patch.msgid.link/C731132E124D75E5+20250521064402.22348-3-jiawenwu@trustnetic.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/libwx/wx_ethtool.c | 9 ++----- drivers/net/ethernet/wangxun/libwx/wx_hw.c | 35 +++++-------------------- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 10 +++---- drivers/net/ethernet/wangxun/libwx/wx_sriov.c | 8 +++--- drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 + drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 1 + 6 files changed, 20 insertions(+), 44 deletions(-) (limited to 'drivers/net/ethernet/wangxun/libwx/wx_lib.c') diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c index 43019ec9329c..d58d7a8735bc 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c @@ -413,15 +413,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; diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c index 143cc1088eea..1c5c14ac61bc 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c @@ -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); @@ -774,14 +764,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 +903,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 +1491,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 +1522,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 +2053,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 { diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 2a808afeb414..eab16c57b039 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1633,7 +1633,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 +1693,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 +1853,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++) { @@ -2354,10 +2354,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); } diff --git a/drivers/net/ethernet/wangxun/libwx/wx_sriov.c b/drivers/net/ethernet/wangxun/libwx/wx_sriov.c index 195f64baedab..e8656d9d733b 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_sriov.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_sriov.c @@ -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); } diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 5f024f5ac3a6..6563d30e60c5 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -1184,6 +1184,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, diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index ea0b1cb721c8..0c81d8fc2f7d 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -318,6 +318,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; -- cgit v1.2.3 From 39709fe4bacda6748759522738e33464d6704dc0 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Wed, 21 May 2025 14:43:56 +0800 Subject: net: txgbe: Distinguish between 40G and 25G devices For the following patches to support PHYLINK for AML 25G devices, separate MAC type wx_mac_aml40 to maintain the driver of 40G devices. Because 40G devices will complete support later, not now. And this patch makes the 25G devices use some PHYLINK interfaces, but it is not yet create PHYLINK and cannot be used on its own. It is just preparation for the next patches. Signed-off-by: Jiawen Wu Reviewed-by: Simon Horman Link: https://patch.msgid.link/592B1A6920867D0C+20250521064402.22348-4-jiawenwu@trustnetic.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/libwx/wx_ethtool.c | 12 ++++++---- drivers/net/ethernet/wangxun/libwx/wx_hw.c | 1 + drivers/net/ethernet/wangxun/libwx/wx_lib.c | 2 ++ drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 + drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c | 4 ++-- drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 32 ++++++++++++++++++------- drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 32 +++++++++++++++++-------- drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 3 ++- 8 files changed, 61 insertions(+), 26 deletions(-) (limited to 'drivers/net/ethernet/wangxun/libwx/wx_lib.c') diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c index d58d7a8735bc..86c0159e8a2d 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c @@ -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,7 +231,7 @@ int wx_get_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_get(wx->phylink, cmd); @@ -243,7 +243,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 +255,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 +267,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 +345,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 +376,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: diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c index 1c5c14ac61bc..7a3467b41524 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c @@ -695,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; diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index eab16c57b039..68e7cfe2f7ea 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1959,6 +1959,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 +2328,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: diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 6563d30e60c5..b4275ba622de 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -838,6 +838,7 @@ enum wx_mac_type { wx_mac_sp, wx_mac_em, wx_mac_aml, + wx_mac_aml40, }; enum wx_media_type { diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c index 19878f02d956..f53a5d00a41b 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c @@ -176,7 +176,7 @@ 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; free_irq(txgbe->link_irq, txgbe); @@ -190,7 +190,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; diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 0c81d8fc2f7d..ca3dbc448646 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -91,6 +91,7 @@ static int txgbe_enumerate_functions(struct wx *wx) 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 +100,21 @@ 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: + case wx_mac_sp: phylink_start(wx->phylink); + break; + default: + break; } /* clear any pending interrupts, may auto mask */ @@ -207,10 +212,18 @@ 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: + 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 +253,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; @@ -341,6 +356,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; diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index b5ae7c25ac99..ece378fa2620 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -573,11 +573,17 @@ 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: + case wx_mac_aml: return 0; - - if (txgbe->wx->media_type == wx_media_copper) - return txgbe_ext_phy_init(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 +646,19 @@ err_unregister_swnode: void txgbe_remove_phy(struct txgbe *txgbe) { - if (txgbe->wx->mac.type == wx_mac_aml) - return; - - if (txgbe->wx->media_type == wx_media_copper) { - phylink_disconnect_phy(txgbe->wx->phylink); - phylink_destroy(txgbe->wx->phylink); + switch (txgbe->wx->mac.type) { + case wx_mac_aml40: + case wx_mac_aml: 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); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 8376248fecda..3b4e4361462a 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -152,7 +152,8 @@ #define TXGBE_PX_PF_BME 0x4B8 #define TXGBE_AML_MAC_TX_CFG 0x11000 #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_RDM_RSC_CTL 0x1200C #define TXGBE_RDM_RSC_CTL_FREE_CTL BIT(7) -- cgit v1.2.3 From 343929799ace121cd9b795c526b2ad7aefe54458 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Wed, 21 May 2025 14:43:58 +0800 Subject: net: txgbe: Support to handle GPIO IRQs for AML devices The driver needs to handle GPIO interrupts to identify SFP module and configure PHY by sending mailbox messages to firmware. Since the SFP module needs to wait for ready to get information when it is inserted, workqueue is added to handle delayed tasks. And each SW-FW interaction takes time to wait, so they are processed in the workqueue instead of IRQ handler function. Signed-off-by: Jiawen Wu Reviewed-by: Simon Horman Link: https://patch.msgid.link/399624AF221E8E28+20250521064402.22348-6-jiawenwu@trustnetic.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 31 ++++ drivers/net/ethernet/wangxun/libwx/wx_lib.h | 3 + drivers/net/ethernet/wangxun/libwx/wx_type.h | 8 + drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c | 204 ++++++++++++++++++++++++ drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h | 5 + drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c | 35 +++- drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 74 ++++++++- drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 75 +++++++++ 8 files changed, 433 insertions(+), 2 deletions(-) (limited to 'drivers/net/ethernet/wangxun/libwx/wx_lib.c') diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 68e7cfe2f7ea..5c747509d56b 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -3095,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"); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_lib.h index 49f8bde36ddb..aed6ea8cf0d6 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.h @@ -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_ */ diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index b4275ba622de..7730c9fc3e02 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -1154,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 */ }; @@ -1197,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 */ }; @@ -1235,6 +1238,8 @@ struct wx { /* PHY stuff */ bool notify_down; + int adv_speed; + int adv_duplex; unsigned int link; int speed; int duplex; @@ -1332,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) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c index 49eb93987a9d..af12ebb89c71 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c @@ -13,6 +13,96 @@ #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; +} + +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; @@ -28,6 +118,120 @@ static void txgbe_get_phy_link(struct wx *wx, int *speed) *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) { diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h index aa3b7848e03d..2376a021ba8d 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h @@ -4,6 +4,11 @@ #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_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_ */ diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c index f53a5d00a41b..05fe8fd43b80 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c @@ -11,6 +11,7 @@ #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 +20,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 +89,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 +173,11 @@ 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++; + } wx_intr_enable(wx, TXGBE_INTR_MISC); return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); @@ -179,6 +200,9 @@ void txgbe_free_misc_irq(struct txgbe *txgbe) 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); @@ -222,11 +246,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: diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index ca3dbc448646..6f3b67def51a 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -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,6 +89,58 @@ 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; @@ -110,6 +163,11 @@ static void txgbe_up_complete(struct wx *wx) netif_carrier_on(wx->netdev); 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; @@ -125,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, @@ -173,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 @@ -218,6 +279,10 @@ void txgbe_down(struct wx *wx) netif_carrier_off(wx->netdev); 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; @@ -752,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 @@ -847,6 +914,9 @@ err_free_misc_irq: 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); @@ -873,6 +943,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); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index ca4da2696eed..98bd25254c80 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -6,6 +6,8 @@ #include #include +#include +#include "../libwx/wx_type.h" /* Device IDs */ #define TXGBE_DEV_ID_SP1000 0x1001 @@ -311,6 +313,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, \ @@ -348,6 +416,7 @@ struct txgbe_nodes { enum txgbe_misc_irqs { TXGBE_IRQ_LINK = 0, + TXGBE_IRQ_GPIO, TXGBE_IRQ_MAX }; @@ -369,6 +438,7 @@ struct txgbe { struct clk *clk; struct gpio_chip *gpio; unsigned int link_irq; + unsigned int gpio_irq; u32 eicr; /* flow director */ @@ -376,6 +446,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_ */ -- cgit v1.2.3