mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-28 20:02:17 +00:00
sky2: convert to new VLAN model (v0.2)
This converts sky2 to new VLAN offload flags control via ethtool. It also allows for transmit offload of vlan tagged frames which was not possible before. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Reviewed-by: Jesse Gross <jesse@nicira.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2aca31e765
commit
86aa77854f
2 changed files with 52 additions and 71 deletions
|
@ -46,10 +46,6 @@
|
||||||
|
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
|
|
||||||
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
|
|
||||||
#define SKY2_VLAN_TAG_USED 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "sky2.h"
|
#include "sky2.h"
|
||||||
|
|
||||||
#define DRV_NAME "sky2"
|
#define DRV_NAME "sky2"
|
||||||
|
@ -1326,39 +1322,34 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)
|
||||||
static void sky2_set_vlan_mode(struct sky2_hw *hw, u16 port, bool onoff)
|
|
||||||
{
|
|
||||||
if (onoff) {
|
|
||||||
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
|
|
||||||
RX_VLAN_STRIP_ON);
|
|
||||||
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
|
|
||||||
TX_VLAN_TAG_ON);
|
|
||||||
} else {
|
|
||||||
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
|
|
||||||
RX_VLAN_STRIP_OFF);
|
|
||||||
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
|
|
||||||
TX_VLAN_TAG_OFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
|
static void sky2_vlan_mode(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct sky2_port *sky2 = netdev_priv(dev);
|
struct sky2_port *sky2 = netdev_priv(dev);
|
||||||
struct sky2_hw *hw = sky2->hw;
|
struct sky2_hw *hw = sky2->hw;
|
||||||
u16 port = sky2->port;
|
u16 port = sky2->port;
|
||||||
|
|
||||||
netif_tx_lock_bh(dev);
|
if (dev->features & NETIF_F_HW_VLAN_RX)
|
||||||
napi_disable(&hw->napi);
|
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
|
||||||
|
RX_VLAN_STRIP_ON);
|
||||||
|
else
|
||||||
|
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
|
||||||
|
RX_VLAN_STRIP_OFF);
|
||||||
|
|
||||||
sky2->vlgrp = grp;
|
dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN;
|
||||||
sky2_set_vlan_mode(hw, port, grp != NULL);
|
if (dev->features & NETIF_F_HW_VLAN_TX)
|
||||||
|
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
|
||||||
|
TX_VLAN_TAG_ON);
|
||||||
|
else {
|
||||||
|
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
|
||||||
|
TX_VLAN_TAG_OFF);
|
||||||
|
|
||||||
sky2_read32(hw, B0_Y2_SP_LISR);
|
/* Can't do transmit offload of vlan without hw vlan */
|
||||||
napi_enable(&hw->napi);
|
dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG
|
||||||
netif_tx_unlock_bh(dev);
|
| NETIF_F_ALL_CSUM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Amount of required worst case padding in rx buffer */
|
/* Amount of required worst case padding in rx buffer */
|
||||||
static inline unsigned sky2_rx_pad(const struct sky2_hw *hw)
|
static inline unsigned sky2_rx_pad(const struct sky2_hw *hw)
|
||||||
|
@ -1635,9 +1626,7 @@ static void sky2_hw_up(struct sky2_port *sky2)
|
||||||
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
|
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
|
||||||
sky2->tx_ring_size - 1);
|
sky2->tx_ring_size - 1);
|
||||||
|
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
sky2_vlan_mode(sky2->netdev);
|
||||||
sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sky2_rx_start(sky2);
|
sky2_rx_start(sky2);
|
||||||
}
|
}
|
||||||
|
@ -1780,7 +1769,7 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl = 0;
|
ctrl = 0;
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
|
||||||
/* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
|
/* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
|
||||||
if (vlan_tx_tag_present(skb)) {
|
if (vlan_tx_tag_present(skb)) {
|
||||||
if (!le) {
|
if (!le) {
|
||||||
|
@ -1792,7 +1781,6 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
|
||||||
le->length = cpu_to_be16(vlan_tx_tag_get(skb));
|
le->length = cpu_to_be16(vlan_tx_tag_get(skb));
|
||||||
ctrl |= INS_VLAN;
|
ctrl |= INS_VLAN;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Handle TCP checksum offload */
|
/* Handle TCP checksum offload */
|
||||||
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||||
|
@ -2432,11 +2420,8 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
|
||||||
struct sk_buff *skb = NULL;
|
struct sk_buff *skb = NULL;
|
||||||
u16 count = (status & GMR_FS_LEN) >> 16;
|
u16 count = (status & GMR_FS_LEN) >> 16;
|
||||||
|
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
if (status & GMR_FS_VLAN)
|
||||||
/* Account for vlan tag */
|
count -= VLAN_HLEN; /* Account for vlan tag */
|
||||||
if (sky2->vlgrp && (status & GMR_FS_VLAN))
|
|
||||||
count -= VLAN_HLEN;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
netif_printk(sky2, rx_status, KERN_DEBUG, dev,
|
netif_printk(sky2, rx_status, KERN_DEBUG, dev,
|
||||||
"rx slot %u status 0x%x len %d\n",
|
"rx slot %u status 0x%x len %d\n",
|
||||||
|
@ -2504,17 +2489,9 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
|
||||||
static inline void sky2_skb_rx(const struct sky2_port *sky2,
|
static inline void sky2_skb_rx(const struct sky2_port *sky2,
|
||||||
u32 status, struct sk_buff *skb)
|
u32 status, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
if (status & GMR_FS_VLAN)
|
||||||
u16 vlan_tag = be16_to_cpu(sky2->rx_tag);
|
__vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
|
||||||
if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
|
|
||||||
if (skb->ip_summed == CHECKSUM_NONE)
|
|
||||||
vlan_hwaccel_receive_skb(skb, sky2->vlgrp, vlan_tag);
|
|
||||||
else
|
|
||||||
vlan_gro_receive(&sky2->hw->napi, sky2->vlgrp,
|
|
||||||
vlan_tag, skb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (skb->ip_summed == CHECKSUM_NONE)
|
if (skb->ip_summed == CHECKSUM_NONE)
|
||||||
netif_receive_skb(skb);
|
netif_receive_skb(skb);
|
||||||
else
|
else
|
||||||
|
@ -2631,7 +2608,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
|
||||||
goto exit_loop;
|
goto exit_loop;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
|
||||||
case OP_RXVLAN:
|
case OP_RXVLAN:
|
||||||
sky2->rx_tag = length;
|
sky2->rx_tag = length;
|
||||||
break;
|
break;
|
||||||
|
@ -2639,7 +2615,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
|
||||||
case OP_RXCHKSVLAN:
|
case OP_RXCHKSVLAN:
|
||||||
sky2->rx_tag = length;
|
sky2->rx_tag = length;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
#endif
|
|
||||||
case OP_RXCHKS:
|
case OP_RXCHKS:
|
||||||
if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
|
if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
|
||||||
sky2_rx_checksum(sky2, status);
|
sky2_rx_checksum(sky2, status);
|
||||||
|
@ -3042,6 +3017,10 @@ static int __devinit sky2_init(struct sky2_hw *hw)
|
||||||
| SKY2_HW_NEW_LE
|
| SKY2_HW_NEW_LE
|
||||||
| SKY2_HW_AUTO_TX_SUM
|
| SKY2_HW_AUTO_TX_SUM
|
||||||
| SKY2_HW_ADV_POWER_CTL;
|
| SKY2_HW_ADV_POWER_CTL;
|
||||||
|
|
||||||
|
/* The workaround for status conflicts VLAN tag detection. */
|
||||||
|
if (hw->chip_rev == CHIP_REV_YU_FE2_A0)
|
||||||
|
hw->flags |= SKY2_HW_VLAN_BROKEN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CHIP_ID_YUKON_SUPR:
|
case CHIP_ID_YUKON_SUPR:
|
||||||
|
@ -4237,16 +4216,29 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
|
||||||
static int sky2_set_flags(struct net_device *dev, u32 data)
|
static int sky2_set_flags(struct net_device *dev, u32 data)
|
||||||
{
|
{
|
||||||
struct sky2_port *sky2 = netdev_priv(dev);
|
struct sky2_port *sky2 = netdev_priv(dev);
|
||||||
u32 supported =
|
unsigned long old_feat = dev->features;
|
||||||
(sky2->hw->flags & SKY2_HW_RSS_BROKEN) ? 0 : ETH_FLAG_RXHASH;
|
u32 supported = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN))
|
||||||
|
supported |= ETH_FLAG_RXHASH;
|
||||||
|
|
||||||
|
if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN))
|
||||||
|
supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN;
|
||||||
|
|
||||||
|
printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n",
|
||||||
|
supported, data);
|
||||||
|
|
||||||
rc = ethtool_op_set_flags(dev, data, supported);
|
rc = ethtool_op_set_flags(dev, data, supported);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
if ((old_feat ^ dev->features) & NETIF_F_RXHASH)
|
||||||
rx_set_rss(dev);
|
rx_set_rss(dev);
|
||||||
|
|
||||||
|
if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN)
|
||||||
|
sky2_vlan_mode(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4281,6 +4273,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
|
||||||
.get_sset_count = sky2_get_sset_count,
|
.get_sset_count = sky2_get_sset_count,
|
||||||
.get_ethtool_stats = sky2_get_ethtool_stats,
|
.get_ethtool_stats = sky2_get_ethtool_stats,
|
||||||
.set_flags = sky2_set_flags,
|
.set_flags = sky2_set_flags,
|
||||||
|
.get_flags = ethtool_op_get_flags,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SKY2_DEBUG
|
#ifdef CONFIG_SKY2_DEBUG
|
||||||
|
@ -4562,9 +4555,6 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
|
||||||
.ndo_change_mtu = sky2_change_mtu,
|
.ndo_change_mtu = sky2_change_mtu,
|
||||||
.ndo_tx_timeout = sky2_tx_timeout,
|
.ndo_tx_timeout = sky2_tx_timeout,
|
||||||
.ndo_get_stats64 = sky2_get_stats,
|
.ndo_get_stats64 = sky2_get_stats,
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
|
||||||
.ndo_vlan_rx_register = sky2_vlan_rx_register,
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_poll_controller = sky2_netpoll,
|
.ndo_poll_controller = sky2_netpoll,
|
||||||
#endif
|
#endif
|
||||||
|
@ -4580,9 +4570,6 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
|
||||||
.ndo_change_mtu = sky2_change_mtu,
|
.ndo_change_mtu = sky2_change_mtu,
|
||||||
.ndo_tx_timeout = sky2_tx_timeout,
|
.ndo_tx_timeout = sky2_tx_timeout,
|
||||||
.ndo_get_stats64 = sky2_get_stats,
|
.ndo_get_stats64 = sky2_get_stats,
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
|
||||||
.ndo_vlan_rx_register = sky2_vlan_rx_register,
|
|
||||||
#endif
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4634,6 +4621,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
|
||||||
|
|
||||||
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG
|
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG
|
||||||
| NETIF_F_TSO | NETIF_F_GRO;
|
| NETIF_F_TSO | NETIF_F_GRO;
|
||||||
|
|
||||||
if (highmem)
|
if (highmem)
|
||||||
dev->features |= NETIF_F_HIGHDMA;
|
dev->features |= NETIF_F_HIGHDMA;
|
||||||
|
|
||||||
|
@ -4641,13 +4629,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
|
||||||
if (!(hw->flags & SKY2_HW_RSS_BROKEN))
|
if (!(hw->flags & SKY2_HW_RSS_BROKEN))
|
||||||
dev->features |= NETIF_F_RXHASH;
|
dev->features |= NETIF_F_RXHASH;
|
||||||
|
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
if (!(hw->flags & SKY2_HW_VLAN_BROKEN))
|
||||||
/* The workaround for FE+ status conflicts with VLAN tag detection. */
|
|
||||||
if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
|
|
||||||
sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) {
|
|
||||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* read the mac address */
|
/* read the mac address */
|
||||||
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
|
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
|
||||||
|
|
|
@ -2236,11 +2236,8 @@ struct sky2_port {
|
||||||
u16 rx_pending;
|
u16 rx_pending;
|
||||||
u16 rx_data_size;
|
u16 rx_data_size;
|
||||||
u16 rx_nfrags;
|
u16 rx_nfrags;
|
||||||
|
|
||||||
#ifdef SKY2_VLAN_TAG_USED
|
|
||||||
u16 rx_tag;
|
u16 rx_tag;
|
||||||
struct vlan_group *vlgrp;
|
|
||||||
#endif
|
|
||||||
struct {
|
struct {
|
||||||
unsigned long last;
|
unsigned long last;
|
||||||
u32 mac_rp;
|
u32 mac_rp;
|
||||||
|
@ -2284,6 +2281,7 @@ struct sky2_hw {
|
||||||
#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
|
#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
|
||||||
#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
|
#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
|
||||||
#define SKY2_HW_RSS_BROKEN 0x00000100
|
#define SKY2_HW_RSS_BROKEN 0x00000100
|
||||||
|
#define SKY2_HW_VLAN_BROKEN 0x00000200
|
||||||
|
|
||||||
u8 chip_id;
|
u8 chip_id;
|
||||||
u8 chip_rev;
|
u8 chip_rev;
|
||||||
|
|
Loading…
Reference in a new issue