sky2: size status ring based on Tx/Rx ring
Subsystems (2)
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/2 sky2: size status ring based on Tx/Rx ring
Sky2 status ring must be big enough to handle worst case number of status messages. It was being oversized (to handle dual port cards), and excessive number of tx ring entries were allowed. This patch reduces the footprint and makes sure the value is enough.
Later patch to add RSS increases the number of possible Rx status elements.
---
drivers/net/sky2.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++-- drivers/net/sky2.h | 23 ++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-)
drivers/net/sky2.c +19 -16
@@ -70,18 +70,15 @@VLAN:GSO + CKSUM + Data + skb_frags * DMA */ #define MAX_SKB_TX_LE (2 + (sizeof(dma_addr_t)/sizeof(u32))*(MAX_SKB_FRAGS+1))#define TX_MIN_PENDING (MAX_SKB_TX_LE+1) -#define TX_MAX_PENDING 4096 +#define TX_MAX_PENDING 1024#define TX_DEF_PENDING 127 -#define STATUS_RING_SIZE 2048/* 2 ports * (TX + 2*RX) */ -#define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le))#define TX_WATCHDOG (5 * HZ)#define NAPI_WEIGHT 64#define PHY_RETRIES 1000#define SKY2_EEPROM_MAGIC 0x9955aabb -#define RING_NEXT (x,s) (((x)+1) & ((s)-1)) static const u32 default_msg =
@@ -2558,7 +2555,7 @@ static int sky2_status_intr(struct sky2_if (!(opcode &HW_OWNER ))break ; - hw->st_idx =RING_NEXT (hw->st_idx,STATUS_RING_SIZE ); + hw->st_idx =RING_NEXT (hw->st_idx, hw->st_size); port = le->css &CSS_LINK_BIT ; dev = hw->dev[port];
@@ -3198,7 +3195,7 @@ static void sky2_reset(struct sky2_hw *hfor (i =0 ; i < hw->ports; i++)sky2_gmac_reset (hw, i); -memset (hw->st_le,0 ,STATUS_LE_BYTES ); +memset (hw->st_le,0 , hw->st_size *sizeof (struct sky2_status_le )); hw->st_idx =0 ;sky2_write32 (hw,STAT_CTRL ,SC_STAT_RST_SET );
@@ -3208,7 +3205,7 @@ static void sky2_reset(struct sky2_hw *hsky2_write32 (hw,STAT_LIST_ADDR_HI , (u64 ) hw->st_dma >>32 );/* Set the list last index */ -sky2_write16 (hw,STAT_LAST_IDX ,STATUS_RING_SIZE -1 ); +sky2_write16 (hw,STAT_LAST_IDX , hw->st_size -1 );sky2_write16 (hw,STAT_TX_IDX_TH ,10 );sky2_write8 (hw,STAT_FIFO_WM ,16 );
@@ -4256,12 +4253,13 @@ static int sky2_debug_show(struct seq_finapi_disable (&hw->napi); last =sky2_read16 (hw,STAT_PUT_IDX ); +seq_printf (seq,"Status ring %u\n" , hw->st_size);if (hw->st_idx == last)seq_puts (seq,"Status ring (empty)\n" );else {seq_puts (seq,"Status ring\n" ); -for (idx = hw->st_idx; idx != last && idx <STATUS_RING_SIZE ; - idx =RING_NEXT (idx,STATUS_RING_SIZE )) { +for (idx = hw->st_idx; idx != last && idx < hw->st_size; + idx =RING_NEXT (idx, hw->st_size)) {const struct sky2_status_le *le = hw->st_le + idx;seq_printf (seq,"[%d] %#x %d %#x\n" , idx, le->opcode, le->length, le->status);
@@ -4689,15 +4687,17 @@ static int __devinit sky2_probe(struct p goto err_out_free_hw; } -/* ring for status responses */ - hw->st_le =pci_alloc_consistent (pdev,STATUS_LE_BYTES , &hw->st_dma); -if (!hw->st_le) - goto err_out_iounmap; - err =sky2_init (hw);if (err) goto err_out_iounmap; +/* ring for status responses */ + hw->st_size = hw->ports *roundup_pow_of_two (2 *RX_MAX_PENDING +TX_MAX_PENDING ); + hw->st_le =pci_alloc_consistent (pdev, hw->st_size *sizeof (struct sky2_status_le ), + &hw->st_dma); +if (!hw->st_le) + goto err_out_reset; +dev_info (&pdev->dev,"Yukon-2 %s chip revision %d\n" ,sky2_name (hw->chip_id, buf1,sizeof (buf1)), hw->chip_rev);
@@ -4771,8 +4771,10 @@ err_out_unregister: err_out_free_netdev:free_netdev (dev); err_out_free_pci: +pci_free_consistent (pdev, hw->st_size *sizeof (struct sky2_status_le ), + hw->st_le, hw->st_dma); +err_out_reset:sky2_write8 (hw,B0_CTST ,CS_RST_SET ); -pci_free_consistent (pdev,STATUS_LE_BYTES , hw->st_le, hw->st_dma); err_out_iounmap:iounmap (hw->regs); err_out_free_hw:
@@ -4810,7 +4812,8 @@ static void __devexit sky2_remove(structfree_irq (pdev->irq, hw);if (hw->flags &SKY2_HW_USE_MSI )pci_disable_msi (pdev); -pci_free_consistent (pdev,STATUS_LE_BYTES , hw->st_le, hw->st_dma); +pci_free_consistent (pdev, hw->st_size *sizeof (struct sky2_status_le ), + hw->st_le, hw->st_dma);pci_release_regions (pdev);pci_disable_device (pdev);
drivers/net/sky2.h +1 -0
@@ -2268,6 +2268,7 @@ struct sky2_hw {u8 ports;struct sky2_status_le *st_le; +u32 st_size;u32 st_idx;dma_addr_t st_dma;
From: Stephen Hemminger <[email protected]>
Date: Thu, 22 Apr 2010 16:42:56 -0700
Quoted 8 lines
Sky2 status ring must be big enough to handle worst case number of status messages. It was being oversized (to handle dual port cards), and excessive number of tx ring entries were allowed. This patch reduces the footprint and makes sure the value is enough.
Later patch to add RSS increases the number of possible Rx status elements.
Signed-off-by Stephen Hemminger <[email protected]>
Applied to net-next-2.6
PATCH 2/2 sky2: add support for receive hashing
In reply to a message not in the archiveSky2 hardware supports hardware receive hash calculation. This enables it unless the chip is probably broken. The list of broken devices is derived from vendor sk98lin which has fragments of code for RSS support but never uses it. Setup information for this in the chip documention is incomplete, so some of this is just best guess.
--- drivers/net/sky2.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++-- drivers/net/sky2.h | 23 ++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-)
drivers/net/sky2.c +81 -2
@@ -1193,6 +1193,39 @@ static void rx_set_checksum(struct sky2_ ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } +/* Enable/disable receive hash calculation (RSS) */ +static void rx_set_rss (struct net_device *dev) +{ +struct sky2_port *sky2 =netdev_priv (dev); +struct sky2_hw *hw = sky2->hw; +int i, nkeys =4 ; + +/* Supports IPv6 and other modes */ +if (hw->flags &SKY2_HW_NEW_LE ) { + nkeys =10 ; +sky2_write32 (hw,SK_REG (sky2->port,RSS_CFG ),HASH_ALL ); + } + +/* Program RSS initial values */ +if (dev->features &NETIF_F_RXHASH ) { +u32 key[nkeys]; + +get_random_bytes (key, nkeys *sizeof (u32)); +for (i =0 ; i < nkeys; i++) +sky2_write32 (hw,SK_REG (sky2->port,RSS_KEY + i *4 ), + key[i]); + +/* Need to turn on (undocumented) flag to make hashing work */ +sky2_write32 (hw,SK_REG (sky2->port,RX_GMF_CTRL_T ), +RX_STFW_ENA ); + +sky2_write32 (hw,Q_ADDR (rxqaddr[sky2->port],Q_CSR ), +BMU_ENA_RX_RSS_HASH ); + }else +sky2_write32 (hw,Q_ADDR (rxqaddr[sky2->port],Q_CSR ), +BMU_DIS_RX_RSS_HASH ); +} +/* * The RX Stop command will not work for Yukon-2 if the BMU does not * 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_poif (!(hw->flags &SKY2_HW_NEW_LE ))rx_set_checksum (sky2); +if (!(hw->flags &SKY2_HW_RSS_BROKEN )) +rx_set_rss (sky2->netdev); +/* submit Rx ring */ for (i =0 ; i < sky2->rx_pending; i++) { re = sky2->rx_ring + i;
@@ -2534,6 +2570,14 @@ static void sky2_rx_checksum(struct sky2 } } +static void sky2_rx_hash (struct sky2_port *sky2,u32 status) +{ +struct sk_buff *skb; + + skb = sky2->rx_ring[sky2->rx_next].skb; + skb->rxhash =le32_to_cpu (status); +} +/* Process status response ring */ static int sky2_status_intr (struct sky2_hw *hw,int to_do,u16 idx) {
@@ -2606,6 +2650,10 @@ static int sky2_status_intr(struct sky2_sky2_rx_checksum (sky2, status);break ; +case OP_RSS_HASH : +sky2_rx_hash (sky2, status); +break ; +case OP_TXINDEXLE :/* TX index reports status for both ports */ sky2_tx_done (hw->dev[0 ], status &0xfff );
@@ -2960,6 +3008,8 @@ static int __devinit sky2_init(struct skswitch (hw->chip_id) {case CHIP_ID_YUKON_XL : hw->flags =SKY2_HW_GIGABIT |SKY2_HW_NEWER_PHY ; +if (hw->chip_rev <CHIP_REV_YU_XL_A2 ) + hw->flags |=SKY2_HW_RSS_BROKEN ;break ;case CHIP_ID_YUKON_EC_U :
@@ -2985,10 +3035,11 @@ static int __devinit sky2_init(struct skdev_err (&hw->pdev->dev,"unsupported revision Yukon-EC rev A1\n" );return -EOPNOTSUPP ; } - hw->flags =SKY2_HW_GIGABIT ; + hw->flags =SKY2_HW_GIGABIT |SKY2_HW_RSS_BROKEN ;break ;case CHIP_ID_YUKON_FE : + hw->flags =SKY2_HW_RSS_BROKEN ;break ;case CHIP_ID_YUKON_FE_P :
@@ -4112,6 +4163,28 @@ static int sky2_set_eeprom(struct net_dereturn sky2_vpd_write (sky2->hw, cap, data, eeprom->offset, eeprom->len); } +static int sky2_set_flags (struct net_device *dev,u32 data) +{ +struct sky2_port *sky2 =netdev_priv (dev); + +if (data Ð_FLAG_LRO ) +return -EOPNOTSUPP ; + +if (data Ð_FLAG_NTUPLE ) +return -EOPNOTSUPP ; + +if (data Ð_FLAG_RXHASH ) { +if (sky2->hw->flags &SKY2_HW_RSS_BROKEN ) +return -EINVAL ; + + dev->features |=NETIF_F_RXHASH ; + }else + dev->features &= ~NETIF_F_RXHASH ; + +rx_set_rss (dev); + +return 0 ; +}static const struct ethtool_ops sky2_ethtool_ops = { .get_settings = sky2_get_settings,
@@ -4143,6 +4216,7 @@ static const struct ethtool_ops sky2_eth .phys_id = sky2_phys_id, .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, + .set_flags = sky2_set_flags, };#ifdef CONFIG_SKY2_DEBUG
@@ -4491,6 +4565,11 @@ static __devinit struct net_device *sky2if (highmem) dev->features |=NETIF_F_HIGHDMA ; +#ifdef CONFIG_RPS +if (!(hw->flags &SKY2_HW_RSS_BROKEN )) + dev->features |=NETIF_F_RXHASH ; +#endif +#ifdef SKY2_VLAN_TAG_USED /* The workaround for FE+ status conflicts with VLAN tag detection. */ if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
@@ -4687,7 +4766,7 @@ static int __devinit sky2_probe(struct p goto err_out_iounmap;/* ring for status responses */ - hw->st_size = hw->ports *roundup_pow_of_two (2 *RX_MAX_PENDING +TX_MAX_PENDING ); + hw->st_size = hw->ports *roundup_pow_of_two (3 *RX_MAX_PENDING +TX_MAX_PENDING ); hw->st_le =pci_alloc_consistent (pdev, hw->st_size *sizeof (struct sky2_status_le ), &hw->st_dma);if (!hw->st_le)
drivers/net/sky2.h +14 -0
@@ -694,8 +694,21 @@ enum {TXA_CTRL =0x0210 ,/* 8 bit Tx Arbiter Control Register */ TXA_TEST =0x0211 ,/* 8 bit Tx Arbiter Test Register */ TXA_STAT =0x0212 ,/* 8 bit Tx Arbiter Status Register */ + +RSS_KEY =0x0220 ,/* RSS Key setup */ + RSS_CFG = 0x0248, /* RSS Configuration */ }; +enum { +HASH_TCP_IPV6_EX_CTRL =1 <<5 , +HASH_IPV6_EX_CTRL =1 <<4 , +HASH_TCP_IPV6_CTRL =1 <<3 , +HASH_IPV6_CTRL =1 <<2 , +HASH_TCP_IPV4_CTRL =1 <<1 , +HASH_IPV4_CTRL =1 <<0 , + +HASH_ALL =0x3f , +};enum { B6_EXT_REG = 0x0300,/* External registers (GENESIS only) */
@@ -2261,6 +2274,7 @@ struct sky2_hw {#define SKY2_HW_NEW_LE 0x00000020/* new LSOv2 format */ #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_RSS_BROKEN 0x00000100u8 chip_id;u8 chip_rev;
David Miller
maintainerRe: [PATCH 2/2] sky2: add support for receive hashing
From: Stephen Hemminger <[email protected]>
Date: Thu, 22 Apr 2010 16:42:57 -0700
drivers/net/sky2.c static __devinit struct net_device *sky2 · line 4573
Quoted 10 lines
drivers/net/sky2.c +5
-0@@ -4491,6 +4565,11 @@ static __devinit struct net_device *sky2if (highmem) dev->features |=NETIF_F_HIGHDMA ; +#ifdef CONFIG_RPS +if (!(hw->flags &SKY2_HW_RSS_BROKEN )) + dev->features |=NETIF_F_RXHASH ; +#endif +#ifdef SKY2_VLAN_TAG_USED
Stephen, I asked you to drop this CONFIG_RPS check.
Please do it and resubmit.
Re: [PATCH 2/2] sky2: add support for receive hashing
In reply to Stephen Hemmingerdrivers/net/sky2.c static int sky2_set_eeprom(struct net_de · line 4174
Quoted 9 lines · Stephen Hemminger
drivers/net/sky2.c +9
-0+static int sky2_set_flags (struct net_device *dev,u32 data) +{ +struct sky2_port *sky2 =netdev_priv (dev); + +if (dataÐ_FLAG_LRO ) +return -EOPNOTSUPP ; + +if (dataÐ_FLAG_NTUPLE ) +return -EOPNOTSUPP ;
Minor nit: you don't need separate tests for each bit.
Jeff
PATCH 2/2 sky2: add support for receive hashing (v3)
Subject: 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.
---
drivers/net/sky2.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++-- drivers/net/sky2.h | 23 ++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-)
drivers/net/sky2.c +77 -2
@@ -1193,6 +1193,39 @@ static void rx_set_checksum(struct sky2_ ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } +/* Enable/disable receive hash calculation (RSS) */ +static void rx_set_rss (struct net_device *dev) +{ +struct sky2_port *sky2 =netdev_priv (dev); +struct sky2_hw *hw = sky2->hw; +int i, nkeys =4 ; + +/* Supports IPv6 and other modes */ +if (hw->flags &SKY2_HW_NEW_LE ) { + nkeys =10 ; +sky2_write32 (hw,SK_REG (sky2->port,RSS_CFG ),HASH_ALL ); + } + +/* Program RSS initial values */ +if (dev->features &NETIF_F_RXHASH ) { +u32 key[nkeys]; + +get_random_bytes (key, nkeys *sizeof (u32)); +for (i =0 ; i < nkeys; i++) +sky2_write32 (hw,SK_REG (sky2->port,RSS_KEY + i *4 ), + key[i]); + +/* Need to turn on (undocumented) flag to make hashing work */ +sky2_write32 (hw,SK_REG (sky2->port,RX_GMF_CTRL_T ), +RX_STFW_ENA ); + +sky2_write32 (hw,Q_ADDR (rxqaddr[sky2->port],Q_CSR ), +BMU_ENA_RX_RSS_HASH ); + }else +sky2_write32 (hw,Q_ADDR (rxqaddr[sky2->port],Q_CSR ), +BMU_DIS_RX_RSS_HASH ); +} +/* * The RX Stop command will not work for Yukon-2 if the BMU does not * 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_poif (!(hw->flags &SKY2_HW_NEW_LE ))rx_set_checksum (sky2); +if (!(hw->flags &SKY2_HW_RSS_BROKEN )) +rx_set_rss (sky2->netdev); +/* submit Rx ring */ for (i =0 ; i < sky2->rx_pending; i++) { re = sky2->rx_ring + i;
@@ -2534,6 +2570,14 @@ static void sky2_rx_checksum(struct sky2 } } +static void sky2_rx_hash (struct sky2_port *sky2,u32 status) +{ +struct sk_buff *skb; + + skb = sky2->rx_ring[sky2->rx_next].skb; + skb->rxhash =le32_to_cpu (status); +} +/* Process status response ring */ static int sky2_status_intr (struct sky2_hw *hw,int to_do,u16 idx) {
@@ -2606,6 +2650,10 @@ static int sky2_status_intr(struct sky2_sky2_rx_checksum (sky2, status);break ; +case OP_RSS_HASH : +sky2_rx_hash (sky2, status); +break ; +case OP_TXINDEXLE :/* TX index reports status for both ports */ sky2_tx_done (hw->dev[0 ], status &0xfff );
@@ -2960,6 +3008,8 @@ static int __devinit sky2_init(struct skswitch (hw->chip_id) {case CHIP_ID_YUKON_XL : hw->flags =SKY2_HW_GIGABIT |SKY2_HW_NEWER_PHY ; +if (hw->chip_rev <CHIP_REV_YU_XL_A2 ) + hw->flags |=SKY2_HW_RSS_BROKEN ;break ;case CHIP_ID_YUKON_EC_U :
@@ -2985,10 +3035,11 @@ static int __devinit sky2_init(struct skdev_err (&hw->pdev->dev,"unsupported revision Yukon-EC rev A1\n" );return -EOPNOTSUPP ; } - hw->flags =SKY2_HW_GIGABIT ; + hw->flags =SKY2_HW_GIGABIT |SKY2_HW_RSS_BROKEN ;break ;case CHIP_ID_YUKON_FE : + hw->flags =SKY2_HW_RSS_BROKEN ;break ;case CHIP_ID_YUKON_FE_P :
@@ -4112,6 +4163,25 @@ static int sky2_set_eeprom(struct net_dereturn sky2_vpd_write (sky2->hw, cap, data, eeprom->offset, eeprom->len); } +static int sky2_set_flags (struct net_device *dev,u32 data) +{ +struct sky2_port *sky2 =netdev_priv (dev); + +if (data & ~ETH_FLAG_RXHASH ) +return -EOPNOTSUPP ; + +if (data Ð_FLAG_RXHASH ) { +if (sky2->hw->flags &SKY2_HW_RSS_BROKEN ) +return -EINVAL ; + + dev->features |=NETIF_F_RXHASH ; + }else + dev->features &= ~NETIF_F_RXHASH ; + +rx_set_rss (dev); + +return 0 ; +}static const struct ethtool_ops sky2_ethtool_ops = { .get_settings = sky2_get_settings,
@@ -4143,6 +4213,7 @@ static const struct ethtool_ops sky2_eth .phys_id = sky2_phys_id, .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, + .set_flags = sky2_set_flags, };#ifdef CONFIG_SKY2_DEBUG
@@ -4496,6 +4567,10 @@ static __devinit struct net_device *sky2if (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 ; +#ifdef SKY2_VLAN_TAG_USED /* The workaround for FE+ status conflicts with VLAN tag detection. */ if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
@@ -4692,7 +4767,7 @@ static int __devinit sky2_probe(struct p goto err_out_iounmap;/* ring for status responses */ - hw->st_size = hw->ports *roundup_pow_of_two (2 *RX_MAX_PENDING +TX_MAX_PENDING ); + hw->st_size = hw->ports *roundup_pow_of_two (3 *RX_MAX_PENDING +TX_MAX_PENDING ); hw->st_le =pci_alloc_consistent (pdev, hw->st_size *sizeof (struct sky2_status_le ), &hw->st_dma);if (!hw->st_le)
drivers/net/sky2.h +14 -0
@@ -694,8 +694,21 @@ enum {TXA_CTRL =0x0210 ,/* 8 bit Tx Arbiter Control Register */ TXA_TEST =0x0211 ,/* 8 bit Tx Arbiter Test Register */ TXA_STAT =0x0212 ,/* 8 bit Tx Arbiter Status Register */ + +RSS_KEY =0x0220 ,/* RSS Key setup */ + RSS_CFG = 0x0248, /* RSS Configuration */ }; +enum { +HASH_TCP_IPV6_EX_CTRL =1 <<5 , +HASH_IPV6_EX_CTRL =1 <<4 , +HASH_TCP_IPV6_CTRL =1 <<3 , +HASH_IPV6_CTRL =1 <<2 , +HASH_TCP_IPV4_CTRL =1 <<1 , +HASH_IPV4_CTRL =1 <<0 , + +HASH_ALL =0x3f , +};enum { B6_EXT_REG = 0x0300,/* External registers (GENESIS only) */
@@ -2261,6 +2274,7 @@ struct sky2_hw {#define SKY2_HW_NEW_LE 0x00000020/* new LSOv2 format */ #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_RSS_BROKEN 0x00000100u8 chip_id;u8 chip_rev;
Re: [PATCH 2/2] sky2: add support for receive hashing (v3)
From: Stephen Hemminger <[email protected]>
Date: Sat, 24 Apr 2010 16:22:39 -0700
Quoted 11 lines
Subject: 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. Alsoset_flagsrejects all values except RXHASH, so driver won't have to change next time somebody adds a new one.Signed-off-by Stephen Hemminger <[email protected]>
Applied, thanks Stephen.