[PATCH v2 net-next 3/4] net: aquantia: fix initialization of RSS table

2018-12-07 Thread Igor Russkikh
From: Dmitry Bogdanov 

Now RSS indirection table is initialized before setting up the number of
hw queues, consequently the table may be filled by non existing queues.
This patch moves the initialization when the number of hw queues is
known.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index d617289d95f7..0147c037ca96 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -84,8 +84,6 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
 
cfg->is_lro = AQ_CFG_IS_LRO_DEF;
 
-   aq_nic_rss_init(self, cfg->num_rss_queues);
-
/*descriptors */
cfg->rxds = min(cfg->aq_hw_caps->rxds_max, AQ_CFG_RXDS_DEF);
cfg->txds = min(cfg->aq_hw_caps->txds_max, AQ_CFG_TXDS_DEF);
@@ -106,6 +104,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
 
cfg->num_rss_queues = min(cfg->vecs, AQ_CFG_NUM_RSS_QUEUES_DEF);
 
+   aq_nic_rss_init(self, cfg->num_rss_queues);
+
cfg->irq_type = aq_pci_func_get_irq_type(self);
 
if ((cfg->irq_type == AQ_HW_IRQ_LEGACY) ||
-- 
2.17.1



[PATCH v2 net-next 1/4] net: aquantia: fix RSS table and key sizes

2018-12-07 Thread Igor Russkikh
From: Dmitry Bogdanov 

Set RSS indirection table and RSS hash key sizes to their real size.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | 4 ++--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
index 91eb8910b1c9..90a0e1d0d622 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
@@ -42,8 +42,8 @@
 #define AQ_CFG_IS_LRO_DEF   1U
 
 /* RSS */
-#define AQ_CFG_RSS_INDIRECTION_TABLE_MAX  128U
-#define AQ_CFG_RSS_HASHKEY_SIZE   320U
+#define AQ_CFG_RSS_INDIRECTION_TABLE_MAX  64U
+#define AQ_CFG_RSS_HASHKEY_SIZE   40U
 
 #define AQ_CFG_IS_RSS_DEF   1U
 #define AQ_CFG_NUM_RSS_QUEUES_DEF   AQ_CFG_VECS_DEF
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 279ea58f4a9e..d617289d95f7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -44,7 +44,7 @@ static void aq_nic_rss_init(struct aq_nic_s *self, unsigned 
int num_rss_queues)
struct aq_rss_parameters *rss_params = >aq_rss;
int i = 0;
 
-   static u8 rss_key[40] = {
+   static u8 rss_key[AQ_CFG_RSS_HASHKEY_SIZE] = {
0x1e, 0xad, 0x71, 0x87, 0x65, 0xfc, 0x26, 0x7d,
0x0d, 0x45, 0x67, 0x74, 0xcd, 0x06, 0x1a, 0x18,
0xb6, 0xc1, 0xf0, 0xc7, 0xbb, 0x18, 0xbe, 0xf8,
-- 
2.17.1



[PATCH v2 net-next 4/4] net: aquantia: add support of RSS configuration

2018-12-07 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add support of configuration of RSS hash key and RSS indirection table.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../ethernet/aquantia/atlantic/aq_ethtool.c   | 36 +++
 1 file changed, 36 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index a5fd71692c8b..fcbfecf41c45 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -202,6 +202,41 @@ static int aq_ethtool_get_rss(struct net_device *ndev, u32 
*indir, u8 *key,
return 0;
 }
 
+static int aq_ethtool_set_rss(struct net_device *netdev, const u32 *indir,
+ const u8 *key, const u8 hfunc)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(netdev);
+   struct aq_nic_cfg_s *cfg;
+   unsigned int i = 0U;
+   u32 rss_entries;
+   int err = 0;
+
+   cfg = aq_nic_get_cfg(aq_nic);
+   rss_entries = cfg->aq_rss.indirection_table_size;
+
+   /* We do not allow change in unsupported parameters */
+   if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+   return -EOPNOTSUPP;
+   /* Fill out the redirection table */
+   if (indir)
+   for (i = 0; i < rss_entries; i++)
+   cfg->aq_rss.indirection_table[i] = indir[i];
+
+   /* Fill out the rss hash key */
+   if (key) {
+   memcpy(cfg->aq_rss.hash_secret_key, key,
+  sizeof(cfg->aq_rss.hash_secret_key));
+   err = aq_nic->aq_hw_ops->hw_rss_hash_set(aq_nic->aq_hw,
+   >aq_rss);
+   if (err)
+   return err;
+   }
+
+   err = aq_nic->aq_hw_ops->hw_rss_set(aq_nic->aq_hw, >aq_rss);
+
+   return err;
+}
+
 static int aq_ethtool_get_rxnfc(struct net_device *ndev,
struct ethtool_rxnfc *cmd,
u32 *rule_locs)
@@ -549,6 +584,7 @@ const struct ethtool_ops aq_ethtool_ops = {
.set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
+   .set_rxfh= aq_ethtool_set_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
.set_rxnfc   = aq_ethtool_set_rxnfc,
.get_sset_count  = aq_ethtool_get_sset_count,
-- 
2.17.1



[PATCH v2 net-next 2/4] net: aquantia: increase max number of hw queues

2018-12-07 Thread Igor Russkikh
From: Dmitry Bogdanov 

Increase the upper limit of the hw queues up to 8.
This makes RSS better on multiheaded cpus.

This is a maximum AQC hardware supports in one traffic class.

The actual value is still limited by a number of available cpu cores.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_cfg.h   | 2 +-
 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
index 90a0e1d0d622..3944ce7f0870 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
@@ -12,7 +12,7 @@
 #ifndef AQ_CFG_H
 #define AQ_CFG_H
 
-#define AQ_CFG_VECS_DEF   4U
+#define AQ_CFG_VECS_DEF   8U
 #define AQ_CFG_TCS_DEF1U
 
 #define AQ_CFG_TXDS_DEF4096U
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 6af7d7f0cdca..08596a7a6486 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -21,7 +21,7 @@
 
 #define DEFAULT_B0_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true,\
-   .msix_irqs = 4U,  \
+   .msix_irqs = 8U,  \
.irq_mask = ~0U,  \
.vecs = HW_ATL_B0_RSS_MAX,\
.tcs = HW_ATL_B0_TC_MAX,  \
-- 
2.17.1



[PATCH v2 net-next 0/4] net: aquantia: add RSS configuration

2018-12-07 Thread Igor Russkikh
In this patchset few bugs related to RSS are fixed and RSS table and
hash key configuration is added.

We also do increase max number of HW rings upto 8.

v2: removed extra arg check

Dmitry Bogdanov (4):
  net: aquantia: fix RSS table and key sizes
  net: aquantia: increase max number of hw queues
  net: aquantia: fix initialization of RSS table
  net: aquantia: add support of RSS configuration

 .../net/ethernet/aquantia/atlantic/aq_cfg.h   |  6 ++--
 .../ethernet/aquantia/atlantic/aq_ethtool.c   | 36 +++
 .../net/ethernet/aquantia/atlantic/aq_nic.c   |  6 ++--
 .../aquantia/atlantic/hw_atl/hw_atl_b0.c  |  2 +-
 4 files changed, 43 insertions(+), 7 deletions(-)

-- 
2.17.1



Re: [PATCH net-next 4/4] net: aquantia: add support of RSS configuration

2018-12-07 Thread Igor Russkikh

>> +/* Fill out the redirection table */
>> +if (indir) {
>> +/* Verify user input. */
>> +for (i = 0; i < rss_entries; i++)
>> +if (indir[i] >= cfg->num_rss_queues)
>> +return -EINVAL;
> 
> nit: you shouldn't have to do this, see ethtool_copy_validate_indir().
> 

Thanks, Jakub, indeed. Will resubmit.

Regards,
  Igor


[PATCH net-next 4/4] net: aquantia: add support of RSS configuration

2018-12-06 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add support of configuration of RSS hash key and RSS indirection table.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../ethernet/aquantia/atlantic/aq_ethtool.c   | 42 +++
 1 file changed, 42 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index a5fd71692c8b..2f2e12c2b632 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -202,6 +202,47 @@ static int aq_ethtool_get_rss(struct net_device *ndev, u32 
*indir, u8 *key,
return 0;
 }
 
+static int aq_ethtool_set_rss(struct net_device *netdev, const u32 *indir,
+ const u8 *key, const u8 hfunc)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(netdev);
+   struct aq_nic_cfg_s *cfg;
+   unsigned int i = 0U;
+   u32 rss_entries;
+   int err = 0;
+
+   cfg = aq_nic_get_cfg(aq_nic);
+   rss_entries = cfg->aq_rss.indirection_table_size;
+
+   /* We do not allow change in unsupported parameters */
+   if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+   return -EOPNOTSUPP;
+   /* Fill out the redirection table */
+   if (indir) {
+   /* Verify user input. */
+   for (i = 0; i < rss_entries; i++)
+   if (indir[i] >= cfg->num_rss_queues)
+   return -EINVAL;
+
+   for (i = 0; i < rss_entries; i++)
+   cfg->aq_rss.indirection_table[i] = indir[i];
+   }
+
+   /* Fill out the rss hash key */
+   if (key) {
+   memcpy(cfg->aq_rss.hash_secret_key, key,
+  sizeof(cfg->aq_rss.hash_secret_key));
+   err = aq_nic->aq_hw_ops->hw_rss_hash_set(aq_nic->aq_hw,
+   >aq_rss);
+   if (err)
+   return err;
+   }
+
+   err = aq_nic->aq_hw_ops->hw_rss_set(aq_nic->aq_hw, >aq_rss);
+
+   return err;
+}
+
 static int aq_ethtool_get_rxnfc(struct net_device *ndev,
struct ethtool_rxnfc *cmd,
u32 *rule_locs)
@@ -549,6 +590,7 @@ const struct ethtool_ops aq_ethtool_ops = {
.set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
+   .set_rxfh= aq_ethtool_set_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
.set_rxnfc   = aq_ethtool_set_rxnfc,
.get_sset_count  = aq_ethtool_get_sset_count,
-- 
2.17.1



[PATCH net-next 3/4] net: aquantia: fix initialization of RSS table

2018-12-06 Thread Igor Russkikh
From: Dmitry Bogdanov 

Now RSS indirection table is initialized before setting up the number of
hw queues, consequently the table may be filled by non existing queues.
This patch moves the initialization when the number of hw queues is
known.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index d617289d95f7..0147c037ca96 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -84,8 +84,6 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
 
cfg->is_lro = AQ_CFG_IS_LRO_DEF;
 
-   aq_nic_rss_init(self, cfg->num_rss_queues);
-
/*descriptors */
cfg->rxds = min(cfg->aq_hw_caps->rxds_max, AQ_CFG_RXDS_DEF);
cfg->txds = min(cfg->aq_hw_caps->txds_max, AQ_CFG_TXDS_DEF);
@@ -106,6 +104,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
 
cfg->num_rss_queues = min(cfg->vecs, AQ_CFG_NUM_RSS_QUEUES_DEF);
 
+   aq_nic_rss_init(self, cfg->num_rss_queues);
+
cfg->irq_type = aq_pci_func_get_irq_type(self);
 
if ((cfg->irq_type == AQ_HW_IRQ_LEGACY) ||
-- 
2.17.1



[PATCH net-next 1/4] net: aquantia: fix RSS table and key sizes

2018-12-06 Thread Igor Russkikh
From: Dmitry Bogdanov 

Set RSS indirection table and RSS hash key sizes to their real size.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | 4 ++--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
index 91eb8910b1c9..90a0e1d0d622 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
@@ -42,8 +42,8 @@
 #define AQ_CFG_IS_LRO_DEF   1U
 
 /* RSS */
-#define AQ_CFG_RSS_INDIRECTION_TABLE_MAX  128U
-#define AQ_CFG_RSS_HASHKEY_SIZE   320U
+#define AQ_CFG_RSS_INDIRECTION_TABLE_MAX  64U
+#define AQ_CFG_RSS_HASHKEY_SIZE   40U
 
 #define AQ_CFG_IS_RSS_DEF   1U
 #define AQ_CFG_NUM_RSS_QUEUES_DEF   AQ_CFG_VECS_DEF
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 279ea58f4a9e..d617289d95f7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -44,7 +44,7 @@ static void aq_nic_rss_init(struct aq_nic_s *self, unsigned 
int num_rss_queues)
struct aq_rss_parameters *rss_params = >aq_rss;
int i = 0;
 
-   static u8 rss_key[40] = {
+   static u8 rss_key[AQ_CFG_RSS_HASHKEY_SIZE] = {
0x1e, 0xad, 0x71, 0x87, 0x65, 0xfc, 0x26, 0x7d,
0x0d, 0x45, 0x67, 0x74, 0xcd, 0x06, 0x1a, 0x18,
0xb6, 0xc1, 0xf0, 0xc7, 0xbb, 0x18, 0xbe, 0xf8,
-- 
2.17.1



[PATCH net-next 2/4] net: aquantia: increase max number of hw queues

2018-12-06 Thread Igor Russkikh
From: Dmitry Bogdanov 

Increase the upper limit of the hw queues up to 8.
This makes RSS better on multiheaded cpus.

This is a maximum AQC hardware supports in one traffic class.

The actual value is still limited by a number of available cpu cores.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_cfg.h   | 2 +-
 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
index 90a0e1d0d622..3944ce7f0870 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
@@ -12,7 +12,7 @@
 #ifndef AQ_CFG_H
 #define AQ_CFG_H
 
-#define AQ_CFG_VECS_DEF   4U
+#define AQ_CFG_VECS_DEF   8U
 #define AQ_CFG_TCS_DEF1U
 
 #define AQ_CFG_TXDS_DEF4096U
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 6af7d7f0cdca..08596a7a6486 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -21,7 +21,7 @@
 
 #define DEFAULT_B0_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true,\
-   .msix_irqs = 4U,  \
+   .msix_irqs = 8U,  \
.irq_mask = ~0U,  \
.vecs = HW_ATL_B0_RSS_MAX,\
.tcs = HW_ATL_B0_TC_MAX,  \
-- 
2.17.1



[PATCH net-next 0/4] net: aquantia: add RSS configuration

2018-12-06 Thread Igor Russkikh
In this patchset few bugs related to RSS are fixed and RSS table and
hash key configuration is added.

We also do increase max number of HW rings upto 8.

Dmitry Bogdanov (4):
  net: aquantia: fix RSS table and key sizes
  net: aquantia: increase max number of hw queues
  net: aquantia: fix initialization of RSS table
  net: aquantia: add support of RSS configuration

 .../net/ethernet/aquantia/atlantic/aq_cfg.h   |  6 +--
 .../ethernet/aquantia/atlantic/aq_ethtool.c   | 42 +++
 .../net/ethernet/aquantia/atlantic/aq_nic.c   |  6 +--
 .../aquantia/atlantic/hw_atl/hw_atl_b0.c  |  2 +-
 4 files changed, 49 insertions(+), 7 deletions(-)

-- 
2.17.1



[PATCH net] net: aquantia: fix rx checksum offload bits

2018-11-27 Thread Igor Russkikh
From: Dmitry Bogdanov 

The last set of csum offload fixes had a leak:

Checksum enabled status bits from rx descriptor were incorrectly
interpreted. Consequently all the other valid logic worked on zero bits.
That caused rx checksum offloads never to trigger.

Tested by dumping rx descriptors and validating resulting csum_level.

Reported-by: Igor Russkikh 
Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
Fixes: ad703c2b9127f ("net: aquantia: invalid checksumm offload implementation")
---
 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 6af7d7f0cdca..672b80c68d3f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -667,7 +667,7 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s 
*self,
 
rx_stat = (0x003CU & rxd_wb->status) >> 2;
 
-   is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19);
+   is_rx_check_sum_enabled = (rxd_wb->type >> 19) & 0x3U;
 
pkt_type = 0xFFU & (rxd_wb->type >> 4);
 
-- 
2.17.1



[PATCH net-next v2 1/6] net: aquantia: add rx-flow filter definitions

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add missing register definitions and the functions accessing them
related to rx-flow filters.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 109 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  48 
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 135 ++---
 3 files changed, 275 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 5502ec5f0f69..939f77e2e117 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -898,6 +898,24 @@ void hw_atl_rpf_vlan_id_flr_set(struct aq_hw_s *aq_hw, u32 
vlan_id_flr,
vlan_id_flr);
 }
 
+void hw_atl_rpf_vlan_rxq_en_flr_set(struct aq_hw_s *aq_hw, u32 vlan_rxq_en,
+   u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_VL_RXQ_EN_F_ADR(filter),
+   HW_ATL_RPF_VL_RXQ_EN_F_MSK,
+   HW_ATL_RPF_VL_RXQ_EN_F_SHIFT,
+   vlan_rxq_en);
+}
+
+void hw_atl_rpf_vlan_rxq_flr_set(struct aq_hw_s *aq_hw, u32 vlan_rxq,
+u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_VL_RXQ_F_ADR(filter),
+   HW_ATL_RPF_VL_RXQ_F_MSK,
+   HW_ATL_RPF_VL_RXQ_F_SHIFT,
+   vlan_rxq);
+};
+
 void hw_atl_rpf_etht_flr_en_set(struct aq_hw_s *aq_hw, u32 etht_flr_en,
u32 filter)
 {
@@ -965,6 +983,20 @@ void hw_atl_rpf_etht_flr_set(struct aq_hw_s *aq_hw, u32 
etht_flr, u32 filter)
HW_ATL_RPF_ET_VALF_SHIFT, etht_flr);
 }
 
+void hw_atl_rpf_l4_spd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_L4_SPD_ADR(filter),
+   HW_ATL_RPF_L4_SPD_MSK,
+   HW_ATL_RPF_L4_SPD_SHIFT, val);
+}
+
+void hw_atl_rpf_l4_dpd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_L4_DPD_ADR(filter),
+   HW_ATL_RPF_L4_DPD_MSK,
+   HW_ATL_RPF_L4_DPD_SHIFT, val);
+}
+
 /* RPO: rx packet offload */
 void hw_atl_rpo_ipv4header_crc_offload_en_set(struct aq_hw_s *aq_hw,
  u32 ipv4header_crc_offload_en)
@@ -1476,3 +1508,80 @@ void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, 
u32 up_force_intr)
HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT,
up_force_intr);
 }
+
+void hw_atl_rpfl3l4_ipv4_dest_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_DSTA_ADR(location), 0U);
+}
+
+void hw_atl_rpfl3l4_ipv4_src_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_SRCA_ADR(location), 0U);
+}
+
+void hw_atl_rpfl3l4_cmd_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_REG_CTRL_ADR(location), 0U);
+}
+
+void hw_atl_rpfl3l4_ipv6_dest_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   int i;
+
+   for (i = 0; i < 4; ++i)
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_DSTA_ADR(location + i),
+   0U);
+}
+
+void hw_atl_rpfl3l4_ipv6_src_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   int i;
+
+   for (i = 0; i < 4; ++i)
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_SRCA_ADR(location + i),
+   0U);
+}
+
+void hw_atl_rpfl3l4_ipv4_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
+  u32 ipv4_dest)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_DSTA_ADR(location),
+   ipv4_dest);
+}
+
+void hw_atl_rpfl3l4_ipv4_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
+ u32 ipv4_src)
+{
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_SRCA_ADR(location),
+   ipv4_src);
+}
+
+void hw_atl_rpfl3l4_cmd_set(struct aq_hw_s *aq_hw, u8 location, u32 cmd)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_REG_CTRL_ADR(location), cmd);
+}
+
+void hw_atl_rpfl3l4_ipv6_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
+ u32 *ipv6_src)
+{
+   int i;
+
+   for (i = 0; i < 4; ++i)
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_SRCA_ADR(location + i),
+   ipv6_src[i]);
+}
+
+void hw_atl_rpfl3l4_ipv6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
+  u32 *ipv6_dest)
+{
+   int i;
+
+   for (i = 0; i

[PATCH net-next v2 2/6] net: aquantia: add infrastructure for ntuple rules

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add infrastructure to support ntuple filter configuration.
Add rule, remove rule, reapply on interface up.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/Makefile|   1 +
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  31 ++
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 413 +
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  31 ++
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   |  15 +
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   6 +
 .../net/ethernet/aquantia/atlantic/aq_pci_func.c   |   2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |   3 +-
 8 files changed, 501 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.c
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.h

diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile 
b/drivers/net/ethernet/aquantia/atlantic/Makefile
index 686f6d8c9e79..4556630ee286 100644
--- a/drivers/net/ethernet/aquantia/atlantic/Makefile
+++ b/drivers/net/ethernet/aquantia/atlantic/Makefile
@@ -36,6 +36,7 @@ atlantic-objs := aq_main.o \
aq_ring.o \
aq_hw_utils.o \
aq_ethtool.o \
+   aq_filters.o \
hw_atl/hw_atl_a0.o \
hw_atl/hw_atl_b0.o \
hw_atl/hw_atl_utils.o \
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 99ef1daaa4d8..a5fd71692c8b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -12,6 +12,7 @@
 #include "aq_ethtool.h"
 #include "aq_nic.h"
 #include "aq_vec.h"
+#include "aq_filters.h"
 
 static void aq_ethtool_get_regs(struct net_device *ndev,
struct ethtool_regs *regs, void *p)
@@ -213,7 +214,36 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev,
case ETHTOOL_GRXRINGS:
cmd->data = cfg->vecs;
break;
+   case ETHTOOL_GRXCLSRLCNT:
+   cmd->rule_cnt = aq_get_rxnfc_count_all_rules(aq_nic);
+   break;
+   case ETHTOOL_GRXCLSRULE:
+   err = aq_get_rxnfc_rule(aq_nic, cmd);
+   break;
+   case ETHTOOL_GRXCLSRLALL:
+   err = aq_get_rxnfc_all_rules(aq_nic, cmd, rule_locs);
+   break;
+   default:
+   err = -EOPNOTSUPP;
+   break;
+   }
 
+   return err;
+}
+
+static int aq_ethtool_set_rxnfc(struct net_device *ndev,
+   struct ethtool_rxnfc *cmd)
+{
+   int err = 0;
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   switch (cmd->cmd) {
+   case ETHTOOL_SRXCLSRLINS:
+   err = aq_add_rxnfc_rule(aq_nic, cmd);
+   break;
+   case ETHTOOL_SRXCLSRLDEL:
+   err = aq_del_rxnfc_rule(aq_nic, cmd);
+   break;
default:
err = -EOPNOTSUPP;
break;
@@ -520,6 +550,7 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
+   .set_rxnfc   = aq_ethtool_set_rxnfc,
.get_sset_count  = aq_ethtool_get_sset_count,
.get_ethtool_stats   = aq_ethtool_stats,
.get_link_ksettings  = aq_ethtool_get_link_ksettings,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
new file mode 100644
index ..8cb4eaefd6e1
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2014-2017 aQuantia Corporation. */
+
+/* File aq_filters.c: RX filters related functions. */
+
+#include "aq_filters.h"
+
+static bool __must_check
+aq_rule_is_approve(struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->flow_type & FLOW_MAC_EXT)
+   return false;
+
+   switch (fsp->flow_type & ~FLOW_EXT) {
+   case ETHER_FLOW:
+   case TCP_V4_FLOW:
+   case UDP_V4_FLOW:
+   case SCTP_V4_FLOW:
+   case TCP_V6_FLOW:
+   case UDP_V6_FLOW:
+   case SCTP_V6_FLOW:
+   case IPV4_FLOW:
+   case IPV6_FLOW:
+   return true;
+   case IP_USER_FLOW:
+   switch (fsp->h_u.usr_ip4_spec.proto) {
+   case IPPROTO_TCP:
+   case IPPROTO_UDP:
+   case IPPROTO_SCTP:
+   case IPPROTO_IP:
+   return true;
+   default:
+   return false;
+   }
+   case IPV6_USER_FLOW:
+   switch (fsp->h_u.usr_ip6_spec.l4_proto) {
+   case IPPROTO_TCP:
+   ca

[PATCH net-next v2 4/6] net: aquantia: add vlan id to rx flow filters

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

The VLAN filter (VLAN id) is compared against 16 filters.
VLAN id must be accompanied by mask 0xF000. That is to distinguish
VLAN filter from L2 Ethertype filter with UserPriority since both
User Priority and VLAN ID are passed in the same 'vlan' parameter.
Flow type may be any as  it is not matched for VLAN filter.
Due to fixed order of the rules in the NIC, the location 0-15 are
reserved for vlan filters.

Example:
To add a rule that directs packets from VLAN 2001 to queue 5:
ethtool -N  flow-type ip4 vlan 2001 m 0xF000 action 5 loc 0

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |  2 +-
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 92 +-
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  2 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 +++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  5 ++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 37 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  7 ++
 7 files changed, 151 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index becb578211ed..6b6d1724676e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -14,7 +14,7 @@
 
 #include 
 #include 
-
+#include 
 #include "ver.h"
 #include "aq_cfg.h"
 #include "aq_utils.h"
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index 34e2a28d344a..c5240bc487b4 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -120,6 +120,29 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
 }
 
 static int __must_check
+aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
+  struct aq_hw_rx_fltrs_s *rx_fltrs,
+  struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->location < AQ_RX_FIRST_LOC_FVLANID ||
+   fsp->location > AQ_RX_LAST_LOC_FVLANID) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: location must be in range [%d, %d]",
+  AQ_RX_FIRST_LOC_FVLANID,
+  AQ_RX_LAST_LOC_FVLANID);
+   return -EINVAL;
+   }
+
+   if (fsp->ring_cookie > aq_nic->aq_nic_cfg.num_rss_queues) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: queue number must be in range [0, %d]",
+  aq_nic->aq_nic_cfg.num_rss_queues - 1);
+   return -EINVAL;
+   }
+   return 0;
+}
+
+static int __must_check
 aq_check_filter(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
 {
@@ -127,7 +150,14 @@ aq_check_filter(struct aq_nic_s *aq_nic,
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
 
if (fsp->flow_type & FLOW_EXT) {
-   err = -EOPNOTSUPP;
+   if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
+   err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
+   } else {
+   netdev_err(aq_nic->ndev,
+  "ethtool: invalid vlan mask 0x%x specified",
+  be16_to_cpu(fsp->m_ext.vlan_tci));
+   err = -EINVAL;
+   }
} else {
switch (fsp->flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
@@ -229,6 +259,42 @@ aq_check_rule(struct aq_nic_s *aq_nic,
return err;
 }
 
+static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
+struct aq_rx_filter *aq_rx_fltr,
+struct aq_rx_filter_vlan *aq_vlans, bool add)
+{
+   const struct ethtool_rx_flow_spec *fsp = _rx_fltr->aq_fsp;
+   int location = fsp->location - AQ_RX_FIRST_LOC_FVLANID;
+
+   memset(_vlans[location], 0, sizeof(aq_vlans[location]));
+
+   if (!add)
+   return 0;
+
+   aq_vlans[location].location = location;
+   aq_vlans[location].vlan_id = be16_to_cpu(fsp->h_ext.vlan_tci)
+& VLAN_VID_MASK;
+   aq_vlans[location].queue = fsp->ring_cookie & 0x1FU;
+   aq_vlans[location].enable = 1U;
+   return 0;
+}
+
+static int aq_add_del_fvlan(struct aq_nic_s *aq_nic,
+   struct aq_rx_filter *aq_rx_fltr, bool add)
+{
+   const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
+
+   if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
+   return -EOPNOTSUPP;
+
+   aq_set_data_fvlan(aq_nic,
+ aq_rx_fltr,
+ aq_nic->aq_hw_rx_f

[PATCH net-next v2 5/6] net: aquantia: add ethertype and PCP to rx flow filters

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

L2 EtherType filters allows to filter packet by EtherType field or
both EtherType and User Priority (PCP) field of 802.1Q.
UserPriority (vlan) parameter must be accompanied by mask 0x1FFF. That
is to distinguish VLAN filter from L2 Ethertype filter with
UserPriority since both User Priority and VLAN ID are passed in the
same 'vlan' parameter.

Example:
To add a filter that directs IP4 packess of priority 3 to queue 3:
ethtool -N  flow-type ether proto 0x800 vlan 0x600 m 0x1FFF \
action 3 loc 16

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 83 --
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  1 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  8 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 37 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  8 +++
 5 files changed, 133 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index c5240bc487b4..b987c6717af6 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -120,6 +120,30 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
 }
 
 static int __must_check
+aq_check_approve_fl2(struct aq_nic_s *aq_nic,
+struct aq_hw_rx_fltrs_s *rx_fltrs,
+struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->location < AQ_RX_FIRST_LOC_FETHERT ||
+   fsp->location > AQ_RX_LAST_LOC_FETHERT) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: location must be in range [%d, %d]",
+  AQ_RX_FIRST_LOC_FETHERT,
+  AQ_RX_LAST_LOC_FETHERT);
+   return -EINVAL;
+   }
+
+   if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK &&
+   fsp->m_u.ether_spec.h_proto == 0U) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: proto (ether_type) parameter must be 
specfied");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
+static int __must_check
 aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
   struct aq_hw_rx_fltrs_s *rx_fltrs,
   struct ethtool_rx_flow_spec *fsp)
