diff options
-rw-r--r-- | drivers/net/sky2.c | 79 | ||||
-rw-r--r-- | drivers/net/sky2.h | 14 |
2 files changed, 91 insertions, 2 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4f83f111bb20..a1b17fa34c76 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) */ | ||
1197 | static 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 | ||
2573 | static 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 */ |
2538 | static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) | 2582 | static 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 | ||
4166 | static 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 | ||
4116 | static const struct ethtool_ops sky2_ethtool_ops = { | 4186 | static 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) |
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 125b5bd01524..545a3f41ef56 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h | |||
@@ -694,8 +694,21 @@ enum { | |||
694 | TXA_CTRL = 0x0210,/* 8 bit Tx Arbiter Control Register */ | 694 | TXA_CTRL = 0x0210,/* 8 bit Tx Arbiter Control Register */ |
695 | TXA_TEST = 0x0211,/* 8 bit Tx Arbiter Test Register */ | 695 | TXA_TEST = 0x0211,/* 8 bit Tx Arbiter Test Register */ |
696 | TXA_STAT = 0x0212,/* 8 bit Tx Arbiter Status Register */ | 696 | TXA_STAT = 0x0212,/* 8 bit Tx Arbiter Status Register */ |
697 | |||
698 | RSS_KEY = 0x0220, /* RSS Key setup */ | ||
699 | RSS_CFG = 0x0248, /* RSS Configuration */ | ||
697 | }; | 700 | }; |
698 | 701 | ||
702 | enum { | ||
703 | HASH_TCP_IPV6_EX_CTRL = 1<<5, | ||
704 | HASH_IPV6_EX_CTRL = 1<<4, | ||
705 | HASH_TCP_IPV6_CTRL = 1<<3, | ||
706 | HASH_IPV6_CTRL = 1<<2, | ||
707 | HASH_TCP_IPV4_CTRL = 1<<1, | ||
708 | HASH_IPV4_CTRL = 1<<0, | ||
709 | |||
710 | HASH_ALL = 0x3f, | ||
711 | }; | ||
699 | 712 | ||
700 | enum { | 713 | enum { |
701 | B6_EXT_REG = 0x0300,/* External registers (GENESIS only) */ | 714 | B6_EXT_REG = 0x0300,/* External registers (GENESIS only) */ |
@@ -2261,6 +2274,7 @@ struct sky2_hw { | |||
2261 | #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ | 2274 | #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ |
2262 | #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ | 2275 | #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ |
2263 | #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ | 2276 | #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ |
2277 | #define SKY2_HW_RSS_BROKEN 0x00000100 | ||
2264 | 2278 | ||
2265 | u8 chip_id; | 2279 | u8 chip_id; |
2266 | u8 chip_rev; | 2280 | u8 chip_rev; |