Skip to content

Commit

Permalink
Merge branch 'wangxun-netdev-features-support'
Browse files Browse the repository at this point in the history
Mengyuan Lou says:

====================
Wangxun netdev features support

Implement tx_csum and rx_csum to support hardware checksum offload.
Implement ndo_vlan_rx_add_vid and ndo_vlan_rx_kill_vid.
Implement ndo_set_features.
Enable macros in netdev features which wangxun can support.
====================

Link: https://lore.kernel.org/r/20230530022632.17938-1-mengyuanlou@net-swift.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Jun 1, 2023
2 parents 6f4b981 + 7df4af5 commit 735c9ee
Show file tree
Hide file tree
Showing 9 changed files with 1,250 additions and 21 deletions.
272 changes: 271 additions & 1 deletion drivers/net/ethernet/wangxun/libwx/wx_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1182,12 +1182,28 @@ static void wx_enable_sec_rx_path(struct wx *wx)
WX_WRITE_FLUSH(wx);
}

static void wx_vlan_strip_control(struct wx *wx, bool enable)
{
int i, j;

for (i = 0; i < wx->num_rx_queues; i++) {
struct wx_ring *ring = wx->rx_ring[i];

j = ring->reg_idx;
wr32m(wx, WX_PX_RR_CFG(j), WX_PX_RR_CFG_VLAN,
enable ? WX_PX_RR_CFG_VLAN : 0);
}
}

void wx_set_rx_mode(struct net_device *netdev)
{
struct wx *wx = netdev_priv(netdev);
netdev_features_t features;
u32 fctrl, vmolr, vlnctrl;
int count;

features = netdev->features;

/* Check for Promiscuous and All Multicast modes */
fctrl = rd32(wx, WX_PSR_CTL);
fctrl &= ~(WX_PSR_CTL_UPE | WX_PSR_CTL_MPE);
Expand Down Expand Up @@ -1254,6 +1270,13 @@ void wx_set_rx_mode(struct net_device *netdev)
wr32(wx, WX_PSR_VLAN_CTL, vlnctrl);
wr32(wx, WX_PSR_CTL, fctrl);
wr32(wx, WX_PSR_VM_L2CTL(0), vmolr);

if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
(features & NETIF_F_HW_VLAN_STAG_RX))
wx_vlan_strip_control(wx, true);
else
wx_vlan_strip_control(wx, false);

}
EXPORT_SYMBOL(wx_set_rx_mode);

Expand Down Expand Up @@ -1462,6 +1485,16 @@ static void wx_configure_tx(struct wx *wx)
WX_MAC_TX_CFG_TE, WX_MAC_TX_CFG_TE);
}

static void wx_restore_vlan(struct wx *wx)
{
u16 vid = 1;

wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), 0);

for_each_set_bit_from(vid, wx->active_vlans, VLAN_N_VID)
wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), vid);
}

/**
* wx_configure_rx - Configure Receive Unit after Reset
* @wx: pointer to private structure
Expand Down Expand Up @@ -1527,7 +1560,7 @@ void wx_configure(struct wx *wx)
wx_configure_port(wx);

wx_set_rx_mode(wx->netdev);

wx_restore_vlan(wx);
wx_enable_sec_rx_path(wx);

wx_configure_tx(wx);
Expand Down Expand Up @@ -1727,4 +1760,241 @@ int wx_sw_init(struct wx *wx)
}
EXPORT_SYMBOL(wx_sw_init);

/**
* wx_find_vlvf_slot - find the vlanid or the first empty slot
* @wx: pointer to hardware structure
* @vlan: VLAN id to write to VLAN filter
*
* return the VLVF index where this VLAN id should be placed
*
**/
static int wx_find_vlvf_slot(struct wx *wx, u32 vlan)
{
u32 bits = 0, first_empty_slot = 0;
int regindex;

/* short cut the special case */
if (vlan == 0)
return 0;

/* Search for the vlan id in the VLVF entries. Save off the first empty
* slot found along the way
*/
for (regindex = 1; regindex < WX_PSR_VLAN_SWC_ENTRIES; regindex++) {
wr32(wx, WX_PSR_VLAN_SWC_IDX, regindex);
bits = rd32(wx, WX_PSR_VLAN_SWC);
if (!bits && !(first_empty_slot))
first_empty_slot = regindex;
else if ((bits & 0x0FFF) == vlan)
break;
}

if (regindex >= WX_PSR_VLAN_SWC_ENTRIES) {
if (first_empty_slot)
regindex = first_empty_slot;
else
regindex = -ENOMEM;
}

return regindex;
}

/**
* wx_set_vlvf - Set VLAN Pool Filter
* @wx: pointer to hardware structure
* @vlan: VLAN id to write to VLAN filter
* @vind: VMDq output index that maps queue to VLAN id in VFVFB
* @vlan_on: boolean flag to turn on/off VLAN in VFVF
* @vfta_changed: pointer to boolean flag which indicates whether VFTA
* should be changed
*
* Turn on/off specified bit in VLVF table.
**/
static int wx_set_vlvf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
bool *vfta_changed)
{
int vlvf_index;
u32 vt, bits;

/* If VT Mode is set
* Either vlan_on
* make sure the vlan is in VLVF
* set the vind bit in the matching VLVFB
* Or !vlan_on
* clear the pool bit and possibly the vind
*/
vt = rd32(wx, WX_CFG_PORT_CTL);
if (!(vt & WX_CFG_PORT_CTL_NUM_VT_MASK))
return 0;

vlvf_index = wx_find_vlvf_slot(wx, vlan);
if (vlvf_index < 0)
return vlvf_index;

wr32(wx, WX_PSR_VLAN_SWC_IDX, vlvf_index);
if (vlan_on) {
/* set the pool bit */
if (vind < 32) {
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L);
bits |= (1 << vind);
wr32(wx, WX_PSR_VLAN_SWC_VM_L, bits);
} else {
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H);
bits |= (1 << (vind - 32));
wr32(wx, WX_PSR_VLAN_SWC_VM_H, bits);
}
} else {
/* clear the pool bit */
if (vind < 32) {
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L);
bits &= ~(1 << vind);
wr32(wx, WX_PSR_VLAN_SWC_VM_L, bits);
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_H);
} else {
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H);
bits &= ~(1 << (vind - 32));
wr32(wx, WX_PSR_VLAN_SWC_VM_H, bits);
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_L);
}
}

if (bits) {
wr32(wx, WX_PSR_VLAN_SWC, (WX_PSR_VLAN_SWC_VIEN | vlan));
if (!vlan_on && vfta_changed)
*vfta_changed = false;
} else {
wr32(wx, WX_PSR_VLAN_SWC, 0);
}

return 0;
}

/**
* wx_set_vfta - Set VLAN filter table
* @wx: pointer to hardware structure
* @vlan: VLAN id to write to VLAN filter
* @vind: VMDq output index that maps queue to VLAN id in VFVFB
* @vlan_on: boolean flag to turn on/off VLAN in VFVF
*
* Turn on/off specified VLAN in the VLAN filter table.
**/
static int wx_set_vfta(struct wx *wx, u32 vlan, u32 vind, bool vlan_on)
{
u32 bitindex, vfta, targetbit;
bool vfta_changed = false;
int regindex, ret;

/* this is a 2 part operation - first the VFTA, then the
* VLVF and VLVFB if VT Mode is set
* We don't write the VFTA until we know the VLVF part succeeded.
*/

/* Part 1
* The VFTA is a bitstring made up of 128 32-bit registers
* that enable the particular VLAN id, much like the MTA:
* bits[11-5]: which register
* bits[4-0]: which bit in the register
*/
regindex = (vlan >> 5) & 0x7F;
bitindex = vlan & 0x1F;
targetbit = (1 << bitindex);
/* errata 5 */
vfta = wx->mac.vft_shadow[regindex];
if (vlan_on) {
if (!(vfta & targetbit)) {
vfta |= targetbit;
vfta_changed = true;
}
} else {
if ((vfta & targetbit)) {
vfta &= ~targetbit;
vfta_changed = true;
}
}
/* Part 2
* Call wx_set_vlvf to set VLVFB and VLVF
*/
ret = wx_set_vlvf(wx, vlan, vind, vlan_on, &vfta_changed);
if (ret != 0)
return ret;

if (vfta_changed)
wr32(wx, WX_PSR_VLAN_TBL(regindex), vfta);
wx->mac.vft_shadow[regindex] = vfta;

return 0;
}

/**
* wx_clear_vfta - Clear VLAN filter table
* @wx: pointer to hardware structure
*
* Clears the VLAN filer table, and the VMDq index associated with the filter
**/
static void wx_clear_vfta(struct wx *wx)
{
u32 offset;

for (offset = 0; offset < wx->mac.vft_size; offset++) {
wr32(wx, WX_PSR_VLAN_TBL(offset), 0);
wx->mac.vft_shadow[offset] = 0;
}

for (offset = 0; offset < WX_PSR_VLAN_SWC_ENTRIES; offset++) {
wr32(wx, WX_PSR_VLAN_SWC_IDX, offset);
wr32(wx, WX_PSR_VLAN_SWC, 0);
wr32(wx, WX_PSR_VLAN_SWC_VM_L, 0);
wr32(wx, WX_PSR_VLAN_SWC_VM_H, 0);
}
}

int wx_vlan_rx_add_vid(struct net_device *netdev,
__be16 proto, u16 vid)
{
struct wx *wx = netdev_priv(netdev);

/* add VID to filter table */
wx_set_vfta(wx, vid, VMDQ_P(0), true);
set_bit(vid, wx->active_vlans);

return 0;
}
EXPORT_SYMBOL(wx_vlan_rx_add_vid);

int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct wx *wx = netdev_priv(netdev);

/* remove VID from filter table */
if (vid)
wx_set_vfta(wx, vid, VMDQ_P(0), false);
clear_bit(vid, wx->active_vlans);

return 0;
}
EXPORT_SYMBOL(wx_vlan_rx_kill_vid);

/**
* wx_start_hw - Prepare hardware for Tx/Rx
* @wx: pointer to hardware structure
*
* Starts the hardware using the generic start_hw function
* and the generation start_hw function.
* Then performs revision-specific operations, if any.
**/
void wx_start_hw(struct wx *wx)
{
int i;

/* Clear the VLAN filter table */
wx_clear_vfta(wx);
WX_WRITE_FLUSH(wx);
/* Clear the rate limiters */
for (i = 0; i < wx->mac.max_tx_queues; i++) {
wr32(wx, WX_TDM_RP_IDX, i);
wr32(wx, WX_TDM_RP_RATE, 0);
}
}
EXPORT_SYMBOL(wx_start_hw);

MODULE_LICENSE("GPL");
3 changes: 3 additions & 0 deletions drivers/net/ethernet/wangxun/libwx/wx_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ void wx_set_rx_mode(struct net_device *netdev);
int wx_change_mtu(struct net_device *netdev, int new_mtu);
void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring);
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_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);
int wx_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);

#endif /* _WX_HW_H_ */
Loading

0 comments on commit 735c9ee

Please sign in to comment.