@@ -152,6 +176,8 @@ aq_check_filter(struct aq_nic_s *aq_nic,
if (fsp->flow_type & FLOW_EXT) {
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
+   } else if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK) {
+   err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
} else {
netdev_err(aq_nic->ndev,
   "ethtool: invalid vlan mask 0x%x specified",
@@ -161,7 +187,7 @@ aq_check_filter(struct aq_nic_s *aq_nic,
} else {
switch (fsp->flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
-   err = -EOPNOTSUPP;
+   err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
break;
case TCP_V4_FLOW:
case UDP_V4_FLOW:
@@ -210,6 +236,10 @@ aq_rule_is_not_support(struct aq_nic_s *aq_nic,
netdev_err(aq_nic->ndev,
   "ethtool: The specified tos tclass are not 
supported\n");
rule_is_not_support = true;
+   } else if (fsp->flow_type & FLOW_MAC_EXT) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: MAC_EXT is not supported");
+   rule_is_not_support = true;
}
 
return rule_is_not_support;
@@ -259,6 +289,48 @@ aq_check_rule(struct aq_nic_s *aq_nic,
return err;
 }
 
+static void aq_set_data_fl2(struct aq_nic_s *aq_nic,
+   struct aq_rx_filter *aq_rx_fltr,
+   struct aq_rx_filter_l2 *data, bool add)
+{
+   const struct ethtool_rx_flow_spec *fsp = _rx_fltr->aq_fsp;
+
+   memset(data, 0, sizeof(*data));
+
+   data->location = fsp->location - AQ_RX_FIRST_LOC_FETHERT;
+
+   if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
+   data->queue = fsp->ring_cookie;
+   else
+   data->queue = -1;
+
+   data->ethertype = be16_to_cpu(fsp->h_u.ether_spec.h_proto);
+   data->user_priority_en = be16_to_cpu(fsp->m_ext.vlan_tci)
+== VLAN_PRIO_MASK;
+   data->user_priority = (be16_to_cpu(fsp->h_ext.vlan_tci)
+  & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+}
+
+static int aq_add_del_fether(struct aq_nic_s *aq_nic,
+ 

[PATCH net-next v2 6/6] net: aquantia: add support of rx-vlan-filter offload

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Since it uses the same NIC table as rx flow vlan filter therefore
rx-flow vlan filter accepts only vlans that present on the interface
in case of rx-vlan-filter is on.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 138 +
 .../net/ethernet/aquantia/atlantic/aq_filters.h|   2 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |   1 +
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   |  40 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|   2 -
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   3 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  29 ++---
 7 files changed, 197 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index b987c6717af6..f6145e7473b1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -157,6 +157,14 @@ aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
return -EINVAL;
}
 
+   if ((aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+   (!test_bit(be16_to_cpu(fsp->h_ext.vlan_tci),
+  aq_nic->active_vlans))) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: unknown vlan-id specified");
+   return -EINVAL;
+   }
+
if (fsp->ring_cookie > aq_nic->aq_nic_cfg.num_rss_queues) {
netdev_err(aq_nic->ndev,
   "ethtool: queue number must be in range [0, %d]",
@@ -331,26 +339,108 @@ static int aq_add_del_fether(struct aq_nic_s *aq_nic,
return aq_hw_ops->hw_filter_l2_clear(aq_hw, );
 }
 
+static bool aq_fvlan_is_busy(struct aq_rx_filter_vlan *aq_vlans, int vlan)
+{
+   int i;
+
+   for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
+   if (aq_vlans[i].enable &&
+   aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED &&
+   aq_vlans[i].vlan_id == vlan) {
+   return true;
+   }
+   }
+
+   return false;
+}
+
+/* Function rebuilds array of vlan filters so that filters with assigned
+ * queue have a precedence over just vlans on the interface.
+ */
+static void aq_fvlan_rebuild(struct aq_nic_s *aq_nic,
+unsigned long *active_vlans,
+struct aq_rx_filter_vlan *aq_vlans)
+{
+   bool vlan_busy = false;
+   int vlan = -1;
+   int i;
+
+   for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
+   if (aq_vlans[i].enable &&
+   aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED)
+   continue;
+   do {
+   vlan = find_next_bit(active_vlans,
+VLAN_N_VID,
+vlan + 1);
+   if (vlan == VLAN_N_VID) {
+   aq_vlans[i].enable = 0U;
+   aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
+   aq_vlans[i].vlan_id = 0;
+   continue;
+   }
+
+   vlan_busy = aq_fvlan_is_busy(aq_vlans, vlan);
+   if (!vlan_busy) {
+   aq_vlans[i].enable = 1U;
+   aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
+   aq_vlans[i].vlan_id = vlan;
+   }
+   } while (vlan_busy && vlan != VLAN_N_VID);
+   }
+}
+
 static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
 struct aq_rx_filter *aq_rx_fltr,
 struct aq_rx_filter_vlan *aq_vlans, bool add)
 {
const struct ethtool_rx_flow_spec *fsp = _rx_fltr->aq_fsp;
int location = fsp->location - AQ_RX_FIRST_LOC_FVLANID;
+   int i;
 
memset(_vlans[location], 0, sizeof(aq_vlans[location]));
 
if (!add)
return 0;
 
+   /* remove vlan if it was in table without queue assignment */
+   for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
+   if (aq_vlans[i].vlan_id ==
+  (be16_to_cpu(fsp->h_ext.vlan_tci) & VLAN_VID_MASK)) {
+   aq_vlans[i].enable = false;
+   }
+   }
+
aq_vlans[location].location = location;
aq_vlans[location].vlan_id = be16_to_cpu(fsp->h_ext.vlan_tci)
 & VLAN_VID_MASK;
aq_vlans[location].queue = fsp->ring_cookie & 0x1FU;
aq_vlans[location].enable = 1U;
+
return 0;
 }
 
+int aq_del_fvlan_by_vlan(struct aq_nic_s *aq_nic, u16 vlan_id)
+{
+   s

[PATCH net-next v2 3/6] net: aquantia: add support of L3/L4 ntuple filters

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add support of L3/L4 5-tuple {protocol, src-ip, dst-ip, src-port, dst-port}
filters. Mask is not supported. Src-port and dst-port are only compared for
TCP/UDP/SCTP packets. Both IPv4 and IPv6 are supported.
The supported actions are the drop and the queue assignment.
Due to fixed order of the rules in the NIC, the location 32-39 are
reserved for L3/L4 5-tuple filters. The locations 32 and 36 are
reserved for IPv6 filters.

Examples:
sudo ethtool -N eth0 flow-type ip6 src-ip 2001:db8:0:f101::2 \
dst-ip 2001:db8:0:f101::5 action -1 loc 36

sudo ethtool -N eth0 flow-type udp4 src-ip 10.0.0.4 \
dst-ip 10.0.0.7 src-port 2000 dst-port 2001 action 2 loc 32

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 168 -
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  11 ++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   7 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  58 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  43 ++
 5 files changed, 284 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index 8cb4eaefd6e1..34e2a28d344a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -85,11 +85,46 @@ aq_rule_already_exists(struct aq_nic_s *aq_nic,
return false;
 }
 
+static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
+ struct aq_hw_rx_fltrs_s *rx_fltrs,
+ struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->location < AQ_RX_FIRST_LOC_FL3L4 ||
+   fsp->location > AQ_RX_LAST_LOC_FL3L4) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: location must be in range [%d, %d]",
+  AQ_RX_FIRST_LOC_FL3L4,
+  AQ_RX_LAST_LOC_FL3L4);
+   return -EINVAL;
+   }
+   if (rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv4) {
+   rx_fltrs->fl3l4.is_ipv6 = false;
+   netdev_err(aq_nic->ndev,
+  "ethtool: mixing ipv4 and ipv6 is not allowed");
+   return -EINVAL;
+   } else if (!rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv6) {
+   rx_fltrs->fl3l4.is_ipv6 = true;
+   netdev_err(aq_nic->ndev,
+  "ethtool: mixing ipv4 and ipv6 is not allowed");
+   return -EINVAL;
+   } else if (rx_fltrs->fl3l4.is_ipv6&&
+  fsp->location != AQ_RX_FIRST_LOC_FL3L4 + 4 &&
+  fsp->location != AQ_RX_FIRST_LOC_FL3L4) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: The specified location for ipv6 must be %d 
or %d",
+  AQ_RX_FIRST_LOC_FL3L4, AQ_RX_FIRST_LOC_FL3L4 + 4);
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 static int __must_check
 aq_check_filter(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
 {
int err = 0;
+   struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
 
if (fsp->flow_type & FLOW_EXT) {
err = -EOPNOTSUPP;
@@ -103,14 +138,16 @@ aq_check_filter(struct aq_nic_s *aq_nic,
case SCTP_V4_FLOW:
case IPV4_FLOW:
case IP_USER_FLOW:
-   err = -EOPNOTSUPP;
+   rx_fltrs->fl3l4.is_ipv6 = false;
+   err = aq_check_approve_fl3l4(aq_nic, rx_fltrs, fsp);
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV6_FLOW:
case IPV6_USER_FLOW:
-   err = -EOPNOTSUPP;
+   rx_fltrs->fl3l4.is_ipv6 = true;
+   err = aq_check_approve_fl3l4(aq_nic, rx_fltrs, fsp);
break;
default:
netdev_err(aq_nic->ndev,
@@ -156,6 +193,11 @@ aq_rule_is_not_correct(struct aq_nic_s *aq_nic,
 
if (!aq_nic) {
rule_is_not_correct = true;
+   } else if (fsp->location > AQ_RX_MAX_RXNFC_LOC) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: The specified number %u rule is invalid\n",
+  fsp->location);
+   rule_is_not_correct = true;
} else if (aq_check_filter(aq_nic, fsp)) {
rule_is_not_correct = true;
} else if (fsp->ring_cookie != RX_CLS_FLOW_DISC) {
@@ -187,6 +229,125 @@ aq_check_rule(struct aq_nic_s *aq_nic,
retur

[PATCH net-next v2 0/6] net: aquantia: add rx-flow filter support

2018-11-12 Thread Igor Russkikh
In this patchset the rx-flow filters functionality and vlan filter offloads
are implemented.

The rules in NIC hardware have fixed order and priorities.
To support this, the locations of filters from ethtool perspective are also 
fixed:

* Locations 0 - 15 for VLAN ID filters
* Locations 16 - 31 for L2 EtherType and PCP filters
* Locations 32 - 39 for L3/L4 5-tuple filters (locations 32, 36 for IPv6)

Dmitry Bogdanov (6):
  net: aquantia: add rx-flow filter definitions
  net: aquantia: add infrastructure for ntuple rules
  net: aquantia: add support of L3/L4 ntuple filters
  net: aquantia: add vlan id to rx flow filters
  net: aquantia: add ethertype and PCP to rx flow filters
  net: aquantia: add support of rx-vlan-filter offload

 drivers/net/ethernet/aquantia/atlantic/Makefile|   1 +
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |   2 +-
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  31 +
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 876 +
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  36 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  29 +
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   |  55 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|   2 -
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  21 +-
 .../net/ethernet/aquantia/atlantic/aq_pci_func.c   |   2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 162 +++-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 109 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  48 ++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 135 +++-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  58 ++
 15 files changed, 1531 insertions(+), 36 deletions(-)
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.c
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.h

-- 
2.7.4



Re: [PATCH net-next 0/6] net: aquantia: add rx-flow filter support

2018-11-12 Thread Igor Russkikh

On 12.11.2018 18:02, Igor Russkikh wrote:
> In this patchset the rx-flow filters functionality and vlan filter offloads
> are implemented.
> 
> The rules in NIC hardware have fixed order and priorities.
> To support this, the locations of filters from ethtool perspective are also 
> fixed:
> 

Hi David, please discard the patch, it seems it gets a conflict with just 
integrated 'net' tree.

Will resend it shortly.

Sorry for this.


[PATCH net-next 5/6] net: aquantia: add ethertype and PCP to rx flow filters

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

L2 EtherType filters allows to filter packet by EtherType field or
both EtherType and User Priority (PCP) field of 802.1Q.
UserPriority (vlan) parameter must be accompanied by mask 0x1FFF. That
is to distinguish VLAN filter from L2 Ethertype filter with
UserPriority since both User Priority and VLAN ID are passed in the
same 'vlan' parameter.

Example:
To add a filter that directs IP4 packess of priority 3 to queue 3:
ethtool -N  flow-type ether proto 0x800 vlan 0x600 m 0x1FFF \
action 3 loc 16

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 83 --
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  1 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  8 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 37 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  8 +++
 5 files changed, 133 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index c5240bc487b4..b987c6717af6 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -120,6 +120,30 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
 }
 
 static int __must_check
+aq_check_approve_fl2(struct aq_nic_s *aq_nic,
+struct aq_hw_rx_fltrs_s *rx_fltrs,
+struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->location < AQ_RX_FIRST_LOC_FETHERT ||
+   fsp->location > AQ_RX_LAST_LOC_FETHERT) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: location must be in range [%d, %d]",
+  AQ_RX_FIRST_LOC_FETHERT,
+  AQ_RX_LAST_LOC_FETHERT);
+   return -EINVAL;
+   }
+
+   if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK &&
+   fsp->m_u.ether_spec.h_proto == 0U) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: proto (ether_type) parameter must be 
specfied");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
+static int __must_check
 aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
   struct aq_hw_rx_fltrs_s *rx_fltrs,
   struct ethtool_rx_flow_spec *fsp)
@@ -152,6 +176,8 @@ aq_check_filter(struct aq_nic_s *aq_nic,
if (fsp->flow_type & FLOW_EXT) {
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
+   } else if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK) {
+   err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
} else {
netdev_err(aq_nic->ndev,
   "ethtool: invalid vlan mask 0x%x specified",
@@ -161,7 +187,7 @@ aq_check_filter(struct aq_nic_s *aq_nic,
} else {
switch (fsp->flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
-   err = -EOPNOTSUPP;
+   err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
break;
case TCP_V4_FLOW:
case UDP_V4_FLOW:
@@ -210,6 +236,10 @@ aq_rule_is_not_support(struct aq_nic_s *aq_nic,
netdev_err(aq_nic->ndev,
   "ethtool: The specified tos tclass are not 
supported\n");
rule_is_not_support = true;
+   } else if (fsp->flow_type & FLOW_MAC_EXT) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: MAC_EXT is not supported");
+   rule_is_not_support = true;
}
 
return rule_is_not_support;
@@ -259,6 +289,48 @@ aq_check_rule(struct aq_nic_s *aq_nic,
return err;
 }
 
+static void aq_set_data_fl2(struct aq_nic_s *aq_nic,
+   struct aq_rx_filter *aq_rx_fltr,
+   struct aq_rx_filter_l2 *data, bool add)
+{
+   const struct ethtool_rx_flow_spec *fsp = _rx_fltr->aq_fsp;
+
+   memset(data, 0, sizeof(*data));
+
+   data->location = fsp->location - AQ_RX_FIRST_LOC_FETHERT;
+
+   if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
+   data->queue = fsp->ring_cookie;
+   else
+   data->queue = -1;
+
+   data->ethertype = be16_to_cpu(fsp->h_u.ether_spec.h_proto);
+   data->user_priority_en = be16_to_cpu(fsp->m_ext.vlan_tci)
+== VLAN_PRIO_MASK;
+   data->user_priority = (be16_to_cpu(fsp->h_ext.vlan_tci)
+  & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+}
+
+static int aq_add_del_fether(struct aq_nic_s *aq_nic,
+ 

[PATCH net-next 1/6] net: aquantia: add rx-flow filter definitions

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add missing register definitions and the functions accessing them
related to rx-flow filters.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 109 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  48 
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 135 ++---
 3 files changed, 275 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index be0a3a90dfad..06f34092c06d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -890,6 +890,24 @@ void hw_atl_rpf_vlan_id_flr_set(struct aq_hw_s *aq_hw, u32 
vlan_id_flr,
vlan_id_flr);
 }
 
+void hw_atl_rpf_vlan_rxq_en_flr_set(struct aq_hw_s *aq_hw, u32 vlan_rxq_en,
+   u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_VL_RXQ_EN_F_ADR(filter),
+   HW_ATL_RPF_VL_RXQ_EN_F_MSK,
+   HW_ATL_RPF_VL_RXQ_EN_F_SHIFT,
+   vlan_rxq_en);
+}
+
+void hw_atl_rpf_vlan_rxq_flr_set(struct aq_hw_s *aq_hw, u32 vlan_rxq,
+u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_VL_RXQ_F_ADR(filter),
+   HW_ATL_RPF_VL_RXQ_F_MSK,
+   HW_ATL_RPF_VL_RXQ_F_SHIFT,
+   vlan_rxq);
+};
+
 void hw_atl_rpf_etht_flr_en_set(struct aq_hw_s *aq_hw, u32 etht_flr_en,
u32 filter)
 {
@@ -957,6 +975,20 @@ void hw_atl_rpf_etht_flr_set(struct aq_hw_s *aq_hw, u32 
etht_flr, u32 filter)
HW_ATL_RPF_ET_VALF_SHIFT, etht_flr);
 }
 
+void hw_atl_rpf_l4_spd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_L4_SPD_ADR(filter),
+   HW_ATL_RPF_L4_SPD_MSK,
+   HW_ATL_RPF_L4_SPD_SHIFT, val);
+}
+
+void hw_atl_rpf_l4_dpd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RPF_L4_DPD_ADR(filter),
+   HW_ATL_RPF_L4_DPD_MSK,
+   HW_ATL_RPF_L4_DPD_SHIFT, val);
+}
+
 /* RPO: rx packet offload */
 void hw_atl_rpo_ipv4header_crc_offload_en_set(struct aq_hw_s *aq_hw,
  u32 ipv4header_crc_offload_en)
@@ -1468,3 +1500,80 @@ void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, 
u32 up_force_intr)
HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT,
up_force_intr);
 }
+
+void hw_atl_rpfl3l4_ipv4_dest_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_DSTA_ADR(location), 0U);
+}
+
+void hw_atl_rpfl3l4_ipv4_src_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_SRCA_ADR(location), 0U);
+}
+
+void hw_atl_rpfl3l4_cmd_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_REG_CTRL_ADR(location), 0U);
+}
+
+void hw_atl_rpfl3l4_ipv6_dest_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   int i;
+
+   for (i = 0; i < 4; ++i)
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_DSTA_ADR(location + i),
+   0U);
+}
+
+void hw_atl_rpfl3l4_ipv6_src_addr_clear(struct aq_hw_s *aq_hw, u8 location)
+{
+   int i;
+
+   for (i = 0; i < 4; ++i)
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_SRCA_ADR(location + i),
+   0U);
+}
+
+void hw_atl_rpfl3l4_ipv4_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
+  u32 ipv4_dest)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_DSTA_ADR(location),
+   ipv4_dest);
+}
+
+void hw_atl_rpfl3l4_ipv4_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
+ u32 ipv4_src)
+{
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_SRCA_ADR(location),
+   ipv4_src);
+}
+
+void hw_atl_rpfl3l4_cmd_set(struct aq_hw_s *aq_hw, u8 location, u32 cmd)
+{
+   aq_hw_write_reg(aq_hw, HW_ATL_RPF_L3_REG_CTRL_ADR(location), cmd);
+}
+
+void hw_atl_rpfl3l4_ipv6_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
+ u32 *ipv6_src)
+{
+   int i;
+
+   for (i = 0; i < 4; ++i)
+   aq_hw_write_reg(aq_hw,
+   HW_ATL_RPF_L3_SRCA_ADR(location + i),
+   ipv6_src[i]);
+}
+
+void hw_atl_rpfl3l4_ipv6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
+  u32 *ipv6_dest)
+{
+   int i;
+
+   for (i = 0; i

[PATCH net-next 6/6] net: aquantia: add support of rx-vlan-filter offload

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Since it uses the same NIC table as rx flow vlan filter therefore
rx-flow vlan filter accepts only vlans that present on the interface
in case of rx-vlan-filter is on.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 138 +
 .../net/ethernet/aquantia/atlantic/aq_filters.h|   2 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |   1 +
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   |  40 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|   2 -
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   3 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  29 ++---
 7 files changed, 197 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index b987c6717af6..f6145e7473b1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -157,6 +157,14 @@ aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
return -EINVAL;
}
 
+   if ((aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+   (!test_bit(be16_to_cpu(fsp->h_ext.vlan_tci),
+  aq_nic->active_vlans))) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: unknown vlan-id specified");
+   return -EINVAL;
+   }
+
if (fsp->ring_cookie > aq_nic->aq_nic_cfg.num_rss_queues) {
netdev_err(aq_nic->ndev,
   "ethtool: queue number must be in range [0, %d]",
@@ -331,26 +339,108 @@ static int aq_add_del_fether(struct aq_nic_s *aq_nic,
return aq_hw_ops->hw_filter_l2_clear(aq_hw, );
 }
 
+static bool aq_fvlan_is_busy(struct aq_rx_filter_vlan *aq_vlans, int vlan)
+{
+   int i;
+
+   for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
+   if (aq_vlans[i].enable &&
+   aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED &&
+   aq_vlans[i].vlan_id == vlan) {
+   return true;
+   }
+   }
+
+   return false;
+}
+
+/* Function rebuilds array of vlan filters so that filters with assigned
+ * queue have a precedence over just vlans on the interface.
+ */
+static void aq_fvlan_rebuild(struct aq_nic_s *aq_nic,
+unsigned long *active_vlans,
+struct aq_rx_filter_vlan *aq_vlans)
+{
+   bool vlan_busy = false;
+   int vlan = -1;
+   int i;
+
+   for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
+   if (aq_vlans[i].enable &&
+   aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED)
+   continue;
+   do {
+   vlan = find_next_bit(active_vlans,
+VLAN_N_VID,
+vlan + 1);
+   if (vlan == VLAN_N_VID) {
+   aq_vlans[i].enable = 0U;
+   aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
+   aq_vlans[i].vlan_id = 0;
+   continue;
+   }
+
+   vlan_busy = aq_fvlan_is_busy(aq_vlans, vlan);
+   if (!vlan_busy) {
+   aq_vlans[i].enable = 1U;
+   aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
+   aq_vlans[i].vlan_id = vlan;
+   }
+   } while (vlan_busy && vlan != VLAN_N_VID);
+   }
+}
+
 static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
 struct aq_rx_filter *aq_rx_fltr,
 struct aq_rx_filter_vlan *aq_vlans, bool add)
 {
const struct ethtool_rx_flow_spec *fsp = _rx_fltr->aq_fsp;
int location = fsp->location - AQ_RX_FIRST_LOC_FVLANID;
+   int i;
 
memset(_vlans[location], 0, sizeof(aq_vlans[location]));
 
if (!add)
return 0;
 
+   /* remove vlan if it was in table without queue assignment */
+   for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
+   if (aq_vlans[i].vlan_id ==
+  (be16_to_cpu(fsp->h_ext.vlan_tci) & VLAN_VID_MASK)) {
+   aq_vlans[i].enable = false;
+   }
+   }
+
aq_vlans[location].location = location;
aq_vlans[location].vlan_id = be16_to_cpu(fsp->h_ext.vlan_tci)
 & VLAN_VID_MASK;
aq_vlans[location].queue = fsp->ring_cookie & 0x1FU;
aq_vlans[location].enable = 1U;
+
return 0;
 }
 
+int aq_del_fvlan_by_vlan(struct aq_nic_s *aq_nic, u16 vlan_id)
+{
+   s

[PATCH net-next 0/6] net: aquantia: add rx-flow filter support

2018-11-12 Thread Igor Russkikh
In this patchset the rx-flow filters functionality and vlan filter offloads
are implemented.

The rules in NIC hardware have fixed order and priorities.
To support this, the locations of filters from ethtool perspective are also 
fixed:

* Locations 0 - 15 for VLAN ID filters
* Locations 16 - 31 for L2 EtherType and PCP filters
* Locations 32 - 39 for L3/L4 5-tuple filters (locations 32, 36 for IPv6)

Dmitry Bogdanov (6):
  net: aquantia: add rx-flow filter definitions
  net: aquantia: add infrastructure for ntuple rules
  net: aquantia: add support of L3/L4 ntuple filters
  net: aquantia: add vlan id to rx flow filters
  net: aquantia: add ethertype and PCP to rx flow filters
  net: aquantia: add support of rx-vlan-filter offload

 drivers/net/ethernet/aquantia/atlantic/Makefile|   1 +
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |   2 +-
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  31 +
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 876 +
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  36 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  29 +
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   |  58 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|   2 -
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  21 +-
 .../net/ethernet/aquantia/atlantic/aq_pci_func.c   |   2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 162 +++-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 109 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  48 ++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 135 +++-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  58 ++
 15 files changed, 1533 insertions(+), 37 deletions(-)
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.c
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.h

-- 
2.7.4



[PATCH net-next 4/6] net: aquantia: add vlan id to rx flow filters

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

The VLAN filter (VLAN id) is compared against 16 filters.
VLAN id must be accompanied by mask 0xF000. That is to distinguish
VLAN filter from L2 Ethertype filter with UserPriority since both
User Priority and VLAN ID are passed in the same 'vlan' parameter.
Flow type may be any as  it is not matched for VLAN filter.
Due to fixed order of the rules in the NIC, the location 0-15 are
reserved for vlan filters.

Example:
To add a rule that directs packets from VLAN 2001 to queue 5:
ethtool -N  flow-type ip4 vlan 2001 m 0xF000 action 5 loc 0

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |  2 +-
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 92 +-
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  2 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 +++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  5 ++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 37 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  7 ++
 7 files changed, 151 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index becb578211ed..6b6d1724676e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -14,7 +14,7 @@
 
 #include 
 #include 
-
+#include 
 #include "ver.h"
 #include "aq_cfg.h"
 #include "aq_utils.h"
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index 34e2a28d344a..c5240bc487b4 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -120,6 +120,29 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
 }
 
 static int __must_check
+aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
+  struct aq_hw_rx_fltrs_s *rx_fltrs,
+  struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->location < AQ_RX_FIRST_LOC_FVLANID ||
+   fsp->location > AQ_RX_LAST_LOC_FVLANID) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: location must be in range [%d, %d]",
+  AQ_RX_FIRST_LOC_FVLANID,
+  AQ_RX_LAST_LOC_FVLANID);
+   return -EINVAL;
+   }
+
+   if (fsp->ring_cookie > aq_nic->aq_nic_cfg.num_rss_queues) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: queue number must be in range [0, %d]",
+  aq_nic->aq_nic_cfg.num_rss_queues - 1);
+   return -EINVAL;
+   }
+   return 0;
+}
+
+static int __must_check
 aq_check_filter(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
 {
@@ -127,7 +150,14 @@ aq_check_filter(struct aq_nic_s *aq_nic,
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
 
if (fsp->flow_type & FLOW_EXT) {
-   err = -EOPNOTSUPP;
+   if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
+   err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
+   } else {
+   netdev_err(aq_nic->ndev,
+  "ethtool: invalid vlan mask 0x%x specified",
+  be16_to_cpu(fsp->m_ext.vlan_tci));
+   err = -EINVAL;
+   }
} else {
switch (fsp->flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
@@ -229,6 +259,42 @@ aq_check_rule(struct aq_nic_s *aq_nic,
return err;
 }
 
+static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
+struct aq_rx_filter *aq_rx_fltr,
+struct aq_rx_filter_vlan *aq_vlans, bool add)
+{
+   const struct ethtool_rx_flow_spec *fsp = _rx_fltr->aq_fsp;
+   int location = fsp->location - AQ_RX_FIRST_LOC_FVLANID;
+
+   memset(_vlans[location], 0, sizeof(aq_vlans[location]));
+
+   if (!add)
+   return 0;
+
+   aq_vlans[location].location = location;
+   aq_vlans[location].vlan_id = be16_to_cpu(fsp->h_ext.vlan_tci)
+& VLAN_VID_MASK;
+   aq_vlans[location].queue = fsp->ring_cookie & 0x1FU;
+   aq_vlans[location].enable = 1U;
+   return 0;
+}
+
+static int aq_add_del_fvlan(struct aq_nic_s *aq_nic,
+   struct aq_rx_filter *aq_rx_fltr, bool add)
+{
+   const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
+
+   if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
+   return -EOPNOTSUPP;
+
+   aq_set_data_fvlan(aq_nic,
+ aq_rx_fltr,
+ aq_nic->aq_hw_rx_f

[PATCH net-next 3/6] net: aquantia: add support of L3/L4 ntuple filters

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add support of L3/L4 5-tuple {protocol, src-ip, dst-ip, src-port, dst-port}
filters. Mask is not supported. Src-port and dst-port are only compared for
TCP/UDP/SCTP packets. Both IPv4 and IPv6 are supported.
The supported actions are the drop and the queue assignment.
Due to fixed order of the rules in the NIC, the location 32-39 are
reserved for L3/L4 5-tuple filters. The locations 32 and 36 are
reserved for IPv6 filters.

Examples:
sudo ethtool -N eth0 flow-type ip6 src-ip 2001:db8:0:f101::2 \
dst-ip 2001:db8:0:f101::5 action -1 loc 36

sudo ethtool -N eth0 flow-type udp4 src-ip 10.0.0.4 \
dst-ip 10.0.0.7 src-port 2000 dst-port 2001 action 2 loc 32

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 168 -
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  11 ++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   7 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  58 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  43 ++
 5 files changed, 284 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index 8cb4eaefd6e1..34e2a28d344a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -85,11 +85,46 @@ aq_rule_already_exists(struct aq_nic_s *aq_nic,
return false;
 }
 
+static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
+ struct aq_hw_rx_fltrs_s *rx_fltrs,
+ struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->location < AQ_RX_FIRST_LOC_FL3L4 ||
+   fsp->location > AQ_RX_LAST_LOC_FL3L4) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: location must be in range [%d, %d]",
+  AQ_RX_FIRST_LOC_FL3L4,
+  AQ_RX_LAST_LOC_FL3L4);
+   return -EINVAL;
+   }
+   if (rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv4) {
+   rx_fltrs->fl3l4.is_ipv6 = false;
+   netdev_err(aq_nic->ndev,
+  "ethtool: mixing ipv4 and ipv6 is not allowed");
+   return -EINVAL;
+   } else if (!rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv6) {
+   rx_fltrs->fl3l4.is_ipv6 = true;
+   netdev_err(aq_nic->ndev,
+  "ethtool: mixing ipv4 and ipv6 is not allowed");
+   return -EINVAL;
+   } else if (rx_fltrs->fl3l4.is_ipv6&&
+  fsp->location != AQ_RX_FIRST_LOC_FL3L4 + 4 &&
+  fsp->location != AQ_RX_FIRST_LOC_FL3L4) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: The specified location for ipv6 must be %d 
or %d",
+  AQ_RX_FIRST_LOC_FL3L4, AQ_RX_FIRST_LOC_FL3L4 + 4);
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 static int __must_check
 aq_check_filter(struct aq_nic_s *aq_nic,
struct ethtool_rx_flow_spec *fsp)
 {
int err = 0;
+   struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
 
if (fsp->flow_type & FLOW_EXT) {
err = -EOPNOTSUPP;
@@ -103,14 +138,16 @@ aq_check_filter(struct aq_nic_s *aq_nic,
case SCTP_V4_FLOW:
case IPV4_FLOW:
case IP_USER_FLOW:
-   err = -EOPNOTSUPP;
+   rx_fltrs->fl3l4.is_ipv6 = false;
+   err = aq_check_approve_fl3l4(aq_nic, rx_fltrs, fsp);
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV6_FLOW:
case IPV6_USER_FLOW:
-   err = -EOPNOTSUPP;
+   rx_fltrs->fl3l4.is_ipv6 = true;
+   err = aq_check_approve_fl3l4(aq_nic, rx_fltrs, fsp);
break;
default:
netdev_err(aq_nic->ndev,
@@ -156,6 +193,11 @@ aq_rule_is_not_correct(struct aq_nic_s *aq_nic,
 
if (!aq_nic) {
rule_is_not_correct = true;
+   } else if (fsp->location > AQ_RX_MAX_RXNFC_LOC) {
+   netdev_err(aq_nic->ndev,
+  "ethtool: The specified number %u rule is invalid\n",
+  fsp->location);
+   rule_is_not_correct = true;
} else if (aq_check_filter(aq_nic, fsp)) {
rule_is_not_correct = true;
} else if (fsp->ring_cookie != RX_CLS_FLOW_DISC) {
@@ -187,6 +229,125 @@ aq_check_rule(struct aq_nic_s *aq_nic,
retur

[PATCH net-next 2/6] net: aquantia: add infrastructure for ntuple rules

2018-11-12 Thread Igor Russkikh
From: Dmitry Bogdanov 

Add infrastructure to support ntuple filter configuration.
Add rule, remove rule, reapply on interface up.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/Makefile|   1 +
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  31 ++
 .../net/ethernet/aquantia/atlantic/aq_filters.c| 413 +
 .../net/ethernet/aquantia/atlantic/aq_filters.h|  31 ++
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   |  18 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   6 +
 .../net/ethernet/aquantia/atlantic/aq_pci_func.c   |   2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |   3 +-
 8 files changed, 503 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.c
 create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_filters.h

diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile 
b/drivers/net/ethernet/aquantia/atlantic/Makefile
index 686f6d8c9e79..4556630ee286 100644
--- a/drivers/net/ethernet/aquantia/atlantic/Makefile
+++ b/drivers/net/ethernet/aquantia/atlantic/Makefile
@@ -36,6 +36,7 @@ atlantic-objs := aq_main.o \
aq_ring.o \
aq_hw_utils.o \
aq_ethtool.o \
+   aq_filters.o \
hw_atl/hw_atl_a0.o \
hw_atl/hw_atl_b0.o \
hw_atl/hw_atl_utils.o \
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 6a633c70f603..dce07211c994 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -12,6 +12,7 @@
 #include "aq_ethtool.h"
 #include "aq_nic.h"
 #include "aq_vec.h"
+#include "aq_filters.h"
 
 static void aq_ethtool_get_regs(struct net_device *ndev,
struct ethtool_regs *regs, void *p)
@@ -213,7 +214,36 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev,
case ETHTOOL_GRXRINGS:
cmd->data = cfg->vecs;
break;
+   case ETHTOOL_GRXCLSRLCNT:
+   cmd->rule_cnt = aq_get_rxnfc_count_all_rules(aq_nic);
+   break;
+   case ETHTOOL_GRXCLSRULE:
+   err = aq_get_rxnfc_rule(aq_nic, cmd);
+   break;
+   case ETHTOOL_GRXCLSRLALL:
+   err = aq_get_rxnfc_all_rules(aq_nic, cmd, rule_locs);
+   break;
+   default:
+   err = -EOPNOTSUPP;
+   break;
+   }
 
+   return err;
+}
+
+static int aq_ethtool_set_rxnfc(struct net_device *ndev,
+   struct ethtool_rxnfc *cmd)
+{
+   int err = 0;
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   switch (cmd->cmd) {
+   case ETHTOOL_SRXCLSRLINS:
+   err = aq_add_rxnfc_rule(aq_nic, cmd);
+   break;
+   case ETHTOOL_SRXCLSRLDEL:
+   err = aq_del_rxnfc_rule(aq_nic, cmd);
+   break;
default:
err = -EOPNOTSUPP;
break;
@@ -520,6 +550,7 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
+   .set_rxnfc   = aq_ethtool_set_rxnfc,
.get_sset_count  = aq_ethtool_get_sset_count,
.get_ethtool_stats   = aq_ethtool_stats,
.get_link_ksettings  = aq_ethtool_get_link_ksettings,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
new file mode 100644
index ..8cb4eaefd6e1
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2014-2017 aQuantia Corporation. */
+
+/* File aq_filters.c: RX filters related functions. */
+
+#include "aq_filters.h"
+
+static bool __must_check
+aq_rule_is_approve(struct ethtool_rx_flow_spec *fsp)
+{
+   if (fsp->flow_type & FLOW_MAC_EXT)
+   return false;
+
+   switch (fsp->flow_type & ~FLOW_EXT) {
+   case ETHER_FLOW:
+   case TCP_V4_FLOW:
+   case UDP_V4_FLOW:
+   case SCTP_V4_FLOW:
+   case TCP_V6_FLOW:
+   case UDP_V6_FLOW:
+   case SCTP_V6_FLOW:
+   case IPV4_FLOW:
+   case IPV6_FLOW:
+   return true;
+   case IP_USER_FLOW:
+   switch (fsp->h_u.usr_ip4_spec.proto) {
+   case IPPROTO_TCP:
+   case IPPROTO_UDP:
+   case IPPROTO_SCTP:
+   case IPPROTO_IP:
+   return true;
+   default:
+   return false;
+   }
+   case IPV6_USER_FLOW:
+   switch (fsp->h_u.usr_ip6_spec.l4_proto) {
+   case IPPROTO_TCP:
+   ca

[PATCH net 4/5] net: aquantia: invalid checksumm offload implementation

2018-11-09 Thread Igor Russkikh
From: Dmitry Bogdanov 

Packets with marked invalid IP/UDP/TCP checksums were considered as good
by the driver. The error was in a logic, processing offload bits in
RX descriptor.

Signed-off-by: Igor Russkikh 
Signed-off-by: Dmitry Bogdanov 
---
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   | 35 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 36 +++---
 2 files changed, 41 insertions(+), 30 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index 3db91446cc67..74550ccc7a20 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -172,6 +172,27 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
return !!budget;
 }
 
+static void aq_rx_checksum(struct aq_ring_s *self,
+  struct aq_ring_buff_s *buff,
+  struct sk_buff *skb)
+{
+   if (!(self->aq_nic->ndev->features & NETIF_F_RXCSUM))
+   return;
+
+   if (unlikely(buff->is_cso_err)) {
+   ++self->stats.rx.errors;
+   skb->ip_summed = CHECKSUM_NONE;
+   return;
+   }
+   if (buff->is_ip_cso) {
+   __skb_incr_checksum_unnecessary(skb);
+   if (buff->is_udp_cso || buff->is_tcp_cso)
+   __skb_incr_checksum_unnecessary(skb);
+   } else {
+   skb->ip_summed = CHECKSUM_NONE;
+   }
+}
+
 #define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
 int aq_ring_rx_clean(struct aq_ring_s *self,
 struct napi_struct *napi,
@@ -267,18 +288,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
}
 
skb->protocol = eth_type_trans(skb, ndev);
-   if (unlikely(buff->is_cso_err)) {
-   ++self->stats.rx.errors;
-   skb->ip_summed = CHECKSUM_NONE;
-   } else {
-   if (buff->is_ip_cso) {
-   __skb_incr_checksum_unnecessary(skb);
-   if (buff->is_udp_cso || buff->is_tcp_cso)
-   __skb_incr_checksum_unnecessary(skb);
-   } else {
-   skb->ip_summed = CHECKSUM_NONE;
-   }
-   }
+
+   aq_rx_checksum(self, buff, skb);
 
skb_set_hash(skb, buff->rss_hash,
 buff->is_hash_l4 ? PKT_HASH_TYPE_L4 :
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 3aec56623bf5..179ce12fe4d8 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -660,9 +660,9 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s 
*self,
struct hw_atl_rxd_wb_s *rxd_wb = (struct hw_atl_rxd_wb_s *)
>dx_ring[ring->hw_head * HW_ATL_B0_RXD_SIZE];
 
-   unsigned int is_err = 1U;
unsigned int is_rx_check_sum_enabled = 0U;
unsigned int pkt_type = 0U;
+   u8 rx_stat = 0U;
 
if (!(rxd_wb->status & 0x1U)) { /* RxD is not done */
break;
@@ -670,35 +670,35 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s 
*self,
 
buff = >buff_ring[ring->hw_head];
 
-   is_err = (0x003CU & rxd_wb->status);
+   rx_stat = (0x003CU & rxd_wb->status) >> 2;
 
is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19);
-   is_err &= ~0x20U; /* exclude validity bit */
 
pkt_type = 0xFFU & (rxd_wb->type >> 4);
 
-   if (is_rx_check_sum_enabled) {
-   if (0x0U == (pkt_type & 0x3U))
-   buff->is_ip_cso = (is_err & 0x08U) ? 0U : 1U;
+   if (is_rx_check_sum_enabled & BIT(0) &&
+   (0x0U == (pkt_type & 0x3U)))
+   buff->is_ip_cso = (rx_stat & BIT(1)) ? 0U : 1U;
 
+   if (is_rx_check_sum_enabled & BIT(1)) {
if (0x4U == (pkt_type & 0x1CU))
-   buff->is_udp_cso = buff->is_cso_err ? 0U : 1U;
+   buff->is_udp_cso = (rx_stat & BIT(2)) ? 0U :
+  !!(rx_stat & BIT(3));
else if (0x0U == (pkt_type & 0x1CU))
-   buff->is_tcp_cso = buff->is_cso_err ? 0U : 1U;
-
-   /* Checksum offload workaround for small packets */
- 

[PATCH net 3/5] net: aquantia: fixed enable unicast on 32 macvlan

2018-11-09 Thread Igor Russkikh
Fixed a condition mistake due to which macvlans unicast
item number 32 was not added in the unicast filter.

The consequence is that when exactly 32 macvlans are created
on NIC, the last created macvlan receives no traffic because
its MAC was not registered in HW.

Fixes: 94b3b542303f ("net: aquantia: vlan unicast address list correct 
handling")

Signed-off-by: Igor Russkikh 
Tested-by: Nikita Danilov 
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 0011a3f2f672..b5e7c98f424c 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -600,7 +600,7 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct 
net_device *ndev)
}
}
 
-   if (i > 0 && i < AQ_HW_MULTICAST_ADDRESS_MAX) {
+   if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) {
packet_filter |= IFF_MULTICAST;
self->mc_list.count = i;
self->aq_hw_ops->hw_multicast_list_set(self->aq_hw,
-- 
2.7.4



[PATCH net 5/5] net: aquantia: allow rx checksum offload configuration

2018-11-09 Thread Igor Russkikh
From: Dmitry Bogdanov 

RX Checksum offloads could not be configured and ignored netdev features
flag for checksumming.

Signed-off-by: Igor Russkikh 
Signed-off-by: Dmitry Bogdanov 
---
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h|  3 +++
 drivers/net/ethernet/aquantia/atlantic/aq_main.c  | 10 --
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c   |  2 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h   |  2 +-
 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c |  7 +--
 5 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 7ec8d24b2b0b..a1e70da358ca 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -204,6 +204,9 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
+   int (*hw_set_offload)(struct aq_hw_s *self,
+ struct aq_nic_cfg_s *aq_nic_cfg);
+
int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc);
 };
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
index e3ae29e523f0..7c07eef275eb 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
@@ -99,8 +99,11 @@ static int aq_ndev_set_features(struct net_device *ndev,
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic);
bool is_lro = false;
+   int err = 0;
+
+   aq_cfg->features = features;
 
-   if (aq_cfg->hw_features & NETIF_F_LRO) {
+   if (aq_cfg->aq_hw_caps->hw_features & NETIF_F_LRO) {
is_lro = features & NETIF_F_LRO;
 
if (aq_cfg->is_lro != is_lro) {
@@ -112,8 +115,11 @@ static int aq_ndev_set_features(struct net_device *ndev,
}
}
}
+   if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM)
+   err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
+   aq_cfg);
 
-   return 0;
+   return err;
 }
 
 static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index b5e7c98f424c..7abdc0952425 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -118,7 +118,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
}
 
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
-   cfg->hw_features = cfg->aq_hw_caps->hw_features;
+   cfg->features = cfg->aq_hw_caps->hw_features;
 }
 
 static int aq_nic_update_link_status(struct aq_nic_s *self)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index c1582f4e8e1b..44ec47a3d60a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -23,7 +23,7 @@ struct aq_vec_s;
 
 struct aq_nic_cfg_s {
const struct aq_hw_caps_s *aq_hw_caps;
-   u64 hw_features;
+   u64 features;
u32 rxds;   /* rx ring size, descriptors # */
u32 txds;   /* tx ring size, descriptors # */
u32 vecs;   /* vecs==allocated irqs */
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 179ce12fe4d8..f02592f43fe3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -234,8 +234,10 @@ static int hw_atl_b0_hw_offload_set(struct aq_hw_s *self,
hw_atl_tpo_tcp_udp_crc_offload_en_set(self, 1);
 
/* RX checksums offloads*/
-   hw_atl_rpo_ipv4header_crc_offload_en_set(self, 1);
-   hw_atl_rpo_tcp_udp_crc_offload_en_set(self, 1);
+   hw_atl_rpo_ipv4header_crc_offload_en_set(self, !!(aq_nic_cfg->features &
+NETIF_F_RXCSUM));
+   hw_atl_rpo_tcp_udp_crc_offload_en_set(self, !!(aq_nic_cfg->features &
+ NETIF_F_RXCSUM));
 
/* LSO offloads*/
hw_atl_tdm_large_send_offload_en_set(self, 0xU);
@@ -974,5 +976,6 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version   = hw_atl_utils_get_fw_version,
+   .hw_set_offload  = hw_atl_b0_hw_offload_set,
.hw_set_fc   = hw_atl_b0_set_fc,
 };
-- 
2.7.4



[PATCH net 2/5] net: aquantia: fix potential IOMMU fault after driver unbind

2018-11-09 Thread Igor Russkikh
From: Dmitry Bogdanov 

IOMMU fault may occurr on unbind/bind or if_down/if_up sequence.

Although driver disables the rings on down, this is not enough.
Due to internal HW design, during subsequent initialization
NIC sometimes may reuse RX descriptors cache and write to the
host memory from the descriptor cache.
That's get catched by IOMMU on host.

This patch invalidates the descriptor cache in NIC on interface down
to prevent writing to the cached descriptors and to the memory pointed
in those descriptors.

Signed-off-by: Dmitry Bogdanov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  6 ++
 .../net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |  8 
 .../net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  3 +++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 18 ++
 4 files changed, 35 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 119265762b0c..3aec56623bf5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -920,6 +920,12 @@ static int hw_atl_b0_hw_interrupt_moderation_set(struct 
aq_hw_s *self)
 static int hw_atl_b0_hw_stop(struct aq_hw_s *self)
 {
hw_atl_b0_hw_irq_disable(self, HW_ATL_B0_INT_MASK);
+
+   /* Invalidate Descriptor Cache to prevent writing to the cached
+* descriptors and to the data pointer of those descriptors
+*/
+   hw_atl_rdm_rx_dma_desc_cache_init_set(self, 1);
+
return aq_hw_err_from_flags(self);
 }
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index be0a3a90dfad..5502ec5f0f69 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -619,6 +619,14 @@ void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s 
*aq_hw, u32 rx_flow_ctl_mode
HW_ATL_RPB_RX_FC_MODE_SHIFT, rx_flow_ctl_mode);
 }
 
+void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR,
+   HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK,
+   HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT,
+   init);
+}
+
 void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw,
u32 rx_pkt_buff_size_per_tc, u32 
buffer)
 {
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index 7056c7342afc..41f239928c15 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -325,6 +325,9 @@ void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s 
*aq_hw,
u32 rx_pkt_buff_size_per_tc,
u32 buffer);
 
+/* set rdm rx dma descriptor cache init */
+void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init);
+
 /* set rx xoff enable (per tc) */
 void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 
rx_xoff_en_per_tc,
  u32 buffer);
diff --git 
a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
index 716674a9b729..a715fa317b1c 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -293,6 +293,24 @@
 /* default value of bitfield desc{d}_reset */
 #define HW_ATL_RDM_DESCDRESET_DEFAULT 0x0
 
+/* rdm_desc_init_i bitfield definitions
+ * preprocessor definitions for the bitfield rdm_desc_init_i.
+ * port="pif_rdm_desc_init_i"
+ */
+
+/* register address for bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR 0x5a00
+/* bitmask for bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK 0x
+/* inverted bitmask for bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSKN 0x
+/* lower bit position of bitfield  rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT 0
+/* width of bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_WIDTH 32
+/* default value of bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_DEFAULT 0x0
+
 /* rx int_desc_wrb_en bitfield definitions
  * preprocessor definitions for the bitfield "int_desc_wrb_en".
  * port="pif_rdm_int_desc_wrb_en_i"
-- 
2.7.4



[PATCH net 0/5] net: aquantia: 2018-11 bugfixes

2018-11-09 Thread Igor Russkikh
The patchset fixes a number of bugs found in various areas after
driver validation.

Dmitry Bogdanov (3):
  net: aquantia: fix potential IOMMU fault after driver unbind
  net: aquantia: invalid checksumm offload implementation
  net: aquantia: allow rx checksum offload configuration

Igor Russkikh (2):
  net: aquantia: synchronized flow control between mac/phy
  net: aquantia: fixed enable unicast on 32 macvlan

 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  8 +--
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  6 +++
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   | 10 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c| 18 +--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  2 +-
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   | 35 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 61 ++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |  8 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  3 ++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 18 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 21 
 11 files changed, 145 insertions(+), 45 deletions(-)

-- 
2.7.4



[PATCH net 1/5] net: aquantia: synchronized flow control between mac/phy

2018-11-09 Thread Igor Russkikh
Flow control statuses were not synchronized between blocks,
that caused packets/link drop on some corner cases, when
MAC sent PFC although Phy was not expecting these to come.

Driver should readout the negotiated FC from phy and
configure RX block accordigly.

This is done on each link change event with information from FW.

Fixes: 288551de45aa ("net: aquantia: Implement rx/tx flow control ethtools 
callback")

Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c |  8 
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h  |  3 +++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 14 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c   | 12 +---
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c| 21 +
 5 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 6a633c70f603..99ef1daaa4d8 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -407,13 +407,13 @@ static void aq_ethtool_get_pauseparam(struct net_device 
*ndev,
  struct ethtool_pauseparam *pause)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   u32 fc = aq_nic->aq_nic_cfg.flow_control;
 
pause->autoneg = 0;
 
-   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
-   pause->rx_pause = 1;
-   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
-   pause->tx_pause = 1;
+   pause->rx_pause = !!(fc & AQ_NIC_FC_RX);
+   pause->tx_pause = !!(fc & AQ_NIC_FC_TX);
+
 }
 
 static int aq_ethtool_set_pauseparam(struct net_device *ndev,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index e8689241204e..7ec8d24b2b0b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -204,6 +204,7 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
+   int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc);
 };
 
 struct aq_fw_ops {
@@ -226,6 +227,8 @@ struct aq_fw_ops {
 
int (*update_stats)(struct aq_hw_s *self);
 
+   u32 (*get_flow_control)(struct aq_hw_s *self, u32 *fcmode);
+
int (*set_flow_control)(struct aq_hw_s *self);
 
int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 5fed24446687..0011a3f2f672 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -124,6 +124,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
 static int aq_nic_update_link_status(struct aq_nic_s *self)
 {
int err = self->aq_fw_ops->update_link_status(self->aq_hw);
+   u32 fc = 0;
 
if (err)
return err;
@@ -133,6 +134,15 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
AQ_CFG_DRV_NAME, self->link_status.mbps,
self->aq_hw->aq_link_status.mbps);
aq_nic_update_interrupt_moderation_settings(self);
+
+   /* Driver has to update flow control settings on RX block
+* on any link event.
+* We should query FW whether it negotiated FC.
+*/
+   if (self->aq_fw_ops->get_flow_control)
+   self->aq_fw_ops->get_flow_control(self->aq_hw, );
+   if (self->aq_hw_ops->hw_set_fc)
+   self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0);
}
 
self->link_status = self->aq_hw->aq_link_status;
@@ -772,7 +782,9 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 Pause);
 
-   if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX)
+   /* Asym is when either RX or TX, but not both */
+   if (!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX) ^
+   !!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX))
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 Asym_Pause);
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 76d25d594a0f..119265762b0c 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -100,12 +100,17 @@ static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
return err;
 }

Re: [PATCH v2 net] net: aquantia: memory corruption on jumbo frames

2018-09-18 Thread Igor Russkikh


>> Fixes: 018423e90bee ("net: ethernet: aquantia: Add ring support code")
>>
>> Reported-by: Friedemann Gerold 
>> Reported-by: Michael Rauch 
>> Signed-off-by: Friedemann Gerold 
>> Tested-by: Nikita Danilov 
>> Signed-off-by: Igor Russkikh 
> 
> APplied and queued up for -stable.

Hi David, I see this was applied to net-next tree only.
Can we have it in net? We consider it as critical flaw.

BR, Igor


[PATCH v2 net] net: aquantia: memory corruption on jumbo frames

2018-09-15 Thread Igor Russkikh
From: Friedemann Gerold 

This patch fixes skb_shared area, which will be corrupted
upon reception of 4K jumbo packets.

Originally build_skb usage purpose was to reuse page for skb to eliminate
needs of extra fragments. But that logic does not take into account that
skb_shared_info should be reserved at the end of skb data area.

In case packet data consumes all the page (4K), skb_shinfo location
overflows the page. As a consequence, __build_skb zeroed shinfo data above
the allocated page, corrupting next page.

The issue is rarely seen in real life because jumbo are normally larger
than 4K and that causes another code path to trigger.
But it 100% reproducible with simple scapy packet, like:

sendp(IP(dst="192.168.100.3") / TCP(dport=443) \
  / Raw(RandString(size=(4096-40))), iface="enp1s0")

Fixes: 018423e90bee ("net: ethernet: aquantia: Add ring support code")

Reported-by: Friedemann Gerold 
Reported-by: Michael Rauch 
Signed-off-by: Friedemann Gerold 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 32 +---
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index b5f1f62e8e25..d1e1a0ba8615 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -225,9 +225,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
}
 
/* for single fragment packets use build_skb() */
-   if (buff->is_eop) {
+   if (buff->is_eop &&
+   buff->len <= AQ_CFG_RX_FRAME_MAX - AQ_SKB_ALIGN) {
skb = build_skb(page_address(buff->page),
-   buff->len + AQ_SKB_ALIGN);
+   AQ_CFG_RX_FRAME_MAX);
if (unlikely(!skb)) {
err = -ENOMEM;
goto err_exit;
@@ -247,18 +248,21 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
buff->len - ETH_HLEN,
SKB_TRUESIZE(buff->len - ETH_HLEN));
 
-   for (i = 1U, next_ = buff->next,
-buff_ = >buff_ring[next_]; true;
-next_ = buff_->next,
-buff_ = >buff_ring[next_], ++i) {
-   skb_add_rx_frag(skb, i, buff_->page, 0,
-   buff_->len,
-   SKB_TRUESIZE(buff->len -
-   ETH_HLEN));
-   buff_->is_cleaned = 1;
-
-   if (buff_->is_eop)
-   break;
+   if (!buff->is_eop) {
+   for (i = 1U, next_ = buff->next,
+buff_ = >buff_ring[next_];
+true; next_ = buff_->next,
+buff_ = >buff_ring[next_], ++i) {
+   skb_add_rx_frag(skb, i,
+   buff_->page, 0,
+   buff_->len,
+   SKB_TRUESIZE(buff->len -
+   ETH_HLEN));
+   buff_->is_cleaned = 1;
+
+   if (buff_->is_eop)
+   break;
+   }
}
}
 
-- 
2.7.4



Re: [PATCH net] net: aquantia: memory corruption on jumbo frames

2018-09-15 Thread Igor Russkikh


> This patch fixes skb_shared area, which will be corrupted
> upon reception of 4K jumbo packets.
> 

Hi David, please discard this patch as it wrongly specifies the original issue 
reporter and patch author.
I'm fixing it now and will resend.
Sorry for this.

BR, Igor


[PATCH net] net: aquantia: memory corruption on jumbo frames

2018-09-15 Thread Igor Russkikh
From: Michael Rauch 

This patch fixes skb_shared area, which will be corrupted
upon reception of 4K jumbo packets.

Originally build_skb usage purpose was to reuse page for skb to eliminate
needs of extra fragments. But that logic does not take into account that
skb_shared_info should be reserved at the end of skb data area.

In case packet data consumes all the page (4K), skb_shinfo location
overflows the page. As a consequence, __build_skb zeroed shinfo data above
the allocated page, corrupting next page.

The issue is rarely seen in real life because jumbo are normally larger
than 4K and that causes another code path to trigger.
But it 100% reproducible with simple scapy packet, like:

sendp(IP(dst="192.168.100.3") / TCP(dport=443) \
  / Raw(RandString(size=(4096-40))), iface="enp1s0")

Fixes: 018423e90bee ("net: ethernet: aquantia: Add ring support code")

Reported-by: Michael Rauch 
Tested-by: Michael Rauch 
Signed-off-by: Michael Rauch 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 32 +---
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index b5f1f62e8e25..d1e1a0ba8615 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -225,9 +225,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
}
 
/* for single fragment packets use build_skb() */
-   if (buff->is_eop) {
+   if (buff->is_eop &&
+   buff->len <= AQ_CFG_RX_FRAME_MAX - AQ_SKB_ALIGN) {
skb = build_skb(page_address(buff->page),
-   buff->len + AQ_SKB_ALIGN);
+   AQ_CFG_RX_FRAME_MAX);
if (unlikely(!skb)) {
err = -ENOMEM;
goto err_exit;
@@ -247,18 +248,21 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
buff->len - ETH_HLEN,
SKB_TRUESIZE(buff->len - ETH_HLEN));
 
-   for (i = 1U, next_ = buff->next,
-buff_ = >buff_ring[next_]; true;
-next_ = buff_->next,
-buff_ = >buff_ring[next_], ++i) {
-   skb_add_rx_frag(skb, i, buff_->page, 0,
-   buff_->len,
-   SKB_TRUESIZE(buff->len -
-   ETH_HLEN));
-   buff_->is_cleaned = 1;
-
-   if (buff_->is_eop)
-   break;
+   if (!buff->is_eop) {
+   for (i = 1U, next_ = buff->next,
+buff_ = >buff_ring[next_];
+true; next_ = buff_->next,
+buff_ = >buff_ring[next_], ++i) {
+   skb_add_rx_frag(skb, i,
+   buff_->page, 0,
+   buff_->len,
+   SKB_TRUESIZE(buff->len -
+   ETH_HLEN));
+   buff_->is_cleaned = 1;
+
+   if (buff_->is_eop)
+   break;
+   }
}
}
 
-- 
2.7.4



Re: [PATCH net-next v3 0/7] net: aquantia: implement WOL and EEE support

2018-09-12 Thread Igor Russkikh


>> Discussion outcome regarding driver version bumps was not finished
>> (here https://patchwork.ozlabs.org/patch/954905/)
>> David, could you suggest the best way to proceed on this?
> 
> Having a channel for your driver that is outside of upstream and Linux
> distribution packages creates lots of problems.
> 
> When a user reports a problem with an upstream kernel, that verion
> dictates which driver source was being used.  There is not confusion
> or ambiguity.
> 
> For a distribution kernel, the distributor hashes out which driver
> they published in their kernel package when evaluating a bug reported
> to them.
> 
> None of these two entities is ready to evaluate and handle properly
> your custom scheme.
> 
> So generally I frown against separate distribution schemes.  It is
> in the final analysis an inferior experience for the user because
> you basically narrow all of their support channels for problems
> down to you and you alone.  The whole idea is to make it work the
> opposite way.
> 
> So in the upstream tree, really, the driver version is pretty useless.

Thank you for the comment, David.

I'll pass over these concerns to my company management.

BR, Igor


[PATCH net-next v3 0/7] net: aquantia: implement WOL and EEE support

2018-09-10 Thread Igor Russkikh
This is v3 of WOL/EEE functionality patch for atlantic driver.

In this patchset Yana Esina and Nikita Danilov implemented:

- Upload function to interact with FW memory
- Definitions and structures necessary for the correct operation of Wake ON Lan
- The functionality Wake On Lan via ethtool (Magic packet is supported)
- The functionality for Energy-Efficient Ethernet configuration via ethtool

Version 3:
- use ETH_ALEN instead of raw number

Version 2 has the following fixes:
- patchset reorganized to extract renaming and whitespace fixes into separate
  patches
- some of magic numbers replaced with defines
- reverse christmas tree applied

Discussion outcome regarding driver version bumps was not finished
(here https://patchwork.ozlabs.org/patch/954905/)
David, could you suggest the best way to proceed on this?

Igor Russkikh (1):
  net: aquantia: bump driver version

Nikita Danilov (2):
  net: aquantia: whitespace changes
  net: aquantia: renaming for better visibility

Yana Esina (4):
  net: aquantia: fix hw_atl_utils_fw_upload_dwords
  net: aquantia: definitions for WOL
  net: aquantia: implement WOL support
  net: aquantia: implement EEE support

 drivers/net/ethernet/aquantia/atlantic/aq_common.h |   5 +
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 113 +-
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  13 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  24 ++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   4 +
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   |   4 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  41 ++--
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  35 ++--
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |   8 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |   3 +
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h |  13 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 163 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 130 +++-
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 233 -
 drivers/net/ethernet/aquantia/atlantic/ver.h   |   2 +-
 17 files changed, 675 insertions(+), 128 deletions(-)

-- 
2.7.4



[PATCH net-next v3 2/7] net: aquantia: definitions for WOL

2018-09-10 Thread Igor Russkikh
From: Yana Esina 

Added definitions and structures needed to support WOL.

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  3 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 94 --
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 32 
 3 files changed, 124 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index fecfc401f95d..2069cbb6e1a1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -36,6 +36,7 @@ struct aq_nic_cfg_s {
u32 flow_control;
u32 link_speed_msk;
u32 vlan_id;
+   u32 wol;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
@@ -54,6 +55,8 @@ struct aq_nic_cfg_s {
 #define AQ_NIC_FLAG_ERR_UNPLUG  0x4000U
 #define AQ_NIC_FLAG_ERR_HW  0x8000U
 
+#define AQ_NIC_WOL_ENABLED BIT(0)
+
 #define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index 505c8a2abd9c..beec0775f1c1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -101,8 +101,6 @@ struct __packed hw_aq_atl_utils_fw_rpc {
struct {
u32 priority;
u32 wol_packet_type;
-   u16 friendly_name_len;
-   u16 friendly_name[65];
u32 pattern_id;
u32 next_wol_pattern_offset;
 
@@ -134,13 +132,36 @@ struct __packed hw_aq_atl_utils_fw_rpc {
u32 pattern_offset;
u32 pattern_size;
} wol_bit_map_pattern;
+
+   struct {
+   u8 mac_addr[ETH_ALEN];
+   } wol_magic_packet_patter;
} wol_pattern;
} msg_wol;
 
struct {
-   u32 is_wake_on_link_down;
-   u32 is_wake_on_link_up;
-   } msg_wolink;
+   union {
+   u32 pattern_mask;
+
+   struct {
+   u32 reason_arp_v4_pkt : 1;
+   u32 reason_ipv4_ping_pkt : 1;
+   u32 reason_ipv6_ns_pkt : 1;
+   u32 reason_ipv6_ping_pkt : 1;
+   u32 reason_link_up : 1;
+   u32 reason_link_down : 1;
+   u32 reason_maximum : 1;
+   };
+   };
+
+   union {
+   u32 offload_mask;
+   };
+   } msg_enable_wakeup;
+
+   struct {
+   u32 id;
+   } msg_del_id;
};
 };
 
@@ -155,6 +176,57 @@ struct __packed hw_aq_atl_utils_mbox {
struct hw_atl_stats_s stats;
 };
 
+/* fw2x */
+typedef u32fw_offset_t;
+
+struct __packed offload_ip_info {
+   u8 v4_local_addr_count;
+   u8 v4_addr_count;
+   u8 v6_local_addr_count;
+   u8 v6_addr_count;
+   fw_offset_t v4_addr;
+   fw_offset_t v4_prefix;
+   fw_offset_t v6_addr;
+   fw_offset_t v6_prefix;
+};
+
+struct __packed offload_port_info {
+   u16 udp_port_count;
+   u16 tcp_port_count;
+   fw_offset_t udp_port;
+   fw_offset_t tcp_port;
+};
+
+struct __packed offload_ka_info {
+   u16 v4_ka_count;
+   u16 v6_ka_count;
+   u32 retry_count;
+   u32 retry_interval;
+   fw_offset_t v4_ka;
+   fw_offset_t v6_ka;
+};
+
+struct __packed offload_rr_info {
+   u32 rr_count;
+   u32 rr_buf_len;
+   fw_offset_t rr_id_x;
+   fw_offset_t rr_buf;
+};
+
+struct __packed offload_info {
+   u32 version;
+   u32 len;
+   u8 mac_addr[ETH_ALEN];
+
+   u8 reserved[2];
+
+   struct offload_ip_info ips;
+   struct offload_port_info ports;
+   struct offload_ka_info kas;
+   struct offload_rr_info rrs;
+   u8 buf[0];
+};
+
 #define HAL_ATLANTIC_UTILS_CHIP_MIPS 0x0001U
 #define HAL_ATLANTIC_UTILS_CHIP_TPO2 0x0002U
 #define HAL_ATLANTIC_UTILS_CHIP_RPF2 0x0004U
@@ -181,6 +253,18 @@ enum hal_atl_utils_fw_state_e {
 #define HAL_ATLANTIC_RATE_100M   BIT(5)
 #define HAL_ATLANTIC_RATE_INVALIDBIT(6)
 
+#define HAL_ATLANTIC_UTILS_FW_MSG_PING  0x1U

[PATCH net-next v3 7/7] net: aquantia: bump driver version

2018-09-10 Thread Igor Russkikh
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/ver.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h 
b/drivers/net/ethernet/aquantia/atlantic/ver.h
index 94efc6477bdc..b48260114da3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -12,7 +12,7 @@
 
 #define NIC_MAJOR_DRIVER_VERSION   2
 #define NIC_MINOR_DRIVER_VERSION   0
-#define NIC_BUILD_DRIVER_VERSION   3
+#define NIC_BUILD_DRIVER_VERSION   4
 #define NIC_REVISION_DRIVER_VERSION0
 
 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
-- 
2.7.4



[PATCH net-next v3 3/7] net: aquantia: implement WOL support

2018-09-10 Thread Igor Russkikh
From: Yana Esina 

Add WOL support. Currently only magic packet
(ethtool -s  wol g) feature is implemented.

Remove hw_set_power and move that to FW_OPS set_power:
because WOL configuration behaves differently on 1x and 2x
firmwares

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 32 +++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  4 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c| 12 +--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  1 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  1 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 84 +--
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  5 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 98 +-
 8 files changed, 220 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 08c9fa6ca71f..b88be5e5f0a2 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,36 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_ethtool_get_wol(struct net_device *ndev,
+  struct ethtool_wolinfo *wol)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+
+   wol->supported = WAKE_MAGIC;
+   wol->wolopts = 0;
+
+   if (cfg->wol)
+   wol->wolopts |= WAKE_MAGIC;
+}
+
+static int aq_ethtool_set_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+   struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+   int err = 0;
+
+   if (wol->wolopts & WAKE_MAGIC)
+   cfg->wol |= AQ_NIC_WOL_ENABLED;
+   else
+   cfg->wol &= ~AQ_NIC_WOL_ENABLED;
+   err = device_set_wakeup_enable(>dev, wol->wolopts);
+
+   return err;
+}
+
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -403,6 +433,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .get_wol = aq_ethtool_get_wol,
+   .set_wol = aq_ethtool_set_wol,
.nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 5c00671f248d..9050b40d4f58 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -204,7 +204,6 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
-   int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
 };
 
 struct aq_fw_ops {
@@ -228,6 +227,9 @@ struct aq_fw_ops {
int (*update_stats)(struct aq_hw_s *self);
 
int (*set_flow_control)(struct aq_hw_s *self);
+
+   int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
+u8 *mac);
 };
 
 #endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 26dc6782b475..9809dbf8c272 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -889,11 +889,13 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec);
 
-   if (self->power_state == AQ_HW_POWER_STATE_D0) {
-   (void)self->aq_fw_ops->deinit(self->aq_hw);
-   } else {
-   (void)self->aq_hw_ops->hw_set_power(self->aq_hw,
-  self->power_state);
+   self->aq_fw_ops->deinit(self->aq_hw);
+
+   if (self->power_state != AQ_HW_POWER_STATE_D0 ||
+   self->aq_hw->aq_nic_cfg->wol) {
+   self->aq_fw_ops->set_power(self->aq_hw,
+  self->power_state,
+  self->ndev->dev_addr);
}
 
 err_exit:;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 97addfa6f895..1dd0ef4a895c 100644
--- a/drivers/n

[PATCH net-next v3 6/7] net: aquantia: renaming for better visibility

2018-09-10 Thread Igor Russkikh
From: Nikita Danilov 

Removed extra characters from the names of structures to unify prefixes
used through the driver code (we normally use hw_atl for hw specifics).
HW_ATL_B0_ and HW_ATL_A0_ are the same and useless copies.

Signed-off-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  4 +--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  | 32 ++--
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |  6 
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 34 +++---
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |  6 
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 14 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 14 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  6 ++--
 8 files changed, 52 insertions(+), 64 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 908f19fe19b3..e8689241204e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -112,7 +112,7 @@ struct aq_hw_s {
const struct aq_fw_ops *aq_fw_ops;
void __iomem *mmio;
struct aq_hw_link_status_s aq_link_status;
-   struct hw_aq_atl_utils_mbox mbox;
+   struct hw_atl_utils_mbox mbox;
struct hw_atl_stats_s last_stats;
struct aq_stats_s curr_stats;
u64 speed;
@@ -124,7 +124,7 @@ struct aq_hw_s {
u32 mbox_addr;
u32 rpc_addr;
u32 rpc_tid;
-   struct hw_aq_atl_utils_fw_rpc rpc;
+   struct hw_atl_utils_fw_rpc rpc;
 };
 
 struct aq_ring_s;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index d1d5bfda6a5b..2469ed4d86b9 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -49,37 +49,37 @@
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_FIBRE,
-   .link_speed_msk = HW_ATL_A0_RATE_5G |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
-   .link_speed_msk = HW_ATL_A0_RATE_10G |
- HW_ATL_A0_RATE_5G |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_10G |
+ AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
-   .link_speed_msk = HW_ATL_A0_RATE_5G  |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G  |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
-   .link_speed_msk = HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 static int hw_atl_a0_hw_reset(struct aq_hw_s *self)
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
index 3c94cff57876..a021dc431ef7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
@@ -62,12 +62,6 @@
 #define HW_ATL_A0_MPI_SPEED_MSK   0xU
 #define HW_ATL_A0_MPI_SPEED_SHIFT 16U
 
-#define HW_ATL_A0_RATE_10GBIT(0)
-#define HW_ATL_A0_RATE_5G BIT(1)
-#define HW_ATL_A0_RATE_2G5BIT(3)
-#define HW_ATL_A0_RATE_1G BIT(4)
-#define HW_ATL_A0_RATE_100M   BIT(5)
-
 #define HW_ATL_A0_TXBUF_MAX 160U
 #define HW_ATL_A0_RXBUF_MAX 320U
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 7c8ee103c825

[PATCH net-next v3 4/7] net: aquantia: implement EEE support

2018-09-10 Thread Igor Russkikh
From: Yana Esina 

Support of Energy-Efficient Ethernet to aQuantia NIC's via ethtool
(according to the IEEE 802.3az specifications)

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |  5 ++
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 77 +++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  5 ++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  1 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  2 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 13 
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 86 ++
 7 files changed, 189 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index d52b088ff8f0..becb578211ed 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -57,4 +57,9 @@
 #define AQ_NIC_RATE_1G BIT(4)
 #define AQ_NIC_RATE_100M   BIT(5)
 
+#define AQ_NIC_RATE_EEE_10GBIT(6)
+#define AQ_NIC_RATE_EEE_5G BIT(7)
+#define AQ_NIC_RATE_EEE_2GSBIT(8)
+#define AQ_NIC_RATE_EEE_1G BIT(9)
+
 #endif /* AQ_COMMON_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index b88be5e5f0a2..22dd4fbd34d7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -315,6 +315,81 @@ static int aq_ethtool_set_wol(struct net_device *ndev,
return err;
 }
 
+static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
+{
+   u32 rate = 0;
+
+   if (speed & AQ_NIC_RATE_EEE_10G)
+   rate |= SUPPORTED_1baseT_Full;
+
+   if (speed & AQ_NIC_RATE_EEE_2GS)
+   rate |= SUPPORTED_2500baseX_Full;
+
+   if (speed & AQ_NIC_RATE_EEE_1G)
+   rate |= SUPPORTED_1000baseT_Full;
+
+   return rate;
+}
+
+static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   u32 rate, supported_rates;
+   int err = 0;
+
+   if (!aq_nic->aq_fw_ops->get_eee_rate)
+   return -EOPNOTSUPP;
+
+   err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, ,
+ _rates);
+   if (err < 0)
+   return err;
+
+   eee->supported = eee_mask_to_ethtool_mask(supported_rates);
+
+   if (aq_nic->aq_nic_cfg.eee_speeds)
+   eee->advertised = eee->supported;
+
+   eee->lp_advertised = eee_mask_to_ethtool_mask(rate);
+
+   eee->eee_enabled = !!eee->advertised;
+
+   eee->tx_lpi_enabled = eee->eee_enabled;
+   if (eee->advertised & eee->lp_advertised)
+   eee->eee_active = true;
+
+   return 0;
+}
+
+static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   u32 rate, supported_rates;
+   struct aq_nic_cfg_s *cfg;
+   int err = 0;
+
+   cfg = aq_nic_get_cfg(aq_nic);
+
+   if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate ||
+!aq_nic->aq_fw_ops->set_eee_rate))
+   return -EOPNOTSUPP;
+
+   err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, ,
+ _rates);
+   if (err < 0)
+   return err;
+
+   if (eee->eee_enabled) {
+   rate = supported_rates;
+   cfg->eee_speeds = rate;
+   } else {
+   rate = 0;
+   cfg->eee_speeds = 0;
+   }
+
+   return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
+}
+
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -438,6 +513,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
+   .get_eee = aq_ethtool_get_eee,
+   .set_eee = aq_ethtool_set_eee,
.get_pauseparam  = aq_ethtool_get_pauseparam,
.set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 9050b40d4f58..908f19fe19b3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -230,6 +230,11 @@ struct aq_fw_ops {
 
int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
 u8 *mac);
+
+   int

[PATCH net-next v3 1/7] net: aquantia: fix hw_atl_utils_fw_upload_dwords

2018-09-10 Thread Igor Russkikh
From: Yana Esina 

This patch fixes the upload function, which worked incorrectly with
some chips.

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |  8 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  3 ++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 13 
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 36 +++---
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  5 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  5 +++
 6 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 10ba035dadb1..be0a3a90dfad 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -1460,3 +1460,11 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s 
*aq_hw,
aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp),
glb_cpu_scratch_scp);
 }
+
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR,
+   HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK,
+   HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT,
+   up_force_intr);
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index dfb426f2dc2c..7056c7342afc 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -698,4 +698,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, 
u32 reg_wr_strobe);
 /* set pci register reset disable */
 void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 
pci_reg_res_dis);
 
+/* set uP Force Interrupt */
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
+
 #endif /* HW_ATL_LLH_H */
diff --git 
a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
index e0cf70120f1d..716674a9b729 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -2387,4 +2387,17 @@
 #define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \
(0x0300u + (scratch_scp) * 0x4)
 
+/* register address for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR 0x0404
+/* bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK 0x0002
+/* inverted bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSKN 0xFFFD
+/* lower bit position of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT 1
+/* width of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_WIDTH 1
+/* default value of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0
+
 #endif /* HW_ATL_LLH_INTERNAL_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index c965e65d07db..1926532bd1af 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -325,17 +325,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s 
*self, u32 a, u32 *p,
err = -ETIME;
goto err_exit;
}
+   if (IS_CHIP_FEATURE(REVISION_B1)) {
+   u32 offset = 0;
+
+   for (; offset < cnt; ++offset) {
+   aq_hw_write_reg(self, 0x328, p[offset]);
+   aq_hw_write_reg(self, 0x32C,
+   (0x8000 | (0x & (offset * 4;
+   hw_atl_mcp_up_force_intr_set(self, 1);
+   /* 1000 times by 10us = 10ms */
+   AQ_HW_WAIT_FOR((aq_hw_read_reg(self,
+  0x32C) & 0xF000) !=
+  0x8000,
+  10, 1000);
+   }
+   } else {
+   u32 offset = 0;
 
-   aq_hw_write_reg(self, 0x0208U, a);
-
-   for (++cnt; --cnt;) {
-   u32 i = 0U;
+   aq_hw_write_reg(self, 0x208, a);
 
-   aq_hw_write_reg(self, 0x020CU, *(p++));
-   aq_hw_write_reg(self, 0x0200U, 0xC000U);
+   for (; offset < cnt; ++offset) {
+   aq_hw_write_reg(self, 0x20C, p[offset]);
+   aq_hw_write_reg(self,

[PATCH net-next v3 5/7] net: aquantia: whitespace changes

2018-09-10 Thread Igor Russkikh
From: Nikita Danilov 

Removed extra spaces, corrected alignment.

Signed-off-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  4 +--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c| 12 
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   |  4 +--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  | 18 ++--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 14 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 33 +++---
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  1 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 12 
 8 files changed, 49 insertions(+), 49 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 22dd4fbd34d7..6a633c70f603 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -98,8 +98,8 @@ static void aq_ethtool_stats(struct net_device *ndev,
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
 
memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) +
-   ARRAY_SIZE(aq_ethtool_queue_stat_names) *
-   cfg->vecs) * sizeof(u64));
+ARRAY_SIZE(aq_ethtool_queue_stat_names) *
+cfg->vecs) * sizeof(u64));
aq_nic_get_stats(aq_nic, data);
 }
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 9809dbf8c272..5fed24446687 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -189,7 +189,7 @@ static void aq_nic_polling_timer_cb(struct timer_list *t)
aq_vec_isr(i, (void *)aq_vec);
 
mod_timer(>polling_timer, jiffies +
-   AQ_CFG_POLLING_TIMER_INTERVAL);
+ AQ_CFG_POLLING_TIMER_INTERVAL);
 }
 
 int aq_nic_ndev_register(struct aq_nic_s *self)
@@ -301,13 +301,13 @@ int aq_nic_start(struct aq_nic_s *self)
unsigned int i = 0U;
 
err = self->aq_hw_ops->hw_multicast_list_set(self->aq_hw,
-   self->mc_list.ar,
-   self->mc_list.count);
+self->mc_list.ar,
+self->mc_list.count);
if (err < 0)
goto err_exit;
 
err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw,
-  self->packet_filter);
+   self->packet_filter);
if (err < 0)
goto err_exit;
 
@@ -327,7 +327,7 @@ int aq_nic_start(struct aq_nic_s *self)
goto err_exit;
timer_setup(>service_timer, aq_nic_service_timer_cb, 0);
mod_timer(>service_timer, jiffies +
-   AQ_CFG_SERVICE_TIMER_INTERVAL);
+ AQ_CFG_SERVICE_TIMER_INTERVAL);
 
if (self->aq_nic_cfg.is_polling) {
timer_setup(>polling_timer, aq_nic_polling_timer_cb, 0);
@@ -344,7 +344,7 @@ int aq_nic_start(struct aq_nic_s *self)
}
 
err = self->aq_hw_ops->hw_irq_enable(self->aq_hw,
-   AQ_CFG_IRQ_MASK);
+AQ_CFG_IRQ_MASK);
if (err < 0)
goto err_exit;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index b5f1f62e8e25..32111272d7bf 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -29,8 +29,8 @@ static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
goto err_exit;
}
self->dx_ring = dma_alloc_coherent(aq_nic_get_dev(aq_nic),
-   self->size * self->dx_size,
-   >dx_ring_pa, GFP_KERNEL);
+  self->size * self->dx_size,
+  >dx_ring_pa, GFP_KERNEL);
if (!self->dx_ring) {
err = -ENOMEM;
goto err_exit;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 1dd0ef4a895c..d1d5bfda6a5b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -49,9 +49,9 @@
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYP

[PATCH net-next v2 4/7] net: aquantia: implement EEE support

2018-09-06 Thread Igor Russkikh
From: Yana Esina 

Support of Energy-Efficient Ethernet to aQuantia NIC's via ethtool
(according to the IEEE 802.3az specifications)

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |  5 ++
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 77 +++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  5 ++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  1 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  2 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 13 
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 86 ++
 7 files changed, 189 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index d52b088ff8f0..becb578211ed 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -57,4 +57,9 @@
 #define AQ_NIC_RATE_1G BIT(4)
 #define AQ_NIC_RATE_100M   BIT(5)
 
+#define AQ_NIC_RATE_EEE_10GBIT(6)
+#define AQ_NIC_RATE_EEE_5G BIT(7)
+#define AQ_NIC_RATE_EEE_2GSBIT(8)
+#define AQ_NIC_RATE_EEE_1G BIT(9)
+
 #endif /* AQ_COMMON_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index b88be5e5f0a2..22dd4fbd34d7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -315,6 +315,81 @@ static int aq_ethtool_set_wol(struct net_device *ndev,
return err;
 }
 
+static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
+{
+   u32 rate = 0;
+
+   if (speed & AQ_NIC_RATE_EEE_10G)
+   rate |= SUPPORTED_1baseT_Full;
+
+   if (speed & AQ_NIC_RATE_EEE_2GS)
+   rate |= SUPPORTED_2500baseX_Full;
+
+   if (speed & AQ_NIC_RATE_EEE_1G)
+   rate |= SUPPORTED_1000baseT_Full;
+
+   return rate;
+}
+
+static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   u32 rate, supported_rates;
+   int err = 0;
+
+   if (!aq_nic->aq_fw_ops->get_eee_rate)
+   return -EOPNOTSUPP;
+
+   err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, ,
+ _rates);
+   if (err < 0)
+   return err;
+
+   eee->supported = eee_mask_to_ethtool_mask(supported_rates);
+
+   if (aq_nic->aq_nic_cfg.eee_speeds)
+   eee->advertised = eee->supported;
+
+   eee->lp_advertised = eee_mask_to_ethtool_mask(rate);
+
+   eee->eee_enabled = !!eee->advertised;
+
+   eee->tx_lpi_enabled = eee->eee_enabled;
+   if (eee->advertised & eee->lp_advertised)
+   eee->eee_active = true;
+
+   return 0;
+}
+
+static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   u32 rate, supported_rates;
+   struct aq_nic_cfg_s *cfg;
+   int err = 0;
+
+   cfg = aq_nic_get_cfg(aq_nic);
+
+   if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate ||
+!aq_nic->aq_fw_ops->set_eee_rate))
+   return -EOPNOTSUPP;
+
+   err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, ,
+ _rates);
+   if (err < 0)
+   return err;
+
+   if (eee->eee_enabled) {
+   rate = supported_rates;
+   cfg->eee_speeds = rate;
+   } else {
+   rate = 0;
+   cfg->eee_speeds = 0;
+   }
+
+   return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
+}
+
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -438,6 +513,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
+   .get_eee = aq_ethtool_get_eee,
+   .set_eee = aq_ethtool_set_eee,
.get_pauseparam  = aq_ethtool_get_pauseparam,
.set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 9050b40d4f58..908f19fe19b3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -230,6 +230,11 @@ struct aq_fw_ops {
 
int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
 u8 *mac);
+
+   int

[PATCH net-next v2 5/7] net: aquantia: whitespace changes

2018-09-06 Thread Igor Russkikh
From: Nikita Danilov 

Removed extra spaces, corrected alignment.

Signed-off-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  4 +--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c| 12 
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   |  4 +--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  | 18 ++--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 14 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 33 +++---
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  1 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 12 
 8 files changed, 49 insertions(+), 49 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 22dd4fbd34d7..6a633c70f603 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -98,8 +98,8 @@ static void aq_ethtool_stats(struct net_device *ndev,
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
 
memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) +
-   ARRAY_SIZE(aq_ethtool_queue_stat_names) *
-   cfg->vecs) * sizeof(u64));
+ARRAY_SIZE(aq_ethtool_queue_stat_names) *
+cfg->vecs) * sizeof(u64));
aq_nic_get_stats(aq_nic, data);
 }
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 9809dbf8c272..5fed24446687 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -189,7 +189,7 @@ static void aq_nic_polling_timer_cb(struct timer_list *t)
aq_vec_isr(i, (void *)aq_vec);
 
mod_timer(>polling_timer, jiffies +
-   AQ_CFG_POLLING_TIMER_INTERVAL);
+ AQ_CFG_POLLING_TIMER_INTERVAL);
 }
 
 int aq_nic_ndev_register(struct aq_nic_s *self)
@@ -301,13 +301,13 @@ int aq_nic_start(struct aq_nic_s *self)
unsigned int i = 0U;
 
err = self->aq_hw_ops->hw_multicast_list_set(self->aq_hw,
-   self->mc_list.ar,
-   self->mc_list.count);
+self->mc_list.ar,
+self->mc_list.count);
if (err < 0)
goto err_exit;
 
err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw,
-  self->packet_filter);
+   self->packet_filter);
if (err < 0)
goto err_exit;
 
@@ -327,7 +327,7 @@ int aq_nic_start(struct aq_nic_s *self)
goto err_exit;
timer_setup(>service_timer, aq_nic_service_timer_cb, 0);
mod_timer(>service_timer, jiffies +
-   AQ_CFG_SERVICE_TIMER_INTERVAL);
+ AQ_CFG_SERVICE_TIMER_INTERVAL);
 
if (self->aq_nic_cfg.is_polling) {
timer_setup(>polling_timer, aq_nic_polling_timer_cb, 0);
@@ -344,7 +344,7 @@ int aq_nic_start(struct aq_nic_s *self)
}
 
err = self->aq_hw_ops->hw_irq_enable(self->aq_hw,
-   AQ_CFG_IRQ_MASK);
+AQ_CFG_IRQ_MASK);
if (err < 0)
goto err_exit;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index b5f1f62e8e25..32111272d7bf 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -29,8 +29,8 @@ static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
goto err_exit;
}
self->dx_ring = dma_alloc_coherent(aq_nic_get_dev(aq_nic),
-   self->size * self->dx_size,
-   >dx_ring_pa, GFP_KERNEL);
+  self->size * self->dx_size,
+  >dx_ring_pa, GFP_KERNEL);
if (!self->dx_ring) {
err = -ENOMEM;
goto err_exit;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 1dd0ef4a895c..d1d5bfda6a5b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -49,9 +49,9 @@
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYP

[PATCH net-next v2 0/7] net: aquantia: implement WOL and EEE support

2018-09-06 Thread Igor Russkikh
This is v2 of WOL/EEE functionality patch for atlantic driver.
Sorry for long gap, I was on vacation.

In this patchset Yana Esina and Nikita Danilov implemented:

- Upload function to interact with FW memory
- Definitions and structures necessary for the correct operation of Wake ON Lan
- The functionality Wake On Lan via ethtool (Magic packet is supported)
- The functionality for Energy-Efficient Ethernet configuration via ethtool

Version 2 has the following fixes:
- patchset reorganized to extract renaming and whitespace fixes into separate
  patches
- some of magic numbers replaced with defines
- reverse christmas tree applied

Discussion outcome regarding driver version bumps was not finished
(here https://patchwork.ozlabs.org/patch/954905/)
David, could you suggest the best way to proceed on this?

Igor Russkikh (1):
  net: aquantia: bump driver version

Nikita Danilov (2):
  net: aquantia: whitespace changes
  net: aquantia: renaming for better visibility

Yana Esina (4):
  net: aquantia: fix hw_atl_utils_fw_upload_dwords
  net: aquantia: definitions for WOL
  net: aquantia: implement WOL support
  net: aquantia: implement EEE support

 drivers/net/ethernet/aquantia/atlantic/aq_common.h |   5 +
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 113 +-
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  13 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  24 ++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   4 +
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c   |   4 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  41 ++--
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  35 ++--
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |   8 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |   3 +
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h |  13 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 163 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 130 +++-
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 233 -
 drivers/net/ethernet/aquantia/atlantic/ver.h   |   2 +-
 17 files changed, 675 insertions(+), 128 deletions(-)

-- 
2.7.4



[PATCH net-next v2 6/7] net: aquantia: renaming for better visibility

2018-09-06 Thread Igor Russkikh
From: Nikita Danilov 

Removed extra characters from the names of structures to unify prefixes
used through the driver code (we normally use hw_atl for hw specifics).
HW_ATL_B0_ and HW_ATL_A0_ are the same and useless copies.

Signed-off-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  4 +--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  | 32 ++--
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |  6 
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 34 +++---
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |  6 
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 14 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 14 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  6 ++--
 8 files changed, 52 insertions(+), 64 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 908f19fe19b3..e8689241204e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -112,7 +112,7 @@ struct aq_hw_s {
const struct aq_fw_ops *aq_fw_ops;
void __iomem *mmio;
struct aq_hw_link_status_s aq_link_status;
-   struct hw_aq_atl_utils_mbox mbox;
+   struct hw_atl_utils_mbox mbox;
struct hw_atl_stats_s last_stats;
struct aq_stats_s curr_stats;
u64 speed;
@@ -124,7 +124,7 @@ struct aq_hw_s {
u32 mbox_addr;
u32 rpc_addr;
u32 rpc_tid;
-   struct hw_aq_atl_utils_fw_rpc rpc;
+   struct hw_atl_utils_fw_rpc rpc;
 };
 
 struct aq_ring_s;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index d1d5bfda6a5b..2469ed4d86b9 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -49,37 +49,37 @@
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_FIBRE,
-   .link_speed_msk = HW_ATL_A0_RATE_5G |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
-   .link_speed_msk = HW_ATL_A0_RATE_10G |
- HW_ATL_A0_RATE_5G |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_10G |
+ AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
-   .link_speed_msk = HW_ATL_A0_RATE_5G  |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G  |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
-   .link_speed_msk = HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+   .link_speed_msk = AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
 };
 
 static int hw_atl_a0_hw_reset(struct aq_hw_s *self)
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
index 3c94cff57876..a021dc431ef7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
@@ -62,12 +62,6 @@
 #define HW_ATL_A0_MPI_SPEED_MSK   0xU
 #define HW_ATL_A0_MPI_SPEED_SHIFT 16U
 
-#define HW_ATL_A0_RATE_10GBIT(0)
-#define HW_ATL_A0_RATE_5G BIT(1)
-#define HW_ATL_A0_RATE_2G5BIT(3)
-#define HW_ATL_A0_RATE_1G BIT(4)
-#define HW_ATL_A0_RATE_100M   BIT(5)
-
 #define HW_ATL_A0_TXBUF_MAX 160U
 #define HW_ATL_A0_RXBUF_MAX 320U
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 7c8ee103c825

[PATCH net-next v2 7/7] net: aquantia: bump driver version

2018-09-06 Thread Igor Russkikh
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/ver.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h 
b/drivers/net/ethernet/aquantia/atlantic/ver.h
index 94efc6477bdc..b48260114da3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -12,7 +12,7 @@
 
 #define NIC_MAJOR_DRIVER_VERSION   2
 #define NIC_MINOR_DRIVER_VERSION   0
-#define NIC_BUILD_DRIVER_VERSION   3
+#define NIC_BUILD_DRIVER_VERSION   4
 #define NIC_REVISION_DRIVER_VERSION0
 
 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
-- 
2.7.4



[PATCH net-next v2 2/7] net: aquantia: definitions for WOL

2018-09-06 Thread Igor Russkikh
From: Yana Esina 

Added definitions and structures needed to support WOL.

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  3 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 94 --
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 32 
 3 files changed, 124 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index fecfc401f95d..2069cbb6e1a1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -36,6 +36,7 @@ struct aq_nic_cfg_s {
u32 flow_control;
u32 link_speed_msk;
u32 vlan_id;
+   u32 wol;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
@@ -54,6 +55,8 @@ struct aq_nic_cfg_s {
 #define AQ_NIC_FLAG_ERR_UNPLUG  0x4000U
 #define AQ_NIC_FLAG_ERR_HW  0x8000U
 
+#define AQ_NIC_WOL_ENABLED BIT(0)
+
 #define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index 505c8a2abd9c..1fef28719f1d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -101,8 +101,6 @@ struct __packed hw_aq_atl_utils_fw_rpc {
struct {
u32 priority;
u32 wol_packet_type;
-   u16 friendly_name_len;
-   u16 friendly_name[65];
u32 pattern_id;
u32 next_wol_pattern_offset;
 
@@ -134,13 +132,36 @@ struct __packed hw_aq_atl_utils_fw_rpc {
u32 pattern_offset;
u32 pattern_size;
} wol_bit_map_pattern;
+
+   struct {
+   u8 mac_addr[6];
+   } wol_magic_packet_patter;
} wol_pattern;
} msg_wol;
 
struct {
-   u32 is_wake_on_link_down;
-   u32 is_wake_on_link_up;
-   } msg_wolink;
+   union {
+   u32 pattern_mask;
+
+   struct {
+   u32 reason_arp_v4_pkt : 1;
+   u32 reason_ipv4_ping_pkt : 1;
+   u32 reason_ipv6_ns_pkt : 1;
+   u32 reason_ipv6_ping_pkt : 1;
+   u32 reason_link_up : 1;
+   u32 reason_link_down : 1;
+   u32 reason_maximum : 1;
+   };
+   };
+
+   union {
+   u32 offload_mask;
+   };
+   } msg_enable_wakeup;
+
+   struct {
+   u32 id;
+   } msg_del_id;
};
 };
 
@@ -155,6 +176,57 @@ struct __packed hw_aq_atl_utils_mbox {
struct hw_atl_stats_s stats;
 };
 
+/* fw2x */
+typedef u32fw_offset_t;
+
+struct __packed offload_ip_info {
+   u8 v4_local_addr_count;
+   u8 v4_addr_count;
+   u8 v6_local_addr_count;
+   u8 v6_addr_count;
+   fw_offset_t v4_addr;
+   fw_offset_t v4_prefix;
+   fw_offset_t v6_addr;
+   fw_offset_t v6_prefix;
+};
+
+struct __packed offload_port_info {
+   u16 udp_port_count;
+   u16 tcp_port_count;
+   fw_offset_t udp_port;
+   fw_offset_t tcp_port;
+};
+
+struct __packed offload_ka_info {
+   u16 v4_ka_count;
+   u16 v6_ka_count;
+   u32 retry_count;
+   u32 retry_interval;
+   fw_offset_t v4_ka;
+   fw_offset_t v6_ka;
+};
+
+struct __packed offload_rr_info {
+   u32 rr_count;
+   u32 rr_buf_len;
+   fw_offset_t rr_id_x;
+   fw_offset_t rr_buf;
+};
+
+struct __packed offload_info {
+   u32 version;
+   u32 len;
+   u8 mac_addr[6];
+
+   u8 reserved[2];
+
+   struct offload_ip_info ips;
+   struct offload_port_info ports;
+   struct offload_ka_info kas;
+   struct offload_rr_info rrs;
+   u8 buf[0];
+};
+
 #define HAL_ATLANTIC_UTILS_CHIP_MIPS 0x0001U
 #define HAL_ATLANTIC_UTILS_CHIP_TPO2 0x0002U
 #define HAL_ATLANTIC_UTILS_CHIP_RPF2 0x0004U
@@ -181,6 +253,18 @@ enum hal_atl_utils_fw_state_e {
 #define HAL_ATLANTIC_RATE_100M   BIT(5)
 #define HAL_ATLANTIC_RATE_INVALIDBIT(6)
 
+#define HAL_ATLANTIC_UTILS_FW_MSG_PING  0x1U
+#define

[PATCH net-next v2 3/7] net: aquantia: implement WOL support

2018-09-06 Thread Igor Russkikh
From: Yana Esina 

Add WOL support. Currently only magic packet
(ethtool -s  wol g) feature is implemented.

Remove hw_set_power and move that to FW_OPS set_power:
because WOL configuration behaves differently on 1x and 2x
firmwares

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 32 +++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  4 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c| 12 +--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  1 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  1 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 84 +--
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  5 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 98 +-
 8 files changed, 220 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 08c9fa6ca71f..b88be5e5f0a2 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,36 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_ethtool_get_wol(struct net_device *ndev,
+  struct ethtool_wolinfo *wol)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+
+   wol->supported = WAKE_MAGIC;
+   wol->wolopts = 0;
+
+   if (cfg->wol)
+   wol->wolopts |= WAKE_MAGIC;
+}
+
+static int aq_ethtool_set_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+   struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+   int err = 0;
+
+   if (wol->wolopts & WAKE_MAGIC)
+   cfg->wol |= AQ_NIC_WOL_ENABLED;
+   else
+   cfg->wol &= ~AQ_NIC_WOL_ENABLED;
+   err = device_set_wakeup_enable(>dev, wol->wolopts);
+
+   return err;
+}
+
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -403,6 +433,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .get_wol = aq_ethtool_get_wol,
+   .set_wol = aq_ethtool_set_wol,
.nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 5c00671f248d..9050b40d4f58 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -204,7 +204,6 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
-   int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
 };
 
 struct aq_fw_ops {
@@ -228,6 +227,9 @@ struct aq_fw_ops {
int (*update_stats)(struct aq_hw_s *self);
 
int (*set_flow_control)(struct aq_hw_s *self);
+
+   int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
+u8 *mac);
 };
 
 #endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 26dc6782b475..9809dbf8c272 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -889,11 +889,13 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec);
 
-   if (self->power_state == AQ_HW_POWER_STATE_D0) {
-   (void)self->aq_fw_ops->deinit(self->aq_hw);
-   } else {
-   (void)self->aq_hw_ops->hw_set_power(self->aq_hw,
-  self->power_state);
+   self->aq_fw_ops->deinit(self->aq_hw);
+
+   if (self->power_state != AQ_HW_POWER_STATE_D0 ||
+   self->aq_hw->aq_nic_cfg->wol) {
+   self->aq_fw_ops->set_power(self->aq_hw,
+  self->power_state,
+  self->ndev->dev_addr);
}
 
 err_exit:;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 97addfa6f895..1dd0ef4a895c 100644
--- a/drivers/n

[PATCH net-next v2 1/7] net: aquantia: fix hw_atl_utils_fw_upload_dwords

2018-09-06 Thread Igor Russkikh
From: Yana Esina 

This patch fixes the upload function, which worked incorrectly with
some chips.

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |  8 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  3 ++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 13 
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 36 +++---
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  5 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  5 +++
 6 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 10ba035dadb1..be0a3a90dfad 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -1460,3 +1460,11 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s 
*aq_hw,
aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp),
glb_cpu_scratch_scp);
 }
+
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR,
+   HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK,
+   HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT,
+   up_force_intr);
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index dfb426f2dc2c..7056c7342afc 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -698,4 +698,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, 
u32 reg_wr_strobe);
 /* set pci register reset disable */
 void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 
pci_reg_res_dis);
 
+/* set uP Force Interrupt */
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
+
 #endif /* HW_ATL_LLH_H */
diff --git 
a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
index e0cf70120f1d..716674a9b729 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -2387,4 +2387,17 @@
 #define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \
(0x0300u + (scratch_scp) * 0x4)
 
