Commit 1c57de69 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-aquantia-implement-vlan-offloads'

Igor Russkikh says:

====================
net: aquantia: implement vlan offloads

This patchset introduces hardware VLAN offload support and also does some
maintenance: we replace driver version with uts version string, add
documentation file for atlantic driver, and update maintainers
adding Igor as a maintainer.

v3: shuffle doc sections, per Andrew's comments

v2: updates in doc, gpl spdx tag cleanup
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0b58f648 04f207fb
This diff is collapsed.
......@@ -1140,6 +1140,15 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/i2c/aptina-pll.*
AQUANTIA ETHERNET DRIVER (atlantic)
M: Igor Russkikh <igor.russkikh@aquantia.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.aquantia.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/aquantia/atlantic/
F: Documentation/networking/device_drivers/aquantia/atlantic.txt
ARC FRAMEBUFFER DRIVER
M: Jaya Kumar <jayalk@intworks.biz>
S: Maintained
......
......@@ -9,6 +9,8 @@
#ifndef AQ_CFG_H
#define AQ_CFG_H
#include <generated/utsrelease.h>
#define AQ_CFG_VECS_DEF 8U
#define AQ_CFG_TCS_DEF 1U
......@@ -86,10 +88,7 @@
#define AQ_CFG_DRV_AUTHOR "aQuantia"
#define AQ_CFG_DRV_DESC "aQuantia Corporation(R) Network Driver"
#define AQ_CFG_DRV_NAME "atlantic"
#define AQ_CFG_DRV_VERSION __stringify(NIC_MAJOR_DRIVER_VERSION)"."\
__stringify(NIC_MINOR_DRIVER_VERSION)"."\
__stringify(NIC_BUILD_DRIVER_VERSION)"."\
__stringify(NIC_REVISION_DRIVER_VERSION) \
#define AQ_CFG_DRV_VERSION UTS_RELEASE \
AQ_CFG_DRV_VERSION_SUFFIX
#endif /* AQ_CFG_H */
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2014-2019 aQuantia Corporation. */
/* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* File aq_drvinfo.h: Declaration of common code for firmware info in sys.*/
......
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* File aq_filters.c: RX filters related functions. */
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* File aq_filters.h: RX filters related functions. */
......
......@@ -108,11 +108,16 @@ static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu)
static int aq_ndev_set_features(struct net_device *ndev,
netdev_features_t features)
{
bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
bool is_vlan_tx_insert = !!(features & NETIF_F_HW_VLAN_CTAG_TX);
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic);
bool need_ndev_restart = false;
struct aq_nic_cfg_s *aq_cfg;
bool is_lro = false;
int err = 0;
aq_cfg = aq_nic_get_cfg(aq_nic);
if (!(features & NETIF_F_NTUPLE)) {
if (aq_nic->ndev->features & NETIF_F_NTUPLE) {
err = aq_clear_rxnfc_all_rules(aq_nic);
......@@ -135,17 +140,32 @@ static int aq_ndev_set_features(struct net_device *ndev,
if (aq_cfg->is_lro != is_lro) {
aq_cfg->is_lro = is_lro;
if (netif_running(ndev)) {
aq_ndev_close(ndev);
aq_ndev_open(ndev);
}
need_ndev_restart = true;
}
}
if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM)
if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM) {
err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
aq_cfg);
if (unlikely(err))
goto err_exit;
}
if (aq_cfg->is_vlan_rx_strip != is_vlan_rx_strip) {
aq_cfg->is_vlan_rx_strip = is_vlan_rx_strip;
need_ndev_restart = true;
}
if (aq_cfg->is_vlan_tx_insert != is_vlan_tx_insert) {
aq_cfg->is_vlan_tx_insert = is_vlan_tx_insert;
need_ndev_restart = true;
}
if (need_ndev_restart && netif_running(ndev)) {
aq_ndev_close(ndev);
aq_ndev_open(ndev);
}
err_exit:
return err;
}
......
......@@ -126,6 +126,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
cfg->features = cfg->aq_hw_caps->hw_features;
cfg->is_vlan_rx_strip = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_RX);
cfg->is_vlan_tx_insert = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_TX);
}
static int aq_nic_update_link_status(struct aq_nic_s *self)
......@@ -285,7 +287,8 @@ void aq_nic_ndev_init(struct aq_nic_s *self)
self->ndev->hw_features |= aq_hw_caps->hw_features;
self->ndev->features = aq_hw_caps->hw_features;
self->ndev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
NETIF_F_RXHASH | NETIF_F_SG | NETIF_F_LRO;
NETIF_F_RXHASH | NETIF_F_SG |
NETIF_F_LRO | NETIF_F_TSO;
self->ndev->priv_flags = aq_hw_caps->hw_priv_flags;
self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
......@@ -426,26 +429,37 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self,
unsigned int dx = ring->sw_tail;
struct aq_ring_buff_s *first = NULL;
struct aq_ring_buff_s *dx_buff = &ring->buff_ring[dx];
bool need_context_tag = false;
if (unlikely(skb_is_gso(skb))) {
dx_buff->flags = 0U;
if (unlikely(skb_is_gso(skb))) {
dx_buff->mss = skb_shinfo(skb)->gso_size;
dx_buff->is_gso = 1U;
dx_buff->len_pkt = skb->len;
dx_buff->len_l2 = ETH_HLEN;
dx_buff->len_l3 = ip_hdrlen(skb);
dx_buff->len_l4 = tcp_hdrlen(skb);
dx_buff->mss = skb_shinfo(skb)->gso_size;
dx_buff->is_txc = 1U;
dx_buff->eop_index = 0xffffU;
dx_buff->is_ipv6 =
(ip_hdr(skb)->version == 6) ? 1U : 0U;
need_context_tag = true;
}
if (self->aq_nic_cfg.is_vlan_tx_insert && skb_vlan_tag_present(skb)) {
dx_buff->vlan_tx_tag = skb_vlan_tag_get(skb);
dx_buff->len_pkt = skb->len;
dx_buff->is_vlan = 1U;
need_context_tag = true;
}
if (need_context_tag) {
dx = aq_ring_next_dx(ring, dx);
dx_buff = &ring->buff_ring[dx];
dx_buff->flags = 0U;
++ret;
}
dx_buff->flags = 0U;
dx_buff->len = skb_headlen(skb);
dx_buff->pa = dma_map_single(aq_nic_get_dev(self),
skb->data,
......@@ -534,7 +548,7 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self,
--ret, dx = aq_ring_next_dx(ring, dx)) {
dx_buff = &ring->buff_ring[dx];
if (!dx_buff->is_txc && dx_buff->pa) {
if (!dx_buff->is_gso && !dx_buff->is_vlan && dx_buff->pa) {
if (unlikely(dx_buff->is_sop)) {
dma_unmap_single(aq_nic_get_dev(self),
dx_buff->pa,
......
......@@ -35,6 +35,8 @@ struct aq_nic_cfg_s {
u32 flow_control;
u32 link_speed_msk;
u32 wol;
u8 is_vlan_rx_strip;
u8 is_vlan_tx_insert;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
......
......@@ -409,6 +409,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
}
}
if (buff->is_vlan)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
buff->vlan_rx_tag);
skb->protocol = eth_type_trans(skb, ndev);
aq_rx_checksum(self, buff, skb);
......
......@@ -27,7 +27,7 @@ struct aq_rxpage {
* +----------+----------+----------+-----------
* 4/8bytes|len pkt |len pkt | | skb
* +----------+----------+----------+-----------
* 4/8bytes|is_txc |len,flags |len |len,is_eop
* 4/8bytes|is_gso |len,flags |len |len,is_eop
* +----------+----------+----------+-----------
*
* This aq_ring_buff_s doesn't have endianness dependency.
......@@ -44,6 +44,7 @@ struct __packed aq_ring_buff_s {
u8 is_hash_l4;
u8 rsvd1;
struct aq_rxpage rxdata;
u16 vlan_rx_tag;
};
/* EOP */
struct {
......@@ -59,6 +60,7 @@ struct __packed aq_ring_buff_s {
u8 is_ipv6:1;
u8 rsvd2:7;
u32 len_pkt;
u16 vlan_tx_tag;
};
};
union {
......@@ -70,11 +72,12 @@ struct __packed aq_ring_buff_s {
u32 is_cso_err:1;
u32 is_sop:1;
u32 is_eop:1;
u32 is_txc:1;
u32 is_gso:1;
u32 is_mapped:1;
u32 is_cleaned:1;
u32 is_error:1;
u32 rsvd3:6;
u32 is_vlan:1;
u32 rsvd3:5;
u16 eop_index;
u16 rsvd4;
};
......
......@@ -451,7 +451,7 @@ static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self,
buff = &ring->buff_ring[ring->sw_tail];
if (buff->is_txc) {
if (buff->is_gso) {
txd->ctl |= (buff->len_l3 << 31) |
(buff->len_l2 << 24) |
HW_ATL_A0_TXD_CTL_CMD_TCP |
......
......@@ -40,7 +40,9 @@
NETIF_F_TSO | \
NETIF_F_LRO | \
NETIF_F_NTUPLE | \
NETIF_F_HW_VLAN_CTAG_FILTER, \
NETIF_F_HW_VLAN_CTAG_FILTER | \
NETIF_F_HW_VLAN_CTAG_RX | \
NETIF_F_HW_VLAN_CTAG_TX, \
.hw_priv_flags = IFF_UNICAST_FLT, \
.flow_control = true, \
.mtu = HW_ATL_B0_MTU_JUMBO, \
......@@ -245,6 +247,9 @@ static int hw_atl_b0_hw_offload_set(struct aq_hw_s *self,
/* LSO offloads*/
hw_atl_tdm_large_send_offload_en_set(self, 0xFFFFFFFFU);
/* Outer VLAN tag offload */
hw_atl_rpo_outer_vlan_tag_mode_set(self, 1U);
/* LRO offloads */
{
unsigned int val = (8U < HW_ATL_B0_LRO_RXD_MAX) ? 0x3U :
......@@ -487,6 +492,7 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self,
unsigned int buff_pa_len = 0U;
unsigned int pkt_len = 0U;
unsigned int frag_count = 0U;
bool is_vlan = false;
bool is_gso = false;
buff = &ring->buff_ring[ring->sw_tail];
......@@ -501,36 +507,44 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self,
buff = &ring->buff_ring[ring->sw_tail];
if (buff->is_txc) {
if (buff->is_gso) {
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_TCP;
txd->ctl |= HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC;
txd->ctl |= (buff->len_l3 << 31) |
(buff->len_l2 << 24) |
HW_ATL_B0_TXD_CTL_CMD_TCP |
HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC;
txd->ctl2 |= (buff->mss << 16) |
(buff->len_l4 << 8) |
(buff->len_l3 >> 1);
(buff->len_l2 << 24);
txd->ctl2 |= (buff->mss << 16);
is_gso = true;
pkt_len -= (buff->len_l4 +
buff->len_l3 +
buff->len_l2);
is_gso = true;
if (buff->is_ipv6)
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_IPV6;
} else {
txd->ctl2 |= (buff->len_l4 << 8) |
(buff->len_l3 >> 1);
}
if (buff->is_vlan) {
txd->ctl |= HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC;
txd->ctl |= buff->vlan_tx_tag << 4;
is_vlan = true;
}
if (!buff->is_gso && !buff->is_vlan) {
buff_pa_len = buff->len;
txd->buf_addr = buff->pa;
txd->ctl |= (HW_ATL_B0_TXD_CTL_BLEN &
((u32)buff_pa_len << 4));
txd->ctl |= HW_ATL_B0_TXD_CTL_DESC_TYPE_TXD;
/* PAY_LEN */
txd->ctl2 |= HW_ATL_B0_TXD_CTL2_LEN & (pkt_len << 14);
if (is_gso) {
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_LSO;
if (is_gso || is_vlan) {
/* enable tx context */
txd->ctl2 |= HW_ATL_B0_TXD_CTL2_CTX_EN;
}
if (is_gso)
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_LSO;
/* Tx checksum offloads */
if (buff->is_ip_cso)
......@@ -539,13 +553,16 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self,
if (buff->is_udp_cso || buff->is_tcp_cso)
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_TUCSO;
if (is_vlan)
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_VLAN;
if (unlikely(buff->is_eop)) {
txd->ctl |= HW_ATL_B0_TXD_CTL_EOP;
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_WB;
is_gso = false;
is_vlan = false;
}
}
ring->sw_tail = aq_ring_next_dx(ring, ring->sw_tail);
}
......@@ -559,6 +576,7 @@ static int hw_atl_b0_hw_ring_rx_init(struct aq_hw_s *self,
{
u32 dma_desc_addr_lsw = (u32)aq_ring->dx_ring_pa;
u32 dma_desc_addr_msw = (u32)(((u64)aq_ring->dx_ring_pa) >> 32);
u32 vlan_rx_stripping = self->aq_nic_cfg->is_vlan_rx_strip;
hw_atl_rdm_rx_desc_en_set(self, false, aq_ring->idx);
......@@ -578,7 +596,8 @@ static int hw_atl_b0_hw_ring_rx_init(struct aq_hw_s *self,
hw_atl_rdm_rx_desc_head_buff_size_set(self, 0U, aq_ring->idx);
hw_atl_rdm_rx_desc_head_splitting_set(self, 0U, aq_ring->idx);
hw_atl_rpo_rx_desc_vlan_stripping_set(self, 0U, aq_ring->idx);
hw_atl_rpo_rx_desc_vlan_stripping_set(self, !!vlan_rx_stripping,
aq_ring->idx);
/* Rx ring set mode */
......@@ -681,11 +700,15 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
buff = &ring->buff_ring[ring->hw_head];
buff->flags = 0U;
buff->is_hash_l4 = 0U;
rx_stat = (0x0000003CU & rxd_wb->status) >> 2;
is_rx_check_sum_enabled = (rxd_wb->type >> 19) & 0x3U;
pkt_type = 0xFFU & (rxd_wb->type >> 4);
pkt_type = (rxd_wb->type & HW_ATL_B0_RXD_WB_STAT_PKTTYPE) >>
HW_ATL_B0_RXD_WB_STAT_PKTTYPE_SHIFT;
if (is_rx_check_sum_enabled & BIT(0) &&
(0x0U == (pkt_type & 0x3U)))
......@@ -706,6 +729,13 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
buff->is_cso_err = 0U;
}
if (self->aq_nic_cfg->is_vlan_rx_strip &&
((pkt_type & HW_ATL_B0_RXD_WB_PKTTYPE_VLAN) ||
(pkt_type & HW_ATL_B0_RXD_WB_PKTTYPE_VLAN_DOUBLE))) {
buff->is_vlan = 1;
buff->vlan_rx_tag = le16_to_cpu(rxd_wb->vlan);
}
if ((rx_stat & BIT(0)) || rxd_wb->type & 0x1000U) {
/* MAC error or DMA error */
buff->is_error = 1U;
......
......@@ -107,10 +107,17 @@
#define HW_ATL_B0_RXD_NCEA0 (0x1)
#define HW_ATL_B0_RXD_WB_STAT_RSSTYPE (0x0000000F)
#define HW_ATL_B0_RXD_WB_STAT_RSSTYPE_SHIFT (0x0)
#define HW_ATL_B0_RXD_WB_STAT_PKTTYPE (0x00000FF0)
#define HW_ATL_B0_RXD_WB_STAT_PKTTYPE_SHIFT (0x4)
#define HW_ATL_B0_RXD_WB_STAT_RXCTRL (0x00180000)
#define HW_ATL_B0_RXD_WB_STAT_RXCTRL_SHIFT (0x13)
#define HW_ATL_B0_RXD_WB_STAT_SPLHDR (0x00200000)
#define HW_ATL_B0_RXD_WB_STAT_HDRLEN (0xFFC00000)
#define HW_ATL_B0_RXD_WB_STAT_HDRLEN_SHIFT (0x16)
#define HW_ATL_B0_RXD_WB_PKTTYPE_VLAN BIT(5)
#define HW_ATL_B0_RXD_WB_PKTTYPE_VLAN_DOUBLE BIT(6)
#define HW_ATL_B0_RXD_WB_STAT2_DD (0x0001)
#define HW_ATL_B0_RXD_WB_STAT2_EOP (0x0002)
......
......@@ -1004,6 +1004,22 @@ void hw_atl_rpo_rx_desc_vlan_stripping_set(struct aq_hw_s *aq_hw,
rx_desc_vlan_stripping);
}
void hw_atl_rpo_outer_vlan_tag_mode_set(void *context,
u32 outervlantagmode)
{
aq_hw_write_reg_bit(context, HW_ATL_RPO_OUTER_VL_INS_MODE_ADR,
HW_ATL_RPO_OUTER_VL_INS_MODE_MSK,
HW_ATL_RPO_OUTER_VL_INS_MODE_SHIFT,
outervlantagmode);
}
u32 hw_atl_rpo_outer_vlan_tag_mode_get(void *context)
{
return aq_hw_read_reg_bit(context, HW_ATL_RPO_OUTER_VL_INS_MODE_ADR,
HW_ATL_RPO_OUTER_VL_INS_MODE_MSK,
HW_ATL_RPO_OUTER_VL_INS_MODE_SHIFT);
}
void hw_atl_rpo_tcp_udp_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 tcp_udp_crc_offload_en)
{
......
......@@ -488,6 +488,11 @@ void hw_atl_rpo_rx_desc_vlan_stripping_set(struct aq_hw_s *aq_hw,
u32 rx_desc_vlan_stripping,
u32 descriptor);
void hw_atl_rpo_outer_vlan_tag_mode_set(void *context,
u32 outervlantagmode);
u32 hw_atl_rpo_outer_vlan_tag_mode_get(void *context);
/* set tcp/udp checksum offload enable */
void hw_atl_rpo_tcp_udp_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 tcp_udp_crc_offload_en);
......
......@@ -1383,6 +1383,24 @@
/* default value of bitfield l4_chk_en */
#define HW_ATL_RPOL4CHK_EN_DEFAULT 0x0
/* RX outer_vl_ins_mode Bitfield Definitions
* Preprocessor definitions for the bitfield "outer_vl_ins_mode".
* PORT="pif_rpo_outer_vl_mode_i"
*/
/* Register address for bitfield outer_vl_ins_mode */
#define HW_ATL_RPO_OUTER_VL_INS_MODE_ADR 0x00005580
/* Bitmask for bitfield outer_vl_ins_mode */
#define HW_ATL_RPO_OUTER_VL_INS_MODE_MSK 0x00000004
/* Inverted bitmask for bitfield outer_vl_ins_mode */
#define HW_ATL_RPO_OUTER_VL_INS_MODE_MSKN 0xFFFFFFFB
/* Lower bit position of bitfield outer_vl_ins_mode */
#define HW_ATL_RPO_OUTER_VL_INS_MODE_SHIFT 2
/* Width of bitfield outer_vl_ins_mode */
#define HW_ATL_RPO_OUTER_VL_INS_MODE_WIDTH 1
/* Default value of bitfield outer_vl_ins_mode */
#define HW_ATL_RPO_OUTER_VL_INS_MODE_DEFAULT 0x0
/* rx reg_res_dsbl bitfield definitions
* preprocessor definitions for the bitfield "reg_res_dsbl".
* port="pif_rx_reg_res_dsbl_i"
......
......@@ -7,11 +7,6 @@
#ifndef VER_H
#define VER_H
#define NIC_MAJOR_DRIVER_VERSION 2
#define NIC_MINOR_DRIVER_VERSION 0
#define NIC_BUILD_DRIVER_VERSION 4
#define NIC_REVISION_DRIVER_VERSION 0
#define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
#endif /* VER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment