aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2010-04-24 23:04:12 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-24 23:04:12 -0400
commitbf73130d7f98c8c4db143e2dc4982f4eefd5d5e5 (patch)
tree19a73b4ce836c4a7224706de5febb77ab1ca0c7f /drivers/net/sky2.c
parentb7d6a4321195c32b548f0185a2fa0b8f6e02bcfc (diff)
sky2: add support for receive hashing
Sky2 hardware supports hardware receive hash calculation. Now that Receive Packet Steering is available, add support to enable it. This version does not depend on CONFIG_RPS. Also set_flags rejects all values except RXHASH, so driver won't have to change next time somebody adds a new one. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c79
1 files changed, 77 insertions, 2 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 4f83f111bb2..a1b17fa34c7 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1193,6 +1193,39 @@ static void rx_set_checksum(struct sky2_port *sky2)
1193 ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); 1193 ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
1194} 1194}
1195 1195
1196/* Enable/disable receive hash calculation (RSS) */
1197static void rx_set_rss(struct net_device *dev)
1198{
1199 struct sky2_port *sky2 = netdev_priv(dev);
1200 struct sky2_hw *hw = sky2->hw;
1201 int i, nkeys = 4;
1202
1203 /* Supports IPv6 and other modes */
1204 if (hw->flags & SKY2_HW_NEW_LE) {
1205 nkeys = 10;
1206 sky2_write32(hw, SK_REG(sky2->port, RSS_CFG), HASH_ALL);
1207 }
1208
1209 /* Program RSS initial values */
1210 if (dev->features & NETIF_F_RXHASH) {
1211 u32 key[nkeys];
1212
1213 get_random_bytes(key, nkeys * sizeof(u32));
1214 for (i = 0; i < nkeys; i++)
1215 sky2_write32(hw, SK_REG(sky2->port, RSS_KEY + i * 4),
1216 key[i]);
1217
1218 /* Need to turn on (undocumented) flag to make hashing work */
1219 sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T),
1220 RX_STFW_ENA);
1221
1222 sky2_write32(hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
1223 BMU_ENA_RX_RSS_HASH);
1224 } else
1225 sky2_write32(hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
1226 BMU_DIS_RX_RSS_HASH);
1227}
1228
1196/* 1229/*
1197 * The RX Stop command will not work for Yukon-2 if the BMU does not 1230 * The RX Stop command will not work for Yukon-2 if the BMU does not
1198 * reach the end of packet and since we can't make sure that we have 1231 * reach the end of packet and since we can't make sure that we have
@@ -1425,6 +1458,9 @@ static void sky2_rx_start(struct sky2_port *sky2)
1425 if (!(hw->flags & SKY2_HW_NEW_LE)) 1458 if (!(hw->flags & SKY2_HW_NEW_LE))
1426 rx_set_checksum(sky2); 1459 rx_set_checksum(sky2);
1427 1460
1461 if (!(hw->flags & SKY2_HW_RSS_BROKEN))
1462 rx_set_rss(sky2->netdev);
1463
1428 /* submit Rx ring */ 1464 /* submit Rx ring */
1429 for (i = 0; i < sky2->rx_pending; i++) { 1465 for (i = 0; i < sky2->rx_pending; i++) {
1430 re = sky2->rx_ring + i; 1466 re = sky2->rx_ring + i;
@@ -2534,6 +2570,14 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
2534 } 2570 }
2535} 2571}
2536 2572
2573static void sky2_rx_hash(struct sky2_port *sky2, u32 status)
2574{
2575 struct sk_buff *skb;
2576
2577 skb = sky2->rx_ring[sky2->rx_next].skb;
2578 skb->rxhash = le32_to_cpu(status);
2579}
2580
2537/* Process status response ring */ 2581/* Process status response ring */
2538static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) 2582static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
2539{ 2583{
@@ -2606,6 +2650,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
2606 sky2_rx_checksum(sky2, status); 2650 sky2_rx_checksum(sky2, status);
2607 break; 2651 break;
2608 2652
2653 case OP_RSS_HASH:
2654 sky2_rx_hash(sky2, status);
2655 break;
2656
2609 case OP_TXINDEXLE: 2657 case OP_TXINDEXLE:
2610 /* TX index reports status for both ports */ 2658 /* TX index reports status for both ports */
2611 sky2_tx_done(hw->dev[0], status & 0xfff); 2659 sky2_tx_done(hw->dev[0], status & 0xfff);
@@ -2960,6 +3008,8 @@ static int __devinit sky2_init(struct sky2_hw *hw)
2960 switch(hw->chip_id) { 3008 switch(hw->chip_id) {
2961 case CHIP_ID_YUKON_XL: 3009 case CHIP_ID_YUKON_XL:
2962 hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY; 3010 hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
3011 if (hw->chip_rev < CHIP_REV_YU_XL_A2)
3012 hw->flags |= SKY2_HW_RSS_BROKEN;
2963 break; 3013 break;
2964 3014
2965 case CHIP_ID_YUKON_EC_U: 3015 case CHIP_ID_YUKON_EC_U:
@@ -2985,10 +3035,11 @@ static int __devinit sky2_init(struct sky2_hw *hw)
2985 dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n"); 3035 dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
2986 return -EOPNOTSUPP; 3036 return -EOPNOTSUPP;
2987 } 3037 }
2988 hw->flags = SKY2_HW_GIGABIT; 3038 hw->flags = SKY2_HW_GIGABIT | SKY2_HW_RSS_BROKEN;
2989 break; 3039 break;
2990 3040
2991 case CHIP_ID_YUKON_FE: 3041 case CHIP_ID_YUKON_FE:
3042 hw->flags = SKY2_HW_RSS_BROKEN;
2992 break; 3043 break;
2993 3044
2994 case CHIP_ID_YUKON_FE_P: 3045 case CHIP_ID_YUKON_FE_P:
@@ -4112,6 +4163,25 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
4112 return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len); 4163 return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
4113} 4164}
4114 4165
4166static int sky2_set_flags(struct net_device *dev, u32 data)
4167{
4168 struct sky2_port *sky2 = netdev_priv(dev);
4169
4170 if (data & ~ETH_FLAG_RXHASH)
4171 return -EOPNOTSUPP;
4172
4173 if (data & ETH_FLAG_RXHASH) {
4174 if (sky2->hw->flags & SKY2_HW_RSS_BROKEN)
4175 return -EINVAL;
4176
4177 dev->features |= NETIF_F_RXHASH;
4178 } else
4179 dev->features &= ~NETIF_F_RXHASH;
4180
4181 rx_set_rss(dev);
4182
4183 return 0;
4184}
4115 4185
4116static const struct ethtool_ops sky2_ethtool_ops = { 4186static const struct ethtool_ops sky2_ethtool_ops = {
4117 .get_settings = sky2_get_settings, 4187 .get_settings = sky2_get_settings,
@@ -4143,6 +4213,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
4143 .phys_id = sky2_phys_id, 4213 .phys_id = sky2_phys_id,
4144 .get_sset_count = sky2_get_sset_count, 4214 .get_sset_count = sky2_get_sset_count,
4145 .get_ethtool_stats = sky2_get_ethtool_stats, 4215 .get_ethtool_stats = sky2_get_ethtool_stats,
4216 .set_flags = sky2_set_flags,
4146}; 4217};
4147 4218
4148#ifdef CONFIG_SKY2_DEBUG 4219#ifdef CONFIG_SKY2_DEBUG
@@ -4496,6 +4567,10 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
4496 if (highmem) 4567 if (highmem)
4497 dev->features |= NETIF_F_HIGHDMA; 4568 dev->features |= NETIF_F_HIGHDMA;
4498 4569
4570 /* Enable receive hashing unless hardware is known broken */
4571 if (!(hw->flags & SKY2_HW_RSS_BROKEN))
4572 dev->features |= NETIF_F_RXHASH;
4573
4499#ifdef SKY2_VLAN_TAG_USED 4574#ifdef SKY2_VLAN_TAG_USED
4500 /* The workaround for FE+ status conflicts with VLAN tag detection. */ 4575 /* The workaround for FE+ status conflicts with VLAN tag detection. */
4501 if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P && 4576 if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
@@ -4692,7 +4767,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
4692 goto err_out_iounmap; 4767 goto err_out_iounmap;
4693 4768
4694 /* ring for status responses */ 4769 /* ring for status responses */
4695 hw->st_size = hw->ports * roundup_pow_of_two(2*RX_MAX_PENDING + TX_MAX_PENDING); 4770 hw->st_size = hw->ports * roundup_pow_of_two(3*RX_MAX_PENDING + TX_MAX_PENDING);
4696 hw->st_le = pci_alloc_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le), 4771 hw->st_le = pci_alloc_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
4697 &hw->st_dma); 4772 &hw->st_dma);
4698 if (!hw->st_le) 4773 if (!hw->st_le)