+/* register address for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR 0x0404
+/* bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK 0x0002
+/* inverted bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSKN 0xFFFD
+/* lower bit position of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT 1
+/* width of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_WIDTH 1
+/* default value of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0
+
 #endif /* HW_ATL_LLH_INTERNAL_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index c965e65d07db..1926532bd1af 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -325,17 +325,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s 
*self, u32 a, u32 *p,
err = -ETIME;
goto err_exit;
}
+   if (IS_CHIP_FEATURE(REVISION_B1)) {
+   u32 offset = 0;
+
+   for (; offset < cnt; ++offset) {
+   aq_hw_write_reg(self, 0x328, p[offset]);
+   aq_hw_write_reg(self, 0x32C,
+   (0x8000 | (0x & (offset * 4;
+   hw_atl_mcp_up_force_intr_set(self, 1);
+   /* 1000 times by 10us = 10ms */
+   AQ_HW_WAIT_FOR((aq_hw_read_reg(self,
+  0x32C) & 0xF000) !=
+  0x8000,
+  10, 1000);
+   }
+   } else {
+   u32 offset = 0;
 
-   aq_hw_write_reg(self, 0x0208U, a);
-
-   for (++cnt; --cnt;) {
-   u32 i = 0U;
+   aq_hw_write_reg(self, 0x208, a);
 
-   aq_hw_write_reg(self, 0x020CU, *(p++));
-   aq_hw_write_reg(self, 0x0200U, 0xC000U);
+   for (; offset < cnt; ++offset) {
+   aq_hw_write_reg(self, 0x20C, p[offset]);
+   aq_hw_write_reg(self,

Re: [PATCH net-next 5/5] net: aquantia: bump driver version

2018-08-12 Thread Igor Russkikh



>> Hope the above are good enough arguments to keep up version bumps.
> 
> A reasonably successful strategy is to version your out-of-tree driver
> with corresponding kernel release versions.  Flip the equation.
> 
> E.g. current net-next will become 4.19, so all the features you're
> pushing now would in your GH repo be:
> 
> 4.19.0.${extra_numbers_if_you_want}-gh
> 
> And you still have single versioning scheme, but the "bump to version
> XYZ" commits now go into your local tree not the kernel.
> 
> As Andrew said backports make driver versions less than useful.  Not
> only feature backports to enterprise kernel, but bug fixes which have to
> go to stable.
> 

Technically yes, thats a good and manageable suggestion.

However the problem here is a human factor.

Regular users are often aware that NIC drivers are regularly
get updates, fixes etc. And they logically assume there is a
driver version in there. And what user normally does first
time he/she buys new NIC is checking driver version in system.

Obviously what user use is `ethtool -i` since thats a documented and
the only user visible tool.

What we'll get here is totally uncorrelated versioning info between inkernel
driver (some ancient version or no version at all) and vendor driver.

This will confuse user as he/she will start thinking (for example) that his
in kernel driver is "bad" and has to be updated.

Another human factor is tech support personnel, who also expect NIC drivers
to have version. We'll get tons of requests sort of "why and when you'll update
your upstream driver". It is up to date. "But why its version is not updated 
then?"

A lot of technical reports from fields does not include kernel version, but
(since users talk about NIC) just an "ethtool -i" output. This'll confuse us
as we have to do more queries on kernel version.

These are all legitimate expectations from non-tech people and what we trying
to do now is to keep up inkernel versioning with our local versioning.

Thus, user now sees:

version: 2.0.3.0-kern (for inkernel driver)
or
version: 2.0.6.0 (for external driver)

and can at least judge whether he needs updates or if thats OK.

As a one liner sumup:
kernel have user visible 'ethtool -i' API. Why should we drop it and deprecate 
it?

BR, Igor


Re: [PATCH net-next 5/5] net: aquantia: bump driver version

2018-08-09 Thread Igor Russkikh
Hi Andrew,

Thanks for the review, agreed on all your findings,
we'll address these comments in next version.

> Driver versions are pretty much useless. Say somebody backports this
> driver into a vendor kernel. Vendor kernels are typically based on an
> old kernel, plus thousands of patches. Is 2.0.4 on such a kernel the
> same as 2.0.4 in 4.19?
> 
> You probably want to remove this, just the avoid people thinking is
> means something.

We do distribute our driver as a separate source package, customers for older
kernels use it and install without updating their kernels.

We also in fact always have a gap in featureset between upstream driver and our
preview driver releases on github - alot of people tend to tryout 'hot and 
latest' driver
instead of waiting for their distro kernel to receive updates.

All this means we have to understand which version (and featureset) users have 
installed in fields.

`ethtool -i` and this internal driver version is a huge helper for us.

You are right that in event of backporting there could be some uncertainty 
whether that bugfix is there or not.
But having kernel version plus driver version really helps us to understand the 
exact configuration in fields.

Moreover, inkernel driver version bumps are linked with new features added 
(like in this patchset).
Thus the overall concept of internal version is still very useful for Aquantia 
technical and support engineers.

Hope the above are good enough arguments to keep up version bumps.

BR, Igor


[PATCH net] net: aquantia: Fix IFF_ALLMULTI flag functionality

2018-08-08 Thread Igor Russkikh
From: Dmitry Bogdanov 

It was noticed that NIC always pass all multicast traffic to the host
regardless of IFF_ALLMULTI flag on the interface.
The rule in MC Filter Table in NIC, that is configured to accept any
multicast packets, is turning on if IFF_MULTICAST flag is set on the
interface. It leads to passing all multicast traffic to the host.
This fix changes the condition to turn on that rule by checking
IFF_ALLMULTI flag as it should.

Fixes: b21f502 ("net:ethernet:aquantia: Fix for multicast filter handling.")
Signed-off-by: Dmitry Bogdanov 
---
 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 956860a69797..3bdab972420b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -762,7 +762,7 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s 
*self,
 
hw_atl_rpfl2promiscuous_mode_en_set(self, 
IS_FILTER_ENABLED(IFF_PROMISC));
hw_atl_rpfl2multicast_flr_en_set(self,
-IS_FILTER_ENABLED(IFF_MULTICAST), 0);
+IS_FILTER_ENABLED(IFF_ALLMULTI), 0);
 
hw_atl_rpfl2_accept_all_mc_packets_set(self,
   IS_FILTER_ENABLED(IFF_ALLMULTI));
-- 
2.17.1



[PATCH net-next 2/5] net: aquantia: definitions for WOL patch

2018-08-08 Thread Igor Russkikh
From: Yana Esina 

Added definitions and structures needed to support WOL.

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |   4 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   3 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  10 +-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 108 ++---
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  32 ++
 5 files changed, 138 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 5c00671..6fa7936 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -112,7 +112,7 @@ struct aq_hw_s {
const struct aq_fw_ops *aq_fw_ops;
void __iomem *mmio;
struct aq_hw_link_status_s aq_link_status;
-   struct hw_aq_atl_utils_mbox mbox;
+   struct hw_atl_utils_mbox mbox;
struct hw_atl_stats_s last_stats;
struct aq_stats_s curr_stats;
u64 speed;
@@ -124,7 +124,7 @@ struct aq_hw_s {
u32 mbox_addr;
u32 rpc_addr;
u32 rpc_tid;
-   struct hw_aq_atl_utils_fw_rpc rpc;
+   struct hw_atl_utils_fw_rpc rpc;
 };
 
 struct aq_ring_s;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index fecfc40..2069cbb 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -36,6 +36,7 @@ struct aq_nic_cfg_s {
u32 flow_control;
u32 link_speed_msk;
u32 vlan_id;
+   u32 wol;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
@@ -54,6 +55,8 @@ struct aq_nic_cfg_s {
 #define AQ_NIC_FLAG_ERR_UNPLUG  0x4000U
 #define AQ_NIC_FLAG_ERR_HW  0x8000U
 
+#define AQ_NIC_WOL_ENABLED BIT(0)
+
 #define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index b0aaf6f..f9c4475 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -438,7 +438,7 @@ int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned 
int rpc_size)
 }
 
 int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
-struct hw_aq_atl_utils_fw_rpc **rpc)
+struct hw_atl_utils_fw_rpc **rpc)
 {
int err = 0;
struct aq_hw_atl_utils_fw_rpc_tid_s sw;
@@ -503,7 +503,7 @@ static int hw_atl_utils_mpi_create(struct aq_hw_s *self)
 }
 
 int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
-  struct hw_aq_atl_utils_mbox_header *pmbox)
+  struct hw_atl_utils_mbox_header *pmbox)
 {
return hw_atl_utils_fw_downld_dwords(self,
  self->mbox_addr,
@@ -512,7 +512,7 @@ int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
 }
 
 void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
-struct hw_aq_atl_utils_mbox *pmbox)
+struct hw_atl_utils_mbox *pmbox)
 {
int err = 0;
 
@@ -552,7 +552,7 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
 {
int err = 0;
u32 transaction_id = 0;
-   struct hw_aq_atl_utils_mbox_header mbox;
+   struct hw_atl_utils_mbox_header mbox;
u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
 
if (state == MPI_RESET) {
@@ -754,7 +754,7 @@ int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
 
 int hw_atl_utils_update_stats(struct aq_hw_s *self)
 {
-   struct hw_aq_atl_utils_mbox mbox;
+   struct hw_atl_utils_mbox mbox;
 
hw_atl_utils_mpi_read_stats(self, );
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index aedb911..24f0947 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -75,7 +75,7 @@ union __packed ip_addr {
} v4;
 };
 
-struct __packed hw_aq_atl_utils_fw_rpc {
+struct __packed hw_atl_utils_fw_rpc {
u32 msg_id;
 
union {
@@ -101,8 +101,6 @@ struct __packed hw_aq_atl_utils_fw_rpc {
struct {
u32 priority;
u32 wol_packet_type;
-   u16 friendly_name_len;
-   u16 friendly_name[65];
u32 pattern_id;
u32 next_wol_pattern_offset;
 
@@ -134,27 +132,101 @@ struct __packed hw_aq_atl_utils_fw_rpc {

[PATCH net-next 5/5] net: aquantia: bump driver version

2018-08-08 Thread Igor Russkikh
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/ver.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h 
b/drivers/net/ethernet/aquantia/atlantic/ver.h
index 94efc64..b482601 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -12,7 +12,7 @@
 
 #define NIC_MAJOR_DRIVER_VERSION   2
 #define NIC_MINOR_DRIVER_VERSION   0
-#define NIC_BUILD_DRIVER_VERSION   3
+#define NIC_BUILD_DRIVER_VERSION   4
 #define NIC_REVISION_DRIVER_VERSION0
 
 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
-- 
2.7.4



[PATCH net-next 4/5] net: aquantia: implement EEE support

2018-08-08 Thread Igor Russkikh
From: Yana Esina 

Support of Energy-Efficient Ethernet to aQuantia NIC's via ethtool
(according to the IEEE 802.3az specifications)

We do replace some duplicate speed bits definitions here (HW_ATL_B0_RATE_)
with driver generic constants (AQ_NIC_RATE_)

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_common.h |   5 +
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c|  76 +++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |   4 +
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   1 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  32 ++---
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  34 ++---
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   6 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|   2 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  13 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 141 +
 11 files changed, 250 insertions(+), 70 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index d52b088..becb578 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -57,4 +57,9 @@
 #define AQ_NIC_RATE_1G BIT(4)
 #define AQ_NIC_RATE_100M   BIT(5)
 
+#define AQ_NIC_RATE_EEE_10GBIT(6)
+#define AQ_NIC_RATE_EEE_5G BIT(7)
+#define AQ_NIC_RATE_EEE_2GSBIT(8)
+#define AQ_NIC_RATE_EEE_1G BIT(9)
+
 #endif /* AQ_COMMON_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index f9fe49b..ec12edf 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -315,6 +315,80 @@ static int aq_ethtool_set_wol(struct net_device *ndev,
return err;
 }
 
+static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
+{
+   u32 rate = 0;
+
+   if (speed & AQ_NIC_RATE_EEE_10G)
+   rate |= SUPPORTED_1baseT_Full;
+
+   if (speed & AQ_NIC_RATE_EEE_2GS)
+   rate |= SUPPORTED_2500baseX_Full;
+
+   if (speed & AQ_NIC_RATE_EEE_1G)
+   rate |= SUPPORTED_1000baseT_Full;
+
+   return rate;
+}
+
+static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   int err = 0;
+
+   u32 rate, supported_rates;
+
+   if (!aq_nic->aq_fw_ops->get_eee_rate)
+   return -EOPNOTSUPP;
+
+   err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, ,
+ _rates);
+   if (err < 0)
+   return err;
+
+   eee->supported = eee_mask_to_ethtool_mask(supported_rates);
+
+   if (aq_nic->aq_nic_cfg.eee_speeds)
+   eee->advertised = eee->supported;
+
+   eee->lp_advertised = eee_mask_to_ethtool_mask(rate);
+
+   eee->eee_enabled = !!eee->advertised;
+
+   eee->tx_lpi_enabled = eee->eee_enabled;
+   if (eee->advertised & eee->lp_advertised)
+   eee->eee_active = true;
+
+   return 0;
+}
+
+static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+   u32 rate, supported_rates;
+   int err = 0;
+
+   if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate ||
+!aq_nic->aq_fw_ops->set_eee_rate))
+   return -EOPNOTSUPP;
+
+   err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, ,
+ _rates);
+   if (err < 0)
+   return err;
+
+   if (eee->eee_enabled) {
+   rate = supported_rates;
+   cfg->eee_speeds = rate;
+   } else {
+   rate = 0;
+   cfg->eee_speeds = 0;
+   }
+
+   return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
+}
+
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -438,6 +512,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
+   .get_eee = aq_ethtool_get_eee,
+   .set_eee = aq_ethtool_set_eee,
.get_pauseparam  = aq_ethtool_get_pauseparam,
.set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlant

[PATCH net-next 3/5] net: aquantia: implement WOL support

2018-08-08 Thread Igor Russkikh
From: Yana Esina 

Add WOL support. Currently only magic packet
(ethtool -s  wol g) feature is implemented.

Remove hw_set_power and move that to FW_OPS set_power:
because WOL configuration behaves differently on 1x and 2x
firmwares

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 32 +++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  5 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c| 12 +--
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  1 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  1 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 80 +++--
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  2 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 99 +-
 8 files changed, 215 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 08c9fa6..f9fe49b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,36 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_ethtool_get_wol(struct net_device *ndev,
+  struct ethtool_wolinfo *wol)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+
+   wol->supported = WAKE_MAGIC;
+   wol->wolopts = 0;
+
+   if (cfg->wol)
+   wol->wolopts |= WAKE_MAGIC;
+}
+
+static int aq_ethtool_set_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+   struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
+   int err = 0;
+
+   if (wol->wolopts & WAKE_MAGIC)
+   cfg->wol |= AQ_NIC_WOL_ENABLED;
+   else
+   cfg->wol &= ~AQ_NIC_WOL_ENABLED;
+   err = device_set_wakeup_enable(>dev, wol->wolopts);
+
+   return err;
+}
+
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -403,6 +433,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .get_wol = aq_ethtool_get_wol,
+   .set_wol = aq_ethtool_set_wol,
.nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 6fa7936..403d86ea 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -204,7 +204,6 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
-   int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
 };
 
 struct aq_fw_ops {
@@ -228,6 +227,10 @@ struct aq_fw_ops {
int (*update_stats)(struct aq_hw_s *self);
 
int (*set_flow_control)(struct aq_hw_s *self);
+
+   int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
+u8 *mac);
+
 };
 
 #endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 26dc678..439ae61 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -889,11 +889,13 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec);
 
-   if (self->power_state == AQ_HW_POWER_STATE_D0) {
-   (void)self->aq_fw_ops->deinit(self->aq_hw);
-   } else {
-   (void)self->aq_hw_ops->hw_set_power(self->aq_hw,
-  self->power_state);
+   (void)self->aq_fw_ops->deinit(self->aq_hw);
+
+   if (self->power_state != AQ_HW_POWER_STATE_D0 ||
+   self->aq_hw->aq_nic_cfg->wol) {
+   (void)self->aq_fw_ops->set_power(self->aq_hw,
+self->power_state,
+self->ndev->dev_addr);
}
 
 err_exit:;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 97addfa6..1dd0ef4 100644
--- a/drivers/net/ethernet/

[PATCH net-next 0/5] net: aquantia: implement WOL and EEE support

2018-08-08 Thread Igor Russkikh
In this patchset Yana Esina and Nikita Danilov implemented:

- Upload function to interact with FW memory
- Definitions and structures necessary for the correct operation of Wake ON Lan
- The functionality Wake On Lan via ethtool (Magic packet is supported)
- The functionality for Energy-Efficient Ethernet configuration via ethtool

Igor Russkikh (1):
  net: aquantia: bump driver version

Yana Esina (4):
  net: aquantia: fix hw_atl_utils_fw_upload_dwords
  net: aquantia: definitions for WOL patch
  net: aquantia: implement WOL support
  net: aquantia: implement EEE support

 drivers/net/ethernet/aquantia/atlantic/aq_common.h |   5 +
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 108 
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  13 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  12 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   4 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  33 ++-
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  35 ++-
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   6 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |   7 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |   3 +
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h |  13 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 134 --
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 127 +-
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 277 +++--
 drivers/net/ethernet/aquantia/atlantic/ver.h   |   2 +-
 16 files changed, 665 insertions(+), 120 deletions(-)

-- 
2.7.4



[PATCH net-next 1/5] net: aquantia: fix hw_atl_utils_fw_upload_dwords

2018-08-08 Thread Igor Russkikh
From: Yana Esina 

This patch fixes the upload function, which worked incorrectly with
some chips.

Signed-off-by: Yana Esina 
Signed-off-by: Nikita Danilov 
Tested-by: Nikita Danilov 
Signed-off-by: Igor Russkikh 
---
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |  7 
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  3 ++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 13 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 44 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  6 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  7 +++-
 6 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 10ba035..d0a6ea7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -1460,3 +1460,10 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s 
*aq_hw,
aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp),
glb_cpu_scratch_scp);
 }
+
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr)
+{
+   aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR,
+   HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK,
+   HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT, up_force_intr);
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index dfb426f..7056c73 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -698,4 +698,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, 
u32 reg_wr_strobe);
 /* set pci register reset disable */
 void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 
pci_reg_res_dis);
 
+/* set uP Force Interrupt */
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
+
 #endif /* HW_ATL_LLH_H */
diff --git 
a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
index e0cf701..716674a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -2387,4 +2387,17 @@
 #define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \
(0x0300u + (scratch_scp) * 0x4)
 
+/* register address for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR 0x0404
+/* bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK 0x0002
+/* inverted bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSKN 0xFFFD
+/* lower bit position of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT 1
+/* width of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_WIDTH 1
+/* default value of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0
+
 #endif /* HW_ATL_LLH_INTERNAL_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index c965e65..b0aaf6f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -325,17 +325,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s 
*self, u32 a, u32 *p,
err = -ETIME;
goto err_exit;
}
+   if (IS_CHIP_FEATURE(REVISION_B1)) {
+   u32 offset = 0;
+
+   for (; offset < cnt; ++offset) {
+   aq_hw_write_reg(self, 0x328, p[offset]);
+   aq_hw_write_reg(self, 0x32C,
+   (0x8000 | (0x & (offset * 4;
+   hw_atl_mcp_up_force_intr_set(self, 1);
+   /* 1000 times by 10us = 10ms */
+   AQ_HW_WAIT_FOR((aq_hw_read_reg(self,
+  0x32C) & 0xF000) !=
+  0x8000,
+  10, 1000);
+   }
+   } else {
+   u32 offset = 0;
 
-   aq_hw_write_reg(self, 0x0208U, a);
-
-   for (++cnt; --cnt;) {
-   u32 i = 0U;
+   aq_hw_write_reg(self, 0x208, a);
 
-   aq_hw_write_reg(self, 0x020CU, *(p++));
-   aq_hw_write_reg(self, 0x0200U, 0xC000U);
+   for (; offset < cnt; ++offset) {
+   aq_hw_write_reg(self, 0x20C, p[offset]);
+   aq_hw_write_reg(self, 0x200, 0xC000);
 
-   for (i = 1024U;
-   (0x100U &a

[PATCH net] net: aquantia: vlan unicast address list correct handling

2018-07-05 Thread Igor Russkikh
Setting up macvlan/macvtap networks over atlantic NIC results
in no traffic over these networks because ndo_set_rx_mode did
not listed UC MACs as registered in unicast filter.

Here we fix that taking into account maximum number of UC
filters supported by hardware. If more than MAX addresses were
registered, we just enable promisc  and/or allmulti to pass
the traffic in.

We also remove MULTICAST_ADDRESS_MAX constant from aq_cfg since
thats not a configurable parameter at all.

Fixes: b21f502 ("net:ethernet:aquantia: Fix for multicast filter handling.")
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_cfg.h|  2 -
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  4 +-
 drivers/net/ethernet/aquantia/atlantic/aq_main.c   | 11 +
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c| 47 +-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  2 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  2 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  4 +-
 7 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
index fc73831..91eb891 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
@@ -63,8 +63,6 @@
 
 #define AQ_CFG_NAPI_WEIGHT 64U
 
-#define AQ_CFG_MULTICAST_ADDRESS_MAX 32U
-
 /*#define AQ_CFG_MAC_ADDR_PERMANENT {0x30, 0x0E, 0xE3, 0x12, 0x34, 0x56}*/
 
 #define AQ_NIC_FC_OFF0U
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index a2d416b..2c6ebd9 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -98,6 +98,8 @@ struct aq_stats_s {
 #define AQ_HW_MEDIA_TYPE_TP1U
 #define AQ_HW_MEDIA_TYPE_FIBRE 2U
 
+#define AQ_HW_MULTICAST_ADDRESS_MAX 32U
+
 struct aq_hw_s {
atomic_t flags;
u8 rbl_enabled:1;
@@ -177,7 +179,7 @@ struct aq_hw_ops {
unsigned int packet_filter);
 
int (*hw_multicast_list_set)(struct aq_hw_s *self,
-u8 ar_mac[AQ_CFG_MULTICAST_ADDRESS_MAX]
+u8 ar_mac[AQ_HW_MULTICAST_ADDRESS_MAX]
 [ETH_ALEN],
 u32 count);
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
index ba5fe8c..e3ae29e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
@@ -135,17 +135,10 @@ static int aq_ndev_set_mac_address(struct net_device 
*ndev, void *addr)
 static void aq_ndev_set_multicast_settings(struct net_device *ndev)
 {
struct aq_nic_s *aq_nic = netdev_priv(ndev);
-   int err = 0;
 
-   err = aq_nic_set_packet_filter(aq_nic, ndev->flags);
-   if (err < 0)
-   return;
+   aq_nic_set_packet_filter(aq_nic, ndev->flags);
 
-   if (netdev_mc_count(ndev)) {
-   err = aq_nic_set_multicast_list(aq_nic, ndev);
-   if (err < 0)
-   return;
-   }
+   aq_nic_set_multicast_list(aq_nic, ndev);
 }
 
 static const struct net_device_ops aq_ndev_ops = {
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 1a1a638..7a22d02 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -563,34 +563,41 @@ int aq_nic_set_packet_filter(struct aq_nic_s *self, 
unsigned int flags)
 
 int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
 {
+   unsigned int packet_filter = self->packet_filter;
struct netdev_hw_addr *ha = NULL;
unsigned int i = 0U;
 
-   self->mc_list.count = 0U;
-
-   netdev_for_each_mc_addr(ha, ndev) {
-   ether_addr_copy(self->mc_list.ar[i++], ha->addr);
-   ++self->mc_list.count;
+   self->mc_list.count = 0;
+   if (netdev_uc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
+   packet_filter |= IFF_PROMISC;
+   } else {
+   netdev_for_each_uc_addr(ha, ndev) {
+   ether_addr_copy(self->mc_list.ar[i++], ha->addr);
 
-   if (i >= AQ_CFG_MULTICAST_ADDRESS_MAX)
-   break;
+   if (i >= AQ_HW_MULTICAST_ADDRESS_MAX)
+   break;
+   }
}
 
-   if (i >= AQ_CFG_MULTICAST_ADDRESS_MAX) {
-   /* Number of filters is too big: atlantic does not support this.
-* Force all multi filter to support this.
-* With this we disable all UC filters and setup "all pass"
-* mu

[PATCH net-next v3 5/5] net: aquantia: bump driver version

2018-07-02 Thread Igor Russkikh
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/ver.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h 
b/drivers/net/ethernet/aquantia/atlantic/ver.h
index a445de6..94efc64 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -12,8 +12,8 @@
 
 #define NIC_MAJOR_DRIVER_VERSION   2
 #define NIC_MINOR_DRIVER_VERSION   0
-#define NIC_BUILD_DRIVER_VERSION   2
-#define NIC_REVISION_DRIVER_VERSION1
+#define NIC_BUILD_DRIVER_VERSION   3
+#define NIC_REVISION_DRIVER_VERSION0
 
 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
 
-- 
2.7.4



[PATCH net-next v3 3/5] net: aquantia: Implement rx/tx flow control ethtools callback

2018-07-02 Thread Igor Russkikh
Runtime change of pause frame configuration (rx/tx flow control)
via ethtool.

Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 42 ++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  6 +++-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  1 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 26 ++
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 0624215..37f8460 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,46 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_ethtool_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   pause->autoneg = 0;
+
+   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
+   pause->rx_pause = 1;
+   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
+   pause->tx_pause = 1;
+}
+
+static int aq_ethtool_set_pauseparam(struct net_device *ndev,
+struct ethtool_pauseparam *pause)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   int err = 0;
+
+   if (!aq_nic->aq_fw_ops->set_flow_control)
+   return -EOPNOTSUPP;
+
+   if (pause->autoneg == AUTONEG_ENABLE)
+   return -EOPNOTSUPP;
+
+   if (pause->rx_pause)
+   aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX;
+   else
+   aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX;
+
+   if (pause->tx_pause)
+   aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX;
+   else
+   aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
+
+   err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
+
+   return err;
+}
+
 static void aq_get_ringparam(struct net_device *ndev,
 struct ethtool_ringparam *ring)
 {
@@ -352,6 +392,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
+   .get_pauseparam  = aq_ethtool_get_pauseparam,
+   .set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index e8cf93a..21cfb32 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -761,10 +761,14 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 100baseT_Full);
 
-   if (self->aq_nic_cfg.flow_control)
+   if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 Pause);
 
+   if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX)
+   ethtool_link_ksettings_add_link_mode(cmd, advertising,
+Asym_Pause);
+
if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
else
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index 9d0a96d..e1feba5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -834,4 +834,5 @@ const struct aq_fw_ops aq_fw_1x_ops = {
.set_state = hw_atl_utils_mpi_set_state,
.update_link_status = hw_atl_utils_mpi_get_link_status,
.update_stats = hw_atl_utils_update_stats,
+   .set_flow_control = NULL,
 };
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index a3e95f0..c1b671e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -87,6 +87,19 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 
speed)
return 0;
 }
 
+static void a

[PATCH net-next v3 2/5] net: aquantia: Improve adapter init/deinit logic

2018-07-02 Thread Igor Russkikh
We now pass link drop status to FW on init/deinit. This is required
to inform FW that driver took/released a control on link.
FW then will manage its own state and device power profile based
on this information. To improve management we remove mpi_set
function which ambiguously took both state and speed parameters.

Deinit callback is now a part of FW ops, as it actually manages the FW.

Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 ++--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  2 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  1 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  1 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 53 --
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 31 -
 6 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 904cdfd..3aa36d5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -202,25 +202,28 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
-   int (*hw_deinit)(struct aq_hw_s *self);
-
int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
 };
 
 struct aq_fw_ops {
int (*init)(struct aq_hw_s *self);
 
+   int (*deinit)(struct aq_hw_s *self);
+
int (*reset)(struct aq_hw_s *self);
 
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
 
int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
 
-   int (*set_state)(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e 
state);
+   int (*set_state)(struct aq_hw_s *self,
+enum hal_atl_utils_fw_state_e state);
 
int (*update_link_status)(struct aq_hw_s *self);
 
int (*update_stats)(struct aq_hw_s *self);
+
+   int (*set_flow_control)(struct aq_hw_s *self);
 };
 
 #endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index ba6bbcf..e8cf93a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -879,7 +879,7 @@ void aq_nic_deinit(struct aq_nic_s *self)
aq_vec_deinit(aq_vec);
 
if (self->power_state == AQ_HW_POWER_STATE_D0) {
-   (void)self->aq_hw_ops->hw_deinit(self->aq_hw);
+   (void)self->aq_fw_ops->deinit(self->aq_hw);
} else {
(void)self->aq_hw_ops->hw_set_power(self->aq_hw,
   self->power_state);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 7fd6a7e..ed7fe6f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -877,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self,
 const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_set_mac_address   = hw_atl_a0_hw_mac_addr_set,
.hw_init  = hw_atl_a0_hw_init,
-   .hw_deinit= hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_a0_hw_reset,
.hw_start = hw_atl_a0_hw_start,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 4ea15b9..9dd4f49 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -935,7 +935,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self,
 const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_set_mac_address   = hw_atl_b0_hw_mac_addr_set,
.hw_init  = hw_atl_b0_hw_init,
-   .hw_deinit= hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_b0_hw_reset,
.hw_start = hw_atl_b0_hw_start,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index e652d86..9d0a96d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -30,10 +30,11 @@
 #define HW_ATL_MPI_CONTROL_ADR  0x0368U
 #define HW_ATL_MPI_STATE_ADR0x036CU
 
-#define HW_ATL_MPI_STATE_MSK0x00FFU
-#define HW_ATL_MPI_STATE_SHIFT  0U
-#define HW_ATL_MPI_SPEED_MSK0xU
-#define HW_ATL_MPI_SPEED_SHIFT  16U
+#define HW_ATL_MPI_STATE_MSK  0x00FFU
+#define HW_ATL_MPI_STATE_SHIFT0U
+#define HW_ATL_MPI_SPEED_MSK  0x00FFU
+#define HW_ATL_MPI_SPEED_SHIFT16U
+#define HW_A

[PATCH net-next v3 1/5] net: aquantia: Ethtool based ring size configuration

2018-07-02 Thread Igor Russkikh
From: Anton Mikaev 

Implemented ring size setup, min/max validation and reconfiguration in
runtime.

Signed-off-by: Anton Mikaev 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 61 ++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  4 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  | 46 
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |  8 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 50 +-
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |  8 +++
 7 files changed, 136 insertions(+), 50 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index f2d8063..0624215 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -11,6 +11,7 @@
 
 #include "aq_ethtool.h"
 #include "aq_nic.h"
+#include "aq_vec.h"
 
 static void aq_ethtool_get_regs(struct net_device *ndev,
struct ethtool_regs *regs, void *p)
@@ -284,6 +285,64 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_get_ringparam(struct net_device *ndev,
+struct ethtool_ringparam *ring)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
+
+   ring->rx_pending = aq_nic_cfg->rxds;
+   ring->tx_pending = aq_nic_cfg->txds;
+
+   ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max;
+   ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max;
+}
+
+static int aq_set_ringparam(struct net_device *ndev,
+   struct ethtool_ringparam *ring)
+{
+   int err = 0;
+   bool ndev_running = false;
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
+   const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps;
+
+   if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
+   err = -EOPNOTSUPP;
+   goto err_exit;
+   }
+
+   if (netif_running(ndev)) {
+   ndev_running = true;
+   dev_close(ndev);
+   }
+
+   aq_nic_free_vectors(aq_nic);
+
+   aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
+   aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max);
+   aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE);
+
+   aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min);
+   aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max);
+   aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE);
+
+   for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs;
+aq_nic->aq_vecs++) {
+   aq_nic->aq_vec[aq_nic->aq_vecs] =
+   aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg);
+   if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) {
+   err = -ENOMEM;
+   goto err_exit;
+   }
+   }
+   if (ndev_running)
+   err = dev_open(ndev);
+
+err_exit:
+   return err;
+}
+
 const struct ethtool_ops aq_ethtool_ops = {
.get_link= aq_ethtool_get_link,
.get_regs_len= aq_ethtool_get_regs_len,
@@ -291,6 +350,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .get_ringparam   = aq_get_ringparam,
+   .set_ringparam   = aq_set_ringparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index a2d416b..904cdfd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -24,8 +24,10 @@ struct aq_hw_caps_s {
u64 link_speed_msk;
unsigned int hw_priv_flags;
u32 media_type;
-   u32 rxds;
-   u32 txds;
+   u32 rxds_max;
+   u32 txds_max;
+   u32 rxds_min;
+   u32 txds_min;
u32 txhwb_alignment;
u32 irq_mask;
u32 vecs;
@@ -98,6 +100,9 @@ struct aq_stats_s {
 #define AQ_HW_MEDIA_TYPE_TP1U
 #define AQ_HW_MEDIA_TYPE_FIBRE 2U
 
+#define AQ_HW_TXD_MULTIPLE 8U
+#define AQ_HW_RXD_MULTIPLE 8U
+
 struct aq_hw_s {
atomic_t flags;
u8 rbl_enabled:1;
diff --g

[PATCH net-next v3 0/5] net: aquantia: various ethtool ops implementation

2018-07-02 Thread Igor Russkikh
In this patchset Anton Mikaev and I added some useful ethtool operations:
- ring size changes
- link renegotioation
- flow control management

The patch also improves init/deinit sequence.

V3 changes:
- After review and analysis it is clear that rtnl lock (which is 
  captured by default on ethtool ops) is enough to secure possible
  overlapping of dev open/close. Thus, just dropping internal mutex.

V2 changes:
- using mutex to secure simultaneous dev close/open
- using state var to store/restore dev state

Igor Russkikh (5):
  net: aquantia: Ethtool based ring size configuration
  net: aquantia: Improve adapter init/deinit logic
  net: aquantia: Implement rx/tx flow control ethtools callback
  net: aquantia: Add renegotiate ethtool operation support
  net: aquantia: bump driver version

 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 117 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  20 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  12 ++-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  47 +
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   8 ++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  51 -
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   8 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  54 +-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  35 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  69 +++-
 drivers/net/ethernet/aquantia/atlantic/ver.h   |   4 +-
 11 files changed, 341 insertions(+), 84 deletions(-)

-- 
2.7.4



[PATCH net-next v3 4/5] net: aquantia: Add renegotiate ethtool operation support

2018-07-02 Thread Igor Russkikh
From: Anton Mikaev 

Adds ethtool -r|--negotiate operation support. It triggers special
control bit on FW interface causing FW to restart link negotiation.

Signed-off-by: Igor Russkikh 
Signed-off-by: Anton Mikaev 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 14 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  2 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 35 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 12 
 4 files changed, 63 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 37f8460..08c9fa6 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,19 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static int aq_ethtool_nway_reset(struct net_device *ndev)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
+   return -EOPNOTSUPP;
+
+   if (netif_running(ndev))
+   return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
+
+   return 0;
+}
+
 static void aq_ethtool_get_pauseparam(struct net_device *ndev,
  struct ethtool_pauseparam *pause)
 {
@@ -390,6 +403,7 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
.get_pauseparam  = aq_ethtool_get_pauseparam,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 3aa36d5..1a51152 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -212,6 +212,8 @@ struct aq_fw_ops {
 
int (*reset)(struct aq_hw_s *self);
 
+   int (*renegotiate)(struct aq_hw_s *self);
+
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
 
int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index cd8f18f..b875590 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -239,6 +239,41 @@ enum hw_atl_fw2x_caps_hi {
CAPS_HI_TRANSACTION_ID,
 };
 
+enum hw_atl_fw2x_ctrl {
+   CTRL_RESERVED1 = 0x00,
+   CTRL_RESERVED2,
+   CTRL_RESERVED3,
+   CTRL_PAUSE,
+   CTRL_ASYMMETRIC_PAUSE,
+   CTRL_RESERVED4,
+   CTRL_RESERVED5,
+   CTRL_RESERVED6,
+   CTRL_1GBASET_FD_EEE,
+   CTRL_2P5GBASET_FD_EEE,
+   CTRL_5GBASET_FD_EEE,
+   CTRL_10GBASET_FD_EEE,
+   CTRL_THERMAL_SHUTDOWN,
+   CTRL_PHY_LOGS,
+   CTRL_EEE_AUTO_DISABLE,
+   CTRL_PFC,
+   CTRL_WAKE_ON_LINK,
+   CTRL_CABLE_DIAG,
+   CTRL_TEMPERATURE,
+   CTRL_DOWNSHIFT,
+   CTRL_PTP_AVB,
+   CTRL_RESERVED7,
+   CTRL_LINK_DROP,
+   CTRL_SLEEP_PROXY,
+   CTRL_WOL,
+   CTRL_MAC_STOP,
+   CTRL_EXT_LOOPBACK,
+   CTRL_INT_LOOPBACK,
+   CTRL_RESERVED8,
+   CTRL_WOL_TIMER,
+   CTRL_STATISTICS,
+   CTRL_FORCE_RECONNECT,
+};
+
 struct aq_hw_s;
 struct aq_fw_ops;
 struct aq_hw_caps_s;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index c1b671e..e379437 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -215,6 +215,17 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self)
return hw_atl_utils_update_stats(self);
 }
 
+static int aq_fw2x_renegotiate(struct aq_hw_s *self)
+{
+   u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+
+   mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
+
+   aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+   return 0;
+}
+
 static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
 {
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
@@ -230,6 +241,7 @@ const struct aq_fw_ops aq_fw_2x_ops = {
.init = aq_fw2x_init,
.deinit = aq_fw2x_deinit,
.reset = NULL,
+   .renegotiate = aq_fw2x_renegotiate,
.get_mac_permanent = aq_fw2x_get_mac_permanent,
.set_link_speed = aq_fw2x_set_link_speed,
.set_state = aq_fw2x_set_state,
-- 
2.7.4



[PATCH net] net: aquantia: fix unsigned numvecs comparison with less than zero

2018-06-07 Thread Igor Russkikh
From: Colin Ian King 

From: Colin Ian King 

This was originally mistakenly submitted to net-next. Resubmitting to net.

The comparison of numvecs < 0 is always false because numvecs is a u32
and hence the error return from a failed call to pci_alloc_irq_vectores
is never detected.  Fix this by using the signed int ret to handle the
error return and assign numvecs to err.

Detected by CoverityScan, CID#1468650 ("Unsigned compared against 0")

Fixes: a09bd81b5413 ("net: aquantia: Limit number of vectors to actually 
allocated irqs")
Signed-off-by: Colin Ian King 
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
index a50e08bb4748..750007513f9d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -267,14 +267,13 @@ static int aq_pci_probe(struct pci_dev *pdev,
numvecs = min(numvecs, num_online_cpus());
/*enable interrupts */
 #if !AQ_CFG_FORCE_LEGACY_INT
-   numvecs = pci_alloc_irq_vectors(self->pdev, 1, numvecs,
-   PCI_IRQ_MSIX | PCI_IRQ_MSI |
-   PCI_IRQ_LEGACY);
+   err = pci_alloc_irq_vectors(self->pdev, 1, numvecs,
+   PCI_IRQ_MSIX | PCI_IRQ_MSI |
+   PCI_IRQ_LEGACY);
 
-   if (numvecs < 0) {
-   err = numvecs;
+   if (err < 0)
goto err_hwinit;
-   }
+   numvecs = err;
 #endif
self->irqvecs = numvecs;
 
-- 
2.17.1



Re: [PATCH net-next v2 1/5] net: aquantia: Ethtool based ring size configuration

2018-06-04 Thread Igor Russkikh


>> +mutex_lock(>aq_mutex);
>> +
>>  if (aq_utils_obj_test(>flags, AQ_NIC_FLAGS_IS_NOT_READY))
>>  goto err_exit;
>>  
>> @@ -175,6 +177,7 @@ static void aq_nic_service_timer_cb(struct timer_list *t)
>>  ctimer = max(ctimer / 2, 1);
>>  
>>  err_exit:
>> +mutex_unlock(>aq_mutex);
>>  mod_timer(>service_timer, jiffies + ctimer);
>>  }
>>  
> 
> This looks like a timer callback from the prototype, I don't think you
> can take mutexes in timer callbacks.

True as well. Eventually, think we may just get rid of mutex inside of this 
callback.

Mutex then will only serve to prevent possible parallel `ethtool -G` collisions 
from happening.

BR, Igor


[PATCH net-next v2 1/5] net: aquantia: Ethtool based ring size configuration

2018-06-04 Thread Igor Russkikh
From: Anton Mikaev 

Implemented ring size setup, min/max validation and reconfiguration in
runtime. NIC level lock is used to prevent collisions on parallel
reconfiguration and interference with periodic service timer job.

Signed-off-by: Anton Mikaev 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 65 ++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 ++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  9 ++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  | 46 +++
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |  8 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 50 +
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |  8 +++
 8 files changed, 147 insertions(+), 50 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index f2d8063..97f42d1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -11,6 +11,7 @@
 
 #include "aq_ethtool.h"
 #include "aq_nic.h"
+#include "aq_vec.h"
 
 static void aq_ethtool_get_regs(struct net_device *ndev,
struct ethtool_regs *regs, void *p)
@@ -284,6 +285,68 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_get_ringparam(struct net_device *ndev,
+struct ethtool_ringparam *ring)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
+
+   ring->rx_pending = aq_nic_cfg->rxds;
+   ring->tx_pending = aq_nic_cfg->txds;
+
+   ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max;
+   ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max;
+}
+
+static int aq_set_ringparam(struct net_device *ndev,
+   struct ethtool_ringparam *ring)
+{
+   int err = 0;
+   bool ndev_running = false;
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
+   const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps;
+
+   if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
+   err = -EOPNOTSUPP;
+   goto err_exit;
+   }
+
+   mutex_lock(_nic->aq_mutex);
+
+   if (netif_running(ndev)) {
+   ndev_running = true;
+   dev_close(ndev);
+   }
+
+   aq_nic_free_vectors(aq_nic);
+
+   aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
+   aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max);
+   aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE);
+
+   aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min);
+   aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max);
+   aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE);
+
+   for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs;
+aq_nic->aq_vecs++) {
+   aq_nic->aq_vec[aq_nic->aq_vecs] =
+   aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg);
+   if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) {
+   err = -ENOMEM;
+   goto err_unlock;
+   }
+   }
+   if (ndev_running)
+   err = dev_open(ndev);
+
+err_unlock:
+   mutex_unlock(_nic->aq_mutex);
+err_exit:
+   return err;
+}
+
 const struct ethtool_ops aq_ethtool_ops = {
.get_link= aq_ethtool_get_link,
.get_regs_len= aq_ethtool_get_regs_len,
@@ -291,6 +354,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .get_ringparam   = aq_get_ringparam,
+   .set_ringparam   = aq_set_ringparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index a2d416b..904cdfd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -24,8 +24,10 @@ struct aq_hw_caps_s {
u64 link_speed_msk;
unsigned int hw_priv_flags;
u32 media_type;
-   u32 rxds;
-   u32 txds;
+   u32 rxds_max;
+   u32 txds_max;
+   u32 rxds_min;
+   u32 txds_min;
u32 txhwb_alignment;
  

[PATCH net-next v2 0/5] net: aquantia: various ethtool ops implementation

2018-06-04 Thread Igor Russkikh
In this patchset Anton Mikaev and I added some useful ethtool operations:
- ring size changes
- link renegotioation
- flow control management

The patch also improves init/deinit sequence.

V2 changes:
- using mutex to secure simultaneous dev close/open
- using state var to store/restore dev state

Igor Russkikh (5):
  net: aquantia: Ethtool based ring size configuration
  net: aquantia: Improve adapter init/deinit logic
  net: aquantia: Implement rx/tx flow control ethtools callback
  net: aquantia: Add renegotiate ethtool operation support
  net: aquantia: bump driver version

 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 121 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  20 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  17 ++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  47 
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   8 ++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  51 -
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   8 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  54 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  35 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  69 +++-
 drivers/net/ethernet/aquantia/atlantic/ver.h   |   4 +-
 12 files changed, 352 insertions(+), 84 deletions(-)

-- 
2.7.4



[PATCH net-next v2 4/5] net: aquantia: Add renegotiate ethtool operation support

2018-06-04 Thread Igor Russkikh
From: Anton Mikaev 

Adds ethtool -r|--negotiate operation support. It triggers special
control bit on FW interface causing FW to restart link negotiation.

Signed-off-by: Igor Russkikh 
Signed-off-by: Anton Mikaev 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 14 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  2 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 35 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 12 
 4 files changed, 63 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index ec9ed44..7058f130 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,19 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static int aq_ethtool_nway_reset(struct net_device *ndev)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
+   return -EOPNOTSUPP;
+
+   if (netif_running(ndev))
+   return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
+
+   return 0;
+}
+
 static void aq_ethtool_get_pauseparam(struct net_device *ndev,
  struct ethtool_pauseparam *pause)
 {
@@ -394,6 +407,7 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
.get_pauseparam  = aq_ethtool_get_pauseparam,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 3aa36d5..1a51152 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -212,6 +212,8 @@ struct aq_fw_ops {
 
int (*reset)(struct aq_hw_s *self);
 
+   int (*renegotiate)(struct aq_hw_s *self);
+
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
 
int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index cd8f18f..b875590 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -239,6 +239,41 @@ enum hw_atl_fw2x_caps_hi {
CAPS_HI_TRANSACTION_ID,
 };
 
+enum hw_atl_fw2x_ctrl {
+   CTRL_RESERVED1 = 0x00,
+   CTRL_RESERVED2,
+   CTRL_RESERVED3,
+   CTRL_PAUSE,
+   CTRL_ASYMMETRIC_PAUSE,
+   CTRL_RESERVED4,
+   CTRL_RESERVED5,
+   CTRL_RESERVED6,
+   CTRL_1GBASET_FD_EEE,
+   CTRL_2P5GBASET_FD_EEE,
+   CTRL_5GBASET_FD_EEE,
+   CTRL_10GBASET_FD_EEE,
+   CTRL_THERMAL_SHUTDOWN,
+   CTRL_PHY_LOGS,
+   CTRL_EEE_AUTO_DISABLE,
+   CTRL_PFC,
+   CTRL_WAKE_ON_LINK,
+   CTRL_CABLE_DIAG,
+   CTRL_TEMPERATURE,
+   CTRL_DOWNSHIFT,
+   CTRL_PTP_AVB,
+   CTRL_RESERVED7,
+   CTRL_LINK_DROP,
+   CTRL_SLEEP_PROXY,
+   CTRL_WOL,
+   CTRL_MAC_STOP,
+   CTRL_EXT_LOOPBACK,
+   CTRL_INT_LOOPBACK,
+   CTRL_RESERVED8,
+   CTRL_WOL_TIMER,
+   CTRL_STATISTICS,
+   CTRL_FORCE_RECONNECT,
+};
+
 struct aq_hw_s;
 struct aq_fw_ops;
 struct aq_hw_caps_s;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index d2d030a..1935fd6 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -215,6 +215,17 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self)
return hw_atl_utils_update_stats(self);
 }
 
+static int aq_fw2x_renegotiate(struct aq_hw_s *self)
+{
+   u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+
+   mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
+
+   aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+   return 0;
+}
+
 static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
 {
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
@@ -230,6 +241,7 @@ const struct aq_fw_ops aq_fw_2x_ops = {
.init = aq_fw2x_init,
.deinit = aq_fw2x_deinit,
.reset = NULL,
+   .renegotiate = aq_fw2x_renegotiate,
.get_mac_permanent = aq_fw2x_get_mac_permanent,
.set_link_speed = aq_fw2x_set_link_speed,
.set_state = aq_fw2x_set_state,
-- 
2.7.4



[PATCH net-next v2 3/5] net: aquantia: Implement rx/tx flow control ethtools callback

2018-06-04 Thread Igor Russkikh
Runtime change of pause frame configuration (rx/tx flow control)
via ethtool.

Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 42 ++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  6 +++-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  1 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 26 ++
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 97f42d1..ec9ed44 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,46 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_ethtool_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   pause->autoneg = 0;
+
+   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
+   pause->rx_pause = 1;
+   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
+   pause->tx_pause = 1;
+}
+
+static int aq_ethtool_set_pauseparam(struct net_device *ndev,
+struct ethtool_pauseparam *pause)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   int err = 0;
+
+   if (!aq_nic->aq_fw_ops->set_flow_control)
+   return -EOPNOTSUPP;
+
+   if (pause->autoneg == AUTONEG_ENABLE)
+   return -EOPNOTSUPP;
+
+   if (pause->rx_pause)
+   aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX;
+   else
+   aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX;
+
+   if (pause->tx_pause)
+   aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX;
+   else
+   aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
+
+   err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
+
+   return err;
+}
+
 static void aq_get_ringparam(struct net_device *ndev,
 struct ethtool_ringparam *ring)
 {
@@ -356,6 +396,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
+   .get_pauseparam  = aq_ethtool_get_pauseparam,
+   .set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 6721ffa..f97e0ba 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -766,10 +766,14 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 100baseT_Full);
 
-   if (self->aq_nic_cfg.flow_control)
+   if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 Pause);
 
+   if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX)
+   ethtool_link_ksettings_add_link_mode(cmd, advertising,
+Asym_Pause);
+
if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
else
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index 9d0a96d..e1feba5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -834,4 +834,5 @@ const struct aq_fw_ops aq_fw_1x_ops = {
.set_state = hw_atl_utils_mpi_set_state,
.update_link_status = hw_atl_utils_mpi_get_link_status,
.update_stats = hw_atl_utils_update_stats,
+   .set_flow_control = NULL,
 };
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index a4ac592..d2d030a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -87,6 +87,19 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 
speed)
return 0;
 }
 
+static void a

[PATCH net-next v2 5/5] net: aquantia: bump driver version

2018-06-04 Thread Igor Russkikh
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/ver.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h 
b/drivers/net/ethernet/aquantia/atlantic/ver.h
index a445de6..94efc64 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -12,8 +12,8 @@
 
 #define NIC_MAJOR_DRIVER_VERSION   2
 #define NIC_MINOR_DRIVER_VERSION   0
-#define NIC_BUILD_DRIVER_VERSION   2
-#define NIC_REVISION_DRIVER_VERSION1
+#define NIC_BUILD_DRIVER_VERSION   3
+#define NIC_REVISION_DRIVER_VERSION0
 
 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
 
-- 
2.7.4



[PATCH net-next v2 2/5] net: aquantia: Improve adapter init/deinit logic

2018-06-04 Thread Igor Russkikh
We now pass link drop status to FW on init/deinit. This is required
to inform FW that driver took/released a control on link.
FW then will manage its own state and device power profile based
on this information. To improve management we remove mpi_set
function which ambiguously took both state and speed parameters.

Deinit callback is now a part of FW ops, as it actually manages the FW.

Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 ++--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  2 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  1 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  1 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 53 --
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 31 -
 6 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 904cdfd..3aa36d5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -202,25 +202,28 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
-   int (*hw_deinit)(struct aq_hw_s *self);
-
int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
 };
 
 struct aq_fw_ops {
int (*init)(struct aq_hw_s *self);
 
+   int (*deinit)(struct aq_hw_s *self);
+
int (*reset)(struct aq_hw_s *self);
 
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
 
int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
 
-   int (*set_state)(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e 
state);
+   int (*set_state)(struct aq_hw_s *self,
+enum hal_atl_utils_fw_state_e state);
 
int (*update_link_status)(struct aq_hw_s *self);
 
int (*update_stats)(struct aq_hw_s *self);
+
+   int (*set_flow_control)(struct aq_hw_s *self);
 };
 
 #endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index a5ccfde..6721ffa 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -884,7 +884,7 @@ void aq_nic_deinit(struct aq_nic_s *self)
aq_vec_deinit(aq_vec);
 
if (self->power_state == AQ_HW_POWER_STATE_D0) {
-   (void)self->aq_hw_ops->hw_deinit(self->aq_hw);
+   (void)self->aq_fw_ops->deinit(self->aq_hw);
} else {
(void)self->aq_hw_ops->hw_set_power(self->aq_hw,
   self->power_state);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 7fd6a7e..ed7fe6f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -877,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self,
 const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_set_mac_address   = hw_atl_a0_hw_mac_addr_set,
.hw_init  = hw_atl_a0_hw_init,
-   .hw_deinit= hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_a0_hw_reset,
.hw_start = hw_atl_a0_hw_start,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 4ea15b9..9dd4f49 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -935,7 +935,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self,
 const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_set_mac_address   = hw_atl_b0_hw_mac_addr_set,
.hw_init  = hw_atl_b0_hw_init,
-   .hw_deinit= hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_b0_hw_reset,
.hw_start = hw_atl_b0_hw_start,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index e652d86..9d0a96d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -30,10 +30,11 @@
 #define HW_ATL_MPI_CONTROL_ADR  0x0368U
 #define HW_ATL_MPI_STATE_ADR0x036CU
 
-#define HW_ATL_MPI_STATE_MSK0x00FFU
-#define HW_ATL_MPI_STATE_SHIFT  0U
-#define HW_ATL_MPI_SPEED_MSK0xU
-#define HW_ATL_MPI_SPEED_SHIFT  16U
+#define HW_ATL_MPI_STATE_MSK  0x00FFU
+#define HW_ATL_MPI_STATE_SHIFT0U
+#define HW_ATL_MPI_SPEED_MSK  0x00FFU
+#define HW_ATL_MPI_SPEED_SHIFT16U
+#define HW_A

Re: [PATCH net-next 1/5] net: aquantia: Ethtool based ring size configuration

2018-06-01 Thread Igor Russkikh


>> +
>> +spin_lock(_nic->aq_spinlock);
>> +
>> +if (netif_running(ndev))
>> +dev_close(ndev);
> 
> I don't think you can hold a spinlock around dev_close()/dev_open()
> calls.

Thanks Jakub, think you are right, will consider changing this lock to mutex.

>> +if (!netif_running(ndev))
>> +err = dev_open(ndev);
> 
> Will this not open the device regardless if it was open before or not?

Correct, thanks!

BR, Igor


[PATCH net-next 5/5] net: aquantia: bump driver version

2018-05-29 Thread Igor Russkikh
Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/ver.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h 
b/drivers/net/ethernet/aquantia/atlantic/ver.h
index a445de6..94efc64 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -12,8 +12,8 @@
 
 #define NIC_MAJOR_DRIVER_VERSION   2
 #define NIC_MINOR_DRIVER_VERSION   0
-#define NIC_BUILD_DRIVER_VERSION   2
-#define NIC_REVISION_DRIVER_VERSION1
+#define NIC_BUILD_DRIVER_VERSION   3
+#define NIC_REVISION_DRIVER_VERSION0
 
 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
 
-- 
2.7.4



[PATCH net-next 4/5] net: aquantia: Add renegotiate ethtool operation support

2018-05-29 Thread Igor Russkikh
From: Anton Mikaev 

Adds ethtool -r|--negotiate operation support. It triggers special
control bit on FW interface causing FW to restart link negotiation.

Signed-off-by: Igor Russkikh 
Signed-off-by: Anton Mikaev 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 14 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  2 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h| 35 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 12 
 4 files changed, 63 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index c679203..ad6c504 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,19 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static int aq_ethtool_nway_reset(struct net_device *ndev)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
+   return -EOPNOTSUPP;
+
+   if (netif_running(ndev))
+   return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
+
+   return 0;
+}
+
 static void aq_ethtool_get_pauseparam(struct net_device *ndev,
  struct ethtool_pauseparam *pause)
 {
@@ -391,6 +404,7 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .nway_reset  = aq_ethtool_nway_reset,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
.get_pauseparam  = aq_ethtool_get_pauseparam,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 3aa36d5..1a51152 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -212,6 +212,8 @@ struct aq_fw_ops {
 
int (*reset)(struct aq_hw_s *self);
 
+   int (*renegotiate)(struct aq_hw_s *self);
+
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
 
int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index cd8f18f..b875590 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -239,6 +239,41 @@ enum hw_atl_fw2x_caps_hi {
CAPS_HI_TRANSACTION_ID,
 };
 
+enum hw_atl_fw2x_ctrl {
+   CTRL_RESERVED1 = 0x00,
+   CTRL_RESERVED2,
+   CTRL_RESERVED3,
+   CTRL_PAUSE,
+   CTRL_ASYMMETRIC_PAUSE,
+   CTRL_RESERVED4,
+   CTRL_RESERVED5,
+   CTRL_RESERVED6,
+   CTRL_1GBASET_FD_EEE,
+   CTRL_2P5GBASET_FD_EEE,
+   CTRL_5GBASET_FD_EEE,
+   CTRL_10GBASET_FD_EEE,
+   CTRL_THERMAL_SHUTDOWN,
+   CTRL_PHY_LOGS,
+   CTRL_EEE_AUTO_DISABLE,
+   CTRL_PFC,
+   CTRL_WAKE_ON_LINK,
+   CTRL_CABLE_DIAG,
+   CTRL_TEMPERATURE,
+   CTRL_DOWNSHIFT,
+   CTRL_PTP_AVB,
+   CTRL_RESERVED7,
+   CTRL_LINK_DROP,
+   CTRL_SLEEP_PROXY,
+   CTRL_WOL,
+   CTRL_MAC_STOP,
+   CTRL_EXT_LOOPBACK,
+   CTRL_INT_LOOPBACK,
+   CTRL_RESERVED8,
+   CTRL_WOL_TIMER,
+   CTRL_STATISTICS,
+   CTRL_FORCE_RECONNECT,
+};
+
 struct aq_hw_s;
 struct aq_fw_ops;
 struct aq_hw_caps_s;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index d2d030a..1935fd6 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -215,6 +215,17 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self)
return hw_atl_utils_update_stats(self);
 }
 
+static int aq_fw2x_renegotiate(struct aq_hw_s *self)
+{
+   u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+
+   mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
+
+   aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+   return 0;
+}
+
 static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
 {
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
@@ -230,6 +241,7 @@ const struct aq_fw_ops aq_fw_2x_ops = {
.init = aq_fw2x_init,
.deinit = aq_fw2x_deinit,
.reset = NULL,
+   .renegotiate = aq_fw2x_renegotiate,
.get_mac_permanent = aq_fw2x_get_mac_permanent,
.set_link_speed = aq_fw2x_set_link_speed,
.set_state = aq_fw2x_set_state,
-- 
2.7.4



[PATCH net-next 3/5] net: aquantia: Implement rx/tx flow control ethtools callback

2018-05-29 Thread Igor Russkikh
Runtime change of pause frame configuration (rx/tx flow control)
via ethtool.

Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 42 ++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  6 +++-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  1 +
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 26 ++
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index bc43d29..c679203 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -285,6 +285,46 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_ethtool_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+
+   pause->autoneg = 0;
+
+   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
+   pause->rx_pause = 1;
+   if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
+   pause->tx_pause = 1;
+}
+
+static int aq_ethtool_set_pauseparam(struct net_device *ndev,
+struct ethtool_pauseparam *pause)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   int err = 0;
+
+   if (!aq_nic->aq_fw_ops->set_flow_control)
+   return -EOPNOTSUPP;
+
+   if (pause->autoneg == AUTONEG_ENABLE)
+   return -EOPNOTSUPP;
+
+   if (pause->rx_pause)
+   aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX;
+   else
+   aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX;
+
+   if (pause->tx_pause)
+   aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX;
+   else
+   aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
+
+   err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
+
+   return err;
+}
+
 static void aq_get_ringparam(struct net_device *ndev,
 struct ethtool_ringparam *ring)
 {
@@ -353,6 +393,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
.get_ringparam   = aq_get_ringparam,
.set_ringparam   = aq_set_ringparam,
+   .get_pauseparam  = aq_ethtool_get_pauseparam,
+   .set_pauseparam  = aq_ethtool_set_pauseparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index bbafa4e..14fa76a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -766,10 +766,14 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 100baseT_Full);
 
-   if (self->aq_nic_cfg.flow_control)
+   if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)
ethtool_link_ksettings_add_link_mode(cmd, advertising,
 Pause);
 
+   if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX)
+   ethtool_link_ksettings_add_link_mode(cmd, advertising,
+Asym_Pause);
+
if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
else
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index 9d0a96d..e1feba5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -834,4 +834,5 @@ const struct aq_fw_ops aq_fw_1x_ops = {
.set_state = hw_atl_utils_mpi_set_state,
.update_link_status = hw_atl_utils_mpi_get_link_status,
.update_stats = hw_atl_utils_update_stats,
+   .set_flow_control = NULL,
 };
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index a4ac592..d2d030a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -87,6 +87,19 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 
speed)
return 0;
 }
 
+static void a

[PATCH net-next 2/5] net: aquantia: Improve adapter init/deinit logic

2018-05-29 Thread Igor Russkikh
We now pass link drop status to FW on init/deinit. This is required
to inform FW that driver took/released a control on link.
FW then will manage its own state and device power profile based
on this information. To improve management we remove mpi_set
function which ambiguously took both state and speed parameters.

Deinit callback is now a part of FW ops, as it actually manages the FW.

Signed-off-by: Igor Russkikh 
---
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 ++--
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  2 +-
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  1 -
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  1 -
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c| 53 --
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 31 -
 6 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 904cdfd..3aa36d5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -202,25 +202,28 @@ struct aq_hw_ops {
 
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
 
-   int (*hw_deinit)(struct aq_hw_s *self);
-
int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
 };
 
 struct aq_fw_ops {
int (*init)(struct aq_hw_s *self);
 
+   int (*deinit)(struct aq_hw_s *self);
+
int (*reset)(struct aq_hw_s *self);
 
int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
 
int (*set_link_speed)(struct aq_hw_s *self, u32 speed);
 
-   int (*set_state)(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e 
state);
+   int (*set_state)(struct aq_hw_s *self,
+enum hal_atl_utils_fw_state_e state);
 
int (*update_link_status)(struct aq_hw_s *self);
 
int (*update_stats)(struct aq_hw_s *self);
+
+   int (*set_flow_control)(struct aq_hw_s *self);
 };
 
 #endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 05d4e28..bbafa4e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -884,7 +884,7 @@ void aq_nic_deinit(struct aq_nic_s *self)
aq_vec_deinit(aq_vec);
 
if (self->power_state == AQ_HW_POWER_STATE_D0) {
-   (void)self->aq_hw_ops->hw_deinit(self->aq_hw);
+   (void)self->aq_fw_ops->deinit(self->aq_hw);
} else {
(void)self->aq_hw_ops->hw_set_power(self->aq_hw,
   self->power_state);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 7fd6a7e..ed7fe6f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -877,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self,
 const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_set_mac_address   = hw_atl_a0_hw_mac_addr_set,
.hw_init  = hw_atl_a0_hw_init,
-   .hw_deinit= hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_a0_hw_reset,
.hw_start = hw_atl_a0_hw_start,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 4ea15b9..9dd4f49 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -935,7 +935,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self,
 const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_set_mac_address   = hw_atl_b0_hw_mac_addr_set,
.hw_init  = hw_atl_b0_hw_init,
-   .hw_deinit= hw_atl_utils_hw_deinit,
.hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_b0_hw_reset,
.hw_start = hw_atl_b0_hw_start,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index e652d86..9d0a96d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -30,10 +30,11 @@
 #define HW_ATL_MPI_CONTROL_ADR  0x0368U
 #define HW_ATL_MPI_STATE_ADR0x036CU
 
-#define HW_ATL_MPI_STATE_MSK0x00FFU
-#define HW_ATL_MPI_STATE_SHIFT  0U
-#define HW_ATL_MPI_SPEED_MSK0xU
-#define HW_ATL_MPI_SPEED_SHIFT  16U
+#define HW_ATL_MPI_STATE_MSK  0x00FFU
+#define HW_ATL_MPI_STATE_SHIFT0U
+#define HW_ATL_MPI_SPEED_MSK  0x00FFU
+#define HW_ATL_MPI_SPEED_SHIFT16U
+#define HW_A

[PATCH net-next 0/5] net: aquantia: various ethtool ops implementation

2018-05-29 Thread Igor Russkikh
In this patchset Anton Mikaev and I added some useful ethtool operations:
- ring size changes
- link renegotioation
- flow control management

The patch also improves init/deinit sequence.

Igor Russkikh (5):
  net: aquantia: Ethtool based ring size configuration
  net: aquantia: Improve adapter init/deinit logic
  net: aquantia: Implement rx/tx flow control ethtools callback
  net: aquantia: Add renegotiate ethtool operation support
  net: aquantia: bump driver version

 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 118 +
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  20 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  17 ++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|   2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  |  47 
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |   8 ++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  |  51 -
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |   8 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c|  54 +-
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h|  35 ++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  69 +++-
 drivers/net/ethernet/aquantia/atlantic/ver.h   |   4 +-
 12 files changed, 349 insertions(+), 84 deletions(-)

-- 
2.7.4



[PATCH net-next 1/5] net: aquantia: Ethtool based ring size configuration

2018-05-29 Thread Igor Russkikh
From: Anton Mikaev 

Implemented ring size setup, min/max validation and reconfiguration in
runtime. NIC level lock is used to prevent collisions on parallel
reconfiguration and interference with periodic service timer job.

Signed-off-by: Anton Mikaev 
Signed-off-by: Igor Russkikh 
---
 .../net/ethernet/aquantia/atlantic/aq_ethtool.c| 62 ++
 drivers/net/ethernet/aquantia/atlantic/aq_hw.h |  9 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c|  9 +++-
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h|  2 +
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c  | 46 
 .../aquantia/atlantic/hw_atl/hw_atl_a0_internal.h  |  8 +++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 50 -
 .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h  |  8 +++
 8 files changed, 144 insertions(+), 50 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index f2d8063..bc43d29 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -11,6 +11,7 @@
 
 #include "aq_ethtool.h"
 #include "aq_nic.h"
+#include "aq_vec.h"
 
 static void aq_ethtool_get_regs(struct net_device *ndev,
struct ethtool_regs *regs, void *p)
@@ -284,6 +285,65 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
 }
 
+static void aq_get_ringparam(struct net_device *ndev,
+struct ethtool_ringparam *ring)
+{
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
+
+   ring->rx_pending = aq_nic_cfg->rxds;
+   ring->tx_pending = aq_nic_cfg->txds;
+
+   ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max;
+   ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max;
+}
+
+static int aq_set_ringparam(struct net_device *ndev,
+   struct ethtool_ringparam *ring)
+{
+   int err = 0;
+   struct aq_nic_s *aq_nic = netdev_priv(ndev);
+   struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
+   const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps;
+
+   if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
+   err = -EOPNOTSUPP;
+   goto err_exit;
+   }
+
+   spin_lock(_nic->aq_spinlock);
+
+   if (netif_running(ndev))
+   dev_close(ndev);
+
+   aq_nic_free_vectors(aq_nic);
+
+   aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
+   aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max);
+   aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE);
+
+   aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min);
+   aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max);
+   aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE);
+
+   for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs;
+aq_nic->aq_vecs++) {
+   aq_nic->aq_vec[aq_nic->aq_vecs] =
+   aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg);
+   if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) {
+   err = -ENOMEM;
+   goto err_unlock;
+   }
+   }
+   if (!netif_running(ndev))
+   err = dev_open(ndev);
+
+err_unlock:
+   spin_unlock(_nic->aq_spinlock);
+err_exit:
+   return err;
+}
+
 const struct ethtool_ops aq_ethtool_ops = {
.get_link= aq_ethtool_get_link,
.get_regs_len= aq_ethtool_get_regs_len,
@@ -291,6 +351,8 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+   .get_ringparam   = aq_get_ringparam,
+   .set_ringparam   = aq_set_ringparam,
.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
.get_rxfh= aq_ethtool_get_rss,
.get_rxnfc   = aq_ethtool_get_rxnfc,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index a2d416b..904cdfd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -24,8 +24,10 @@ struct aq_hw_caps_s {
u64 link_speed_msk;
unsigned int hw_priv_flags;
u32 media_type;
-   u32 rxds;
-   u32 txds;
+   u32 rxds_max;
+   u32 txds_max;
+   u32 rxds_min;
+   u32 txds_min;
u32 txhwb_alignment;
u32 irq_mask;
u32 vecs;
@@ -98,6 +100,9 @@ struct aq_stats_s 

Re: [PATCH][next] net: aquantia: fix unsigned numvecs comparison with less than zero

2018-05-11 Thread Igor Russkikh

>> Fixes: a09bd81b5413 ("net: aquantia: Limit number of vectors to actually 
>> allocated irqs")
>> Signed-off-by: Colin Ian King 
> 
> This doesn't apply to net-next.
> 

Colin, believe thats because you should target to net, not net-next.

BR, Igor


Re: [PATCH][next] net: aquantia: fix unsigned numvecs comparison with less than zero

2018-05-10 Thread Igor Russkikh

Thanks, Colin!

> The comparison of numvecs < 0 is always false because numvecs is a u32
> and hence the error return from a failed call to pci_alloc_irq_vectores
> is never detected.  Fix this by using the signed int ret to handle the
> error return and assign numvecs to err.
> 
> Detected by CoverityScan, CID#1468650 ("Unsigned compared against 0")
> 
> Fixes: a09bd81b5413 ("net: aquantia: Limit number of vectors to actually 
> allocated irqs")
> Signed-off-by: Colin Ian King <colin.k...@canonical.com>
> ---

Acked-by: Igor Russkikh <igor.russk...@aquantia.com>


Re: [PATCH] net: aquantia: Fix an error handling path in 'aq_pci_probe()'

2018-05-10 Thread Igor Russkikh

> Patch timing is sometimes surprising!

Indeed it.

> 
> Not sure at all if it can be an issue, but I also noted that the order of 
> 'pci_release_regions()' and 'free_netdev()' is in reverse
> order in the 'aq_pci_remove()' function.
> I don't know if done on purpose and/or needed, so I've left it as-is.

I think the order is not important here, so believe thats merely a cosmetics.

BR, Igor


Re: [PATCH] net: aquantia: Fix an error handling path in 'aq_pci_probe()'

2018-05-08 Thread Igor Russkikh
Hi Christophe,

On 08.05.2018 09:39, Christophe JAILLET wrote:
> The position of 2 labels should be swapped in order to release resources
> in the correct order and avoid leaks.
> 

>   kfree(self->aq_hw);
>  err_ioremap:
>   free_netdev(ndev);
> -err_pci_func:
> - pci_release_regions(pdev);
>  err_ndev:
> + pci_release_regions(pdev);
> +err_pci_func:
>   pci_disable_device(pdev);
>   return err;
>  }
> 

This was just submitted yesterday and is already accepted in netdev by David:

http://patchwork.ozlabs.org/patch/909746/

Thanks!

BR, Igor


[PATCH net 2/2] net: aquantia: Limit number of vectors to actually allocated irqs

2018-05-07 Thread Igor Russkikh
Driver should use pci_alloc_irq_vectors return value to correct number
of allocated vectors and napi instances. Otherwise it'll panic later
in pci_irq_vector.

Driver also should allow more than one MSI vectors to be allocated.

Error return path from pci_alloc_irq_vectors is also fixed to revert
resources in a correct sequence when error happens.

Reported-by: Long, Nicholas <nicholas.a.l...@baesystems.com>
Fixes: 23ee07a ("net: aquantia: Cleanup pci functions module")
Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c  |  1 +
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h  |  1 +
 drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 20 ++--
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 720760d..1a1a638 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -95,6 +95,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
/*rss rings */
cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF);
cfg->vecs = min(cfg->vecs, num_online_cpus());
+   cfg->vecs = min(cfg->vecs, self->irqvecs);
/* cfg->vecs should be power of 2 for RSS */
if (cfg->vecs >= 8U)
cfg->vecs = 8U;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index 219b550..faa533a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -80,6 +80,7 @@ struct aq_nic_s {
 
struct pci_dev *pdev;
unsigned int msix_entry_mask;
+   u32 irqvecs;
 };
 
 static inline struct device *aq_nic_get_dev(struct aq_nic_s *self)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
index ecc6306..a50e08b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -267,16 +267,16 @@ static int aq_pci_probe(struct pci_dev *pdev,
numvecs = min(numvecs, num_online_cpus());
/*enable interrupts */
 #if !AQ_CFG_FORCE_LEGACY_INT
-   err = pci_alloc_irq_vectors(self->pdev, numvecs, numvecs,
-   PCI_IRQ_MSIX);
-
-   if (err < 0) {
-   err = pci_alloc_irq_vectors(self->pdev, 1, 1,
-   PCI_IRQ_MSI | PCI_IRQ_LEGACY);
-   if (err < 0)
-   goto err_hwinit;
+   numvecs = pci_alloc_irq_vectors(self->pdev, 1, numvecs,
+   PCI_IRQ_MSIX | PCI_IRQ_MSI |
+   PCI_IRQ_LEGACY);
+
+   if (numvecs < 0) {
+   err = numvecs;
+   goto err_hwinit;
}
 #endif
+   self->irqvecs = numvecs;
 
/* net device init */
aq_nic_cfg_start(self);
@@ -298,9 +298,9 @@ static int aq_pci_probe(struct pci_dev *pdev,
kfree(self->aq_hw);
 err_ioremap:
free_netdev(ndev);
-err_pci_func:
-   pci_release_regions(pdev);
 err_ndev:
+   pci_release_regions(pdev);
+err_pci_func:
pci_disable_device(pdev);
return err;
 }
-- 
2.7.4



[PATCH net 1/2] net: aquantia: driver should correctly declare vlan_features bits

2018-05-07 Thread Igor Russkikh
In particular, not reporting SG forced skbs to be linear for vlan
interfaces over atlantic NIC.

With this fix it is possible to enable SG feature on device and
therefore optimize performance.

Reported-by: Ma Yuying <y...@redhat.com>
Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 32f6d2e..720760d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -246,6 +246,8 @@ void aq_nic_ndev_init(struct aq_nic_s *self)
 
self->ndev->hw_features |= aq_hw_caps->hw_features;
self->ndev->features = aq_hw_caps->hw_features;
+   self->ndev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
+NETIF_F_RXHASH | NETIF_F_SG | NETIF_F_LRO;
self->ndev->priv_flags = aq_hw_caps->hw_priv_flags;
self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 
-- 
2.7.4



[PATCH net 0/2] Aquantia various patches 2018-05

2018-05-07 Thread Igor Russkikh
These are two patches covering issues found during test cycles:

First is that driver should declare valid vlan_features
Second fix is about correct allocation of MSI interrupts on some systems.

Igor Russkikh (2):
  net: aquantia: driver should correctly declare vlan_features bits
  net: aquantia: Limit number of vectors to actually allocated irqs

 drivers/net/ethernet/aquantia/atlantic/aq_nic.c  |  3 +++
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h  |  1 +
 drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 20 ++--
 3 files changed, 14 insertions(+), 10 deletions(-)

-- 
2.7.4



Atlantic driver 4.16 stable request

2018-04-13 Thread Igor Russkikh
Hi David,

Could you please consider queuing to v4.16:

9a11aff net: aquantia: oops when shutdown on already stopped device
cce96d1 net: aquantia: Regression on reset with 1.x firmware

These are both critical and well tested by our team.

Thanks in advance!


[PATCH net 2/2] net: aquantia: oops when shutdown on already stopped device

2018-04-11 Thread Igor Russkikh
In case netdev is closed at the moment of pci shutdown, aq_nic_stop
gets called second time. napi_disable in that case hangs indefinitely.
In other case, if device was never opened at all, we get oops because
of null pointer access.

We should invoke aq_nic_stop conditionally, only if device is running
at the moment of shutdown.

Reported-by: David Arcari <darc...@redhat.com>
Fixes: 90869ddfefeb ("net: aquantia: Implement pci shutdown callback")
Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index c96a921..32f6d2e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -951,9 +951,11 @@ void aq_nic_shutdown(struct aq_nic_s *self)
 
netif_device_detach(self->ndev);
 
-   err = aq_nic_stop(self);
-   if (err < 0)
-   goto err_exit;
+   if (netif_running(self->ndev)) {
+   err = aq_nic_stop(self);
+   if (err < 0)
+   goto err_exit;
+   }
aq_nic_deinit(self);
 
 err_exit:
-- 
2.7.4



[PATCH net 0/2] Aquantia atlantic critical fixes 04/2018

2018-04-11 Thread Igor Russkikh
Two regressions on latest 4.16 driver reported by users

Some of old FW (1.5.44) had a link management logic which prevents
driver to make clean reset. Driver of 4.16 has a full hardware reset
implemented and that broke the link and traffic on such a cards.

Second is oops on shutdown callback in case interface is already
closed or was never opened.

Igor Russkikh (2):
  net: aquantia: Regression on reset with 1.x firmware
  net: aquantia: oops when shutdown on already stopped device

 drivers/net/ethernet/aquantia/atlantic/aq_nic.c  |  8 +---
 .../net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | 16 
 2 files changed, 21 insertions(+), 3 deletions(-)

-- 
2.7.4



[PATCH net 1/2] net: aquantia: Regression on reset with 1.x firmware

2018-04-11 Thread Igor Russkikh
On ASUS XG-C100C with 1.5.44 firmware a special mode called "dirty wake"
is active. With this mode when motherboard gets powered (but no poweron
happens yet), NIC automatically enables powersave link and watches
for WOL packet.
This normally allows to powerup the PC after AC power failures.

Not all motherboards or bios settings gives power to PCI slots,
so this mode is not enabled on all the hardware.

4.16 linux driver introduced full hardware reset sequence
This is required since before that we had no NIC hardware
reset implemented and there were side effects of "not clean start".

But this full reset is incompatible with "dirty wake" WOL feature
it keeps the PHY link in a special mode forever. As a consequence,
driver sees no link and no traffic.

To fix this we forcibly change FW state to idle state before doing
the full reset. This makes FW to restore link state.

Fixes: c8c82eb net: aquantia: Introduce global AQC hardware reset sequence
Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 .../net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index 84d7f4d..e652d86 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -48,6 +48,8 @@
 #define FORCE_FLASHLESS 0
 
 static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
+static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
+ enum hal_atl_utils_fw_state_e state);
 
 int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
 {
@@ -247,6 +249,20 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self)
 
self->rbl_enabled = (boot_exit_code != 0);
 
+   /* FW 1.x may bootup in an invalid POWER state (WOL feature).
+* We should work around this by forcing its state back to DEINIT
+*/
+   if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
+   aq_hw_read_reg(self,
+  HW_ATL_MPI_FW_VERSION))) {
+   int err = 0;
+
+   hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
+   AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR) &
+  HW_ATL_MPI_STATE_MSK) == MPI_DEINIT,
+  10, 1000U);
+   }
+
if (self->rbl_enabled)
return hw_atl_utils_soft_reset_rbl(self);
else
-- 
2.7.4



Re: aquantia - BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 on reboot

2018-04-10 Thread Igor Russkikh

On 10.04.2018 15:42, Yanko Kaneti wrote:
> Hello, 
> 
> Since 90869ddfefeb net: aquantia: Implement pci shutdown callback
> I get the below oops on reboot.  Without the callback everything works
> as expected.
> 

Thanks, we also recently found out that.

Could you please try the below patch?


diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index c96a921..32f6d2e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -951,9 +951,11 @@ void aq_nic_shutdown(struct aq_nic_s *self)
 
netif_device_detach(self->ndev);
 
-   err = aq_nic_stop(self);
-   if (err < 0)
-   goto err_exit;
+   if (netif_running(self->ndev)) {
+   err = aq_nic_stop(self);
+   if (err < 0)
+   goto err_exit;
+   }
aq_nic_deinit(self);
 
 err_exit:
-- 
2.7.4


[PATCH v2 net 6/7] net: aquantia: Implement pci shutdown callback

2018-03-20 Thread Igor Russkikh
We should close link and all NIC operations during shutdown.
On some systems graceful reboot never closes NIC interface on its own,
but only indicates pci device shutdown. Without explicit handler, NIC
rx rings continued to transfer DMA data into prepared buffers while CPU
rebooted already. That caused memory corruptions on soft reboot.

Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 drivers/net/ethernet/aquantia/atlantic/aq_nic.c  | 20 
 drivers/net/ethernet/aquantia/atlantic/aq_nic.h  |  1 +
 drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 15 +++
 3 files changed, 36 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 34120d5..c96a921 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -939,3 +939,23 @@ int aq_nic_change_pm_state(struct aq_nic_s *self, 
pm_message_t *pm_msg)
 out:
return err;
 }
+
+void aq_nic_shutdown(struct aq_nic_s *self)
+{
+   int err = 0;
+
+   if (!self->ndev)
+   return;
+
+   rtnl_lock();
+
+   netif_device_detach(self->ndev);
+
+   err = aq_nic_stop(self);
+   if (err < 0)
+   goto err_exit;
+   aq_nic_deinit(self);
+
+err_exit:
+   rtnl_unlock();
+}
\ No newline at end of file
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h 
b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index d16b0f1..219b550 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -118,5 +118,6 @@ struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
 u32 aq_nic_get_fw_version(struct aq_nic_s *self);
 int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
 int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
+void aq_nic_shutdown(struct aq_nic_s *self);
 
 #endif /* AQ_NIC_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c 
b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
index 87c4308..ecc6306 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -323,6 +323,20 @@ static void aq_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
 }
 
+static void aq_pci_shutdown(struct pci_dev *pdev)
+{
+   struct aq_nic_s *self = pci_get_drvdata(pdev);
+
+   aq_nic_shutdown(self);
+
+   pci_disable_device(pdev);
+
+   if (system_state == SYSTEM_POWER_OFF) {
+   pci_wake_from_d3(pdev, false);
+   pci_set_power_state(pdev, PCI_D3hot);
+   }
+}
+
 static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg)
 {
struct aq_nic_s *self = pci_get_drvdata(pdev);
@@ -345,6 +359,7 @@ static struct pci_driver aq_pci_ops = {
.remove = aq_pci_remove,
.suspend = aq_pci_suspend,
.resume = aq_pci_resume,
+   .shutdown = aq_pci_shutdown,
 };
 
 module_pci_driver(aq_pci_ops);
-- 
2.7.4



[PATCH v2 net 1/7] net: aquantia: Fix hardware reset when SPI may rarely hangup

2018-03-20 Thread Igor Russkikh
Under some circumstances (notably using thunderbolt interface) SPI
on chip reset may be in active transaction.
Here we forcibly cleanup SPI to prevent possible hangups.

Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index 967f0fd..fcb3279 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -79,16 +79,15 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct 
aq_fw_ops **fw_ops)
 
 static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
 {
+   u32 gsr, val;
int k = 0;
-   u32 gsr;
 
aq_hw_write_reg(self, 0x404, 0x40e1);
AQ_HW_SLEEP(50);
 
/* Cleanup SPI */
-   aq_hw_write_reg(self, 0x534, 0xA0);
-   aq_hw_write_reg(self, 0x100, 0x9F);
-   aq_hw_write_reg(self, 0x100, 0x809F);
+   val = aq_hw_read_reg(self, 0x53C);
+   aq_hw_write_reg(self, 0x53C, val | 0x10);
 
gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
@@ -97,7 +96,14 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
aq_hw_write_reg(self, 0x404, 0x80e0);
aq_hw_write_reg(self, 0x32a8, 0x0);
aq_hw_write_reg(self, 0x520, 0x1);
+
+   /* Reset SPI again because of possible interrupted SPI burst */
+   val = aq_hw_read_reg(self, 0x53C);
+   aq_hw_write_reg(self, 0x53C, val | 0x10);
AQ_HW_SLEEP(10);
+   /* Clear SPI reset state */
+   aq_hw_write_reg(self, 0x53C, val & ~0x10);
+
aq_hw_write_reg(self, 0x404, 0x180e0);
 
for (k = 0; k < 1000; k++) {
@@ -147,7 +153,7 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
 
 static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
 {
-   u32 gsr, rbl_status;
+   u32 gsr, val, rbl_status;
int k;
 
aq_hw_write_reg(self, 0x404, 0x40e1);
@@ -157,6 +163,10 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s 
*self)
/* Alter RBL status */
aq_hw_write_reg(self, 0x388, 0xDEAD);
 
+   /* Cleanup SPI */
+   val = aq_hw_read_reg(self, 0x53C);
+   aq_hw_write_reg(self, 0x53C, val | 0x10);
+
/* Global software reset*/
hw_atl_rx_rx_reg_res_dis_set(self, 0U);
hw_atl_tx_tx_reg_res_dis_set(self, 0U);
-- 
2.7.4



[PATCH v2 net 2/7] net: aquantia: Fix a regression with reset on old firmware

2018-03-20 Thread Igor Russkikh
FW 1.5.58 and below needs a fixed delay even after 0x18 register
is filled. Otherwise, setting MPI_INIT state too fast causes
traffic hang.

Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index fcb3279..dcb27bc 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -147,6 +147,8 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
aq_pr_err("FW kickstart failed\n");
return -EIO;
}
+   /* Old FW requires fixed delay after init */
+   AQ_HW_SLEEP(15);
 
return 0;
 }
@@ -214,6 +216,8 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
aq_pr_err("FW kickstart failed\n");
return -EIO;
}
+   /* Old FW requires fixed delay after init */
+   AQ_HW_SLEEP(15);
 
return 0;
 }
-- 
2.7.4



  1   2   3   >