mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
net: sky2: convert to hw_features
Caveats: - driver modifies vlan_features on HW VLAN TX changes - broken RX checksum will be reenabled on features change Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
872674858f
commit
f5d640371d
@ -1198,12 +1198,12 @@ static void rx_set_checksum(struct sky2_port *sky2)
|
||||
|
||||
sky2_write32(sky2->hw,
|
||||
Q_ADDR(rxqaddr[sky2->port], Q_CSR),
|
||||
(sky2->flags & SKY2_FLAG_RX_CHECKSUM)
|
||||
(sky2->netdev->features & NETIF_F_RXCSUM)
|
||||
? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
|
||||
}
|
||||
|
||||
/* Enable/disable receive hash calculation (RSS) */
|
||||
static void rx_set_rss(struct net_device *dev)
|
||||
static void rx_set_rss(struct net_device *dev, u32 features)
|
||||
{
|
||||
struct sky2_port *sky2 = netdev_priv(dev);
|
||||
struct sky2_hw *hw = sky2->hw;
|
||||
@ -1216,7 +1216,7 @@ static void rx_set_rss(struct net_device *dev)
|
||||
}
|
||||
|
||||
/* Program RSS initial values */
|
||||
if (dev->features & NETIF_F_RXHASH) {
|
||||
if (features & NETIF_F_RXHASH) {
|
||||
u32 key[nkeys];
|
||||
|
||||
get_random_bytes(key, nkeys * sizeof(u32));
|
||||
@ -1322,32 +1322,32 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
return err;
|
||||
}
|
||||
|
||||
#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)
|
||||
#define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO)
|
||||
|
||||
static void sky2_vlan_mode(struct net_device *dev)
|
||||
static void sky2_vlan_mode(struct net_device *dev, u32 features)
|
||||
{
|
||||
struct sky2_port *sky2 = netdev_priv(dev);
|
||||
struct sky2_hw *hw = sky2->hw;
|
||||
u16 port = sky2->port;
|
||||
|
||||
if (dev->features & NETIF_F_HW_VLAN_RX)
|
||||
if (features & NETIF_F_HW_VLAN_RX)
|
||||
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);
|
||||
|
||||
dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN;
|
||||
if (dev->features & NETIF_F_HW_VLAN_TX)
|
||||
if (features & NETIF_F_HW_VLAN_TX) {
|
||||
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
|
||||
TX_VLAN_TAG_ON);
|
||||
else {
|
||||
|
||||
dev->vlan_features |= SKY2_VLAN_OFFLOADS;
|
||||
} else {
|
||||
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
|
||||
TX_VLAN_TAG_OFF);
|
||||
|
||||
/* Can't do transmit offload of vlan without hw vlan */
|
||||
dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG
|
||||
| NETIF_F_ALL_CSUM);
|
||||
dev->vlan_features &= ~SKY2_VLAN_OFFLOADS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1463,7 +1463,7 @@ static void sky2_rx_start(struct sky2_port *sky2)
|
||||
rx_set_checksum(sky2);
|
||||
|
||||
if (!(hw->flags & SKY2_HW_RSS_BROKEN))
|
||||
rx_set_rss(sky2->netdev);
|
||||
rx_set_rss(sky2->netdev, sky2->netdev->features);
|
||||
|
||||
/* submit Rx ring */
|
||||
for (i = 0; i < sky2->rx_pending; i++) {
|
||||
@ -1626,7 +1626,8 @@ static void sky2_hw_up(struct sky2_port *sky2)
|
||||
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
|
||||
sky2->tx_ring_size - 1);
|
||||
|
||||
sky2_vlan_mode(sky2->netdev);
|
||||
sky2_vlan_mode(sky2->netdev, sky2->netdev->features);
|
||||
netdev_update_features(sky2->netdev);
|
||||
|
||||
sky2_rx_start(sky2);
|
||||
}
|
||||
@ -2261,12 +2262,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
|
||||
hw->chip_id == CHIP_ID_YUKON_FE_P))
|
||||
return -EINVAL;
|
||||
|
||||
/* TSO, etc on Yukon Ultra and MTU > 1500 not supported */
|
||||
if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U)
|
||||
dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM);
|
||||
|
||||
if (!netif_running(dev)) {
|
||||
dev->mtu = new_mtu;
|
||||
netdev_update_features(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2288,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
|
||||
sky2_rx_clean(sky2);
|
||||
|
||||
dev->mtu = new_mtu;
|
||||
netdev_update_features(dev);
|
||||
|
||||
mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |
|
||||
GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
|
||||
@ -2535,8 +2534,11 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
|
||||
"%s: receive checksum problem (status = %#x)\n",
|
||||
sky2->netdev->name, status);
|
||||
|
||||
/* Disable checksum offload */
|
||||
sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
|
||||
/* Disable checksum offload
|
||||
* It will be reenabled on next ndo_set_features, but if it's
|
||||
* really broken, will get disabled again
|
||||
*/
|
||||
sky2->netdev->features &= ~NETIF_F_RXCSUM;
|
||||
sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
|
||||
BMU_DIS_RX_CHKSUM);
|
||||
}
|
||||
@ -2591,7 +2593,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
|
||||
|
||||
/* This chip reports checksum status differently */
|
||||
if (hw->flags & SKY2_HW_NEW_LE) {
|
||||
if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) &&
|
||||
if ((dev->features & NETIF_F_RXCSUM) &&
|
||||
(le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
|
||||
(le->css & CSS_TCPUDPCSOK))
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
@ -2616,7 +2618,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
|
||||
sky2->rx_tag = length;
|
||||
/* fall through */
|
||||
case OP_RXCHKS:
|
||||
if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
|
||||
if (likely(dev->features & NETIF_F_RXCSUM))
|
||||
sky2_rx_checksum(sky2, status);
|
||||
break;
|
||||
|
||||
@ -3552,28 +3554,6 @@ static const struct sky2_stat {
|
||||
{ "tx_fifo_underrun", GM_TXE_FIFO_UR },
|
||||
};
|
||||
|
||||
static u32 sky2_get_rx_csum(struct net_device *dev)
|
||||
{
|
||||
struct sky2_port *sky2 = netdev_priv(dev);
|
||||
|
||||
return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM);
|
||||
}
|
||||
|
||||
static int sky2_set_rx_csum(struct net_device *dev, u32 data)
|
||||
{
|
||||
struct sky2_port *sky2 = netdev_priv(dev);
|
||||
|
||||
if (data)
|
||||
sky2->flags |= SKY2_FLAG_RX_CHECKSUM;
|
||||
else
|
||||
sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
|
||||
|
||||
sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
|
||||
data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 sky2_get_msglevel(struct net_device *netdev)
|
||||
{
|
||||
struct sky2_port *sky2 = netdev_priv(netdev);
|
||||
@ -4084,34 +4064,6 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
|
||||
}
|
||||
}
|
||||
|
||||
/* In order to do Jumbo packets on these chips, need to turn off the
|
||||
* transmit store/forward. Therefore checksum offload won't work.
|
||||
*/
|
||||
static int no_tx_offload(struct net_device *dev)
|
||||
{
|
||||
const struct sky2_port *sky2 = netdev_priv(dev);
|
||||
const struct sky2_hw *hw = sky2->hw;
|
||||
|
||||
return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U;
|
||||
}
|
||||
|
||||
static int sky2_set_tx_csum(struct net_device *dev, u32 data)
|
||||
{
|
||||
if (data && no_tx_offload(dev))
|
||||
return -EINVAL;
|
||||
|
||||
return ethtool_op_set_tx_csum(dev, data);
|
||||
}
|
||||
|
||||
|
||||
static int sky2_set_tso(struct net_device *dev, u32 data)
|
||||
{
|
||||
if (data && no_tx_offload(dev))
|
||||
return -EINVAL;
|
||||
|
||||
return ethtool_op_set_tso(dev, data);
|
||||
}
|
||||
|
||||
static int sky2_get_eeprom_len(struct net_device *dev)
|
||||
{
|
||||
struct sky2_port *sky2 = netdev_priv(dev);
|
||||
@ -4214,31 +4166,36 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
|
||||
return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
|
||||
}
|
||||
|
||||
static int sky2_set_flags(struct net_device *dev, u32 data)
|
||||
static u32 sky2_fix_features(struct net_device *dev, u32 features)
|
||||
{
|
||||
const struct sky2_port *sky2 = netdev_priv(dev);
|
||||
const struct sky2_hw *hw = sky2->hw;
|
||||
|
||||
/* In order to do Jumbo packets on these chips, need to turn off the
|
||||
* transmit store/forward. Therefore checksum offload won't work.
|
||||
*/
|
||||
if (dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U)
|
||||
features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM);
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
static int sky2_set_features(struct net_device *dev, u32 features)
|
||||
{
|
||||
struct sky2_port *sky2 = netdev_priv(dev);
|
||||
unsigned long old_feat = dev->features;
|
||||
u32 supported = 0;
|
||||
int rc;
|
||||
u32 changed = dev->features ^ features;
|
||||
|
||||
if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN))
|
||||
supported |= ETH_FLAG_RXHASH;
|
||||
if (changed & NETIF_F_RXCSUM) {
|
||||
u32 on = features & NETIF_F_RXCSUM;
|
||||
sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
|
||||
on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
|
||||
}
|
||||
|
||||
if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN))
|
||||
supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN;
|
||||
if (changed & NETIF_F_RXHASH)
|
||||
rx_set_rss(dev, features);
|
||||
|
||||
printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n",
|
||||
supported, data);
|
||||
|
||||
rc = ethtool_op_set_flags(dev, data, supported);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if ((old_feat ^ dev->features) & NETIF_F_RXHASH)
|
||||
rx_set_rss(dev);
|
||||
|
||||
if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN)
|
||||
sky2_vlan_mode(dev);
|
||||
if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
|
||||
sky2_vlan_mode(dev, features);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4258,11 +4215,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {
|
||||
.get_eeprom_len = sky2_get_eeprom_len,
|
||||
.get_eeprom = sky2_get_eeprom,
|
||||
.set_eeprom = sky2_set_eeprom,
|
||||
.set_sg = ethtool_op_set_sg,
|
||||
.set_tx_csum = sky2_set_tx_csum,
|
||||
.set_tso = sky2_set_tso,
|
||||
.get_rx_csum = sky2_get_rx_csum,
|
||||
.set_rx_csum = sky2_set_rx_csum,
|
||||
.get_strings = sky2_get_strings,
|
||||
.get_coalesce = sky2_get_coalesce,
|
||||
.set_coalesce = sky2_set_coalesce,
|
||||
@ -4273,8 +4225,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {
|
||||
.set_phys_id = sky2_set_phys_id,
|
||||
.get_sset_count = sky2_get_sset_count,
|
||||
.get_ethtool_stats = sky2_get_ethtool_stats,
|
||||
.set_flags = sky2_set_flags,
|
||||
.get_flags = ethtool_op_get_flags,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SKY2_DEBUG
|
||||
@ -4554,6 +4504,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
|
||||
.ndo_set_mac_address = sky2_set_mac_address,
|
||||
.ndo_set_multicast_list = sky2_set_multicast,
|
||||
.ndo_change_mtu = sky2_change_mtu,
|
||||
.ndo_fix_features = sky2_fix_features,
|
||||
.ndo_set_features = sky2_set_features,
|
||||
.ndo_tx_timeout = sky2_tx_timeout,
|
||||
.ndo_get_stats64 = sky2_get_stats,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
@ -4569,6 +4521,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
|
||||
.ndo_set_mac_address = sky2_set_mac_address,
|
||||
.ndo_set_multicast_list = sky2_set_multicast,
|
||||
.ndo_change_mtu = sky2_change_mtu,
|
||||
.ndo_fix_features = sky2_fix_features,
|
||||
.ndo_set_features = sky2_set_features,
|
||||
.ndo_tx_timeout = sky2_tx_timeout,
|
||||
.ndo_get_stats64 = sky2_get_stats,
|
||||
},
|
||||
@ -4601,7 +4555,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
|
||||
/* Auto speed and flow control */
|
||||
sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE;
|
||||
if (hw->chip_id != CHIP_ID_YUKON_XL)
|
||||
sky2->flags |= SKY2_FLAG_RX_CHECKSUM;
|
||||
dev->hw_features |= NETIF_F_RXCSUM;
|
||||
|
||||
sky2->flow_mode = FC_BOTH;
|
||||
|
||||
@ -4620,18 +4574,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
|
||||
|
||||
sky2->port = port;
|
||||
|
||||
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG
|
||||
| NETIF_F_TSO | NETIF_F_GRO;
|
||||
dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO;
|
||||
|
||||
if (highmem)
|
||||
dev->features |= NETIF_F_HIGHDMA;
|
||||
|
||||
/* Enable receive hashing unless hardware is known broken */
|
||||
if (!(hw->flags & SKY2_HW_RSS_BROKEN))
|
||||
dev->features |= NETIF_F_RXHASH;
|
||||
dev->hw_features |= NETIF_F_RXHASH;
|
||||
|
||||
if (!(hw->flags & SKY2_HW_VLAN_BROKEN))
|
||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) {
|
||||
dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
dev->vlan_features |= SKY2_VLAN_OFFLOADS;
|
||||
}
|
||||
|
||||
dev->features |= dev->hw_features;
|
||||
|
||||
/* read the mac address */
|
||||
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
|
||||
|
@ -2254,7 +2254,6 @@ struct sky2_port {
|
||||
u8 wol; /* WAKE_ bits */
|
||||
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
|
||||
u16 flags;
|
||||
#define SKY2_FLAG_RX_CHECKSUM 0x0001
|
||||
#define SKY2_FLAG_AUTO_SPEED 0x0002
|
||||
#define SKY2_FLAG_AUTO_PAUSE 0x0004
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user