[PATCH net] net: hns: Bugfix for Tx timeout handling in hns driver

2017-07-12 Thread Lin Yun Sheng
When hns port type is not debug mode, netif_tx_disable is called
when there is a tx timeout, which requires system reboot to return
to normal state. This patch fix this problem by resetting the net
dev.

Fixes: b5996f11ea54 ("net: add Hisilicon Network Subsystem basic ethernet 
support")
Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c 
b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index fe166e0..3987699 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -1378,13 +1378,20 @@ void hns_nic_net_reset(struct net_device *ndev)
 void hns_nic_net_reinit(struct net_device *netdev)
 {
struct hns_nic_priv *priv = netdev_priv(netdev);
+   enum hnae_port_type type = priv->ae_handle->port_type;
 
netif_trans_update(priv->netdev);
while (test_and_set_bit(NIC_STATE_REINITING, >state))
usleep_range(1000, 2000);
 
hns_nic_net_down(netdev);
-   hns_nic_net_reset(netdev);
+
+   /* Only do hns_nic_net_reset in debug mode
+* because of hardware limitation.
+*/
+   if (type == HNAE_PORT_DEBUG)
+   hns_nic_net_reset(netdev);
+
(void)hns_nic_net_up(netdev);
clear_bit(NIC_STATE_REINITING, >state);
 }
@@ -1997,13 +2004,8 @@ static void hns_nic_reset_subtask(struct hns_nic_priv 
*priv)
rtnl_lock();
/* put off any impending NetWatchDogTimeout */
netif_trans_update(priv->netdev);
+   hns_nic_net_reinit(priv->netdev);
 
-   if (type == HNAE_PORT_DEBUG) {
-   hns_nic_net_reinit(priv->netdev);
-   } else {
-   netif_carrier_off(priv->netdev);
-   netif_tx_disable(priv->netdev);
-   }
rtnl_unlock();
 }
 
-- 
1.9.1



[PATCH net V2 1/2] net: hns: Fix a wrong op phy C45 code

2017-07-05 Thread Lin Yun Sheng
From: Yunsheng Lin 

As the user manual described, the second step to write to C45 phy
by mdio should be data, but not address. Here we should fix this
issue.

Fixes: 5b904d39406a ("net: add Hisilicon Network Subsystem MDIO support")
Signed-off-by: Yunsheng Lin 
Reviewed-by: lipeng 
---
 drivers/net/ethernet/hisilicon/hns_mdio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c 
b/drivers/net/ethernet/hisilicon/hns_mdio.c
index e5221d9..017e084 100644
--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -261,7 +261,7 @@ static int hns_mdio_write(struct mii_bus *bus,
 
/* config the data needed writing */
cmd_reg_cfg = devad;
-   op = MDIO_C45_WRITE_ADDR;
+   op = MDIO_C45_WRITE_DATA;
}
 
MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M,
-- 
1.9.1



[PATCH net V2 2/2] net: hns: Fix a skb used after free bug

2017-07-05 Thread Lin Yun Sheng
From: Yunsheng Lin 

skb maybe freed in hns_nic_net_xmit_hw() and return NETDEV_TX_OK,
which cause hns_nic_net_xmit to use a freed skb.

BUG: KASAN: use-after-free in hns_nic_net_xmit_hw+0x62c/0x940...
[17659.112635]  alloc_debug_processing+0x18c/0x1a0
[17659.117208]  __slab_alloc+0x52c/0x560
[17659.120909]  kmem_cache_alloc_node+0xac/0x2c0
[17659.125309]  __alloc_skb+0x6c/0x260
[17659.128837]  tcp_send_ack+0x8c/0x280
[17659.132449]  __tcp_ack_snd_check+0x9c/0xf0
[17659.136587]  tcp_rcv_established+0x5a4/0xa70
[17659.140899]  tcp_v4_do_rcv+0x27c/0x620
[17659.144687]  tcp_prequeue_process+0x108/0x170
[17659.149085]  tcp_recvmsg+0x940/0x1020
[17659.152787]  inet_recvmsg+0x124/0x180
[17659.156488]  sock_recvmsg+0x64/0x80
[17659.160012]  SyS_recvfrom+0xd8/0x180
[17659.163626]  __sys_trace_return+0x0/0x4
[17659.167506] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=23 cpu=1 pid=13
[17659.174000]  free_debug_processing+0x1d4/0x2c0
[17659.178486]  __slab_free+0x240/0x390
[17659.182100]  kmem_cache_free+0x24c/0x270
[17659.186062]  kfree_skbmem+0xa0/0xb0
[17659.189587]  __kfree_skb+0x28/0x40
[17659.193025]  napi_gro_receive+0x168/0x1c0
[17659.197074]  hns_nic_rx_up_pro+0x58/0x90
[17659.201038]  hns_nic_rx_poll_one+0x518/0xbc0
[17659.205352]  hns_nic_common_poll+0x94/0x140
[17659.209576]  net_rx_action+0x458/0x5e0
[17659.213363]  __do_softirq+0x1b8/0x480
[17659.217062]  run_ksoftirqd+0x64/0x80
[17659.220679]  smpboot_thread_fn+0x224/0x310
[17659.224821]  kthread+0x150/0x170
[17659.228084]  ret_from_fork+0x10/0x40

BUG: KASAN: use-after-free in hns_nic_net_xmit+0x8c/0xc0...
[17751.080490]  __slab_alloc+0x52c/0x560
[17751.084188]  kmem_cache_alloc+0x244/0x280
[17751.088238]  __build_skb+0x40/0x150
[17751.091764]  build_skb+0x28/0x100
[17751.095115]  __alloc_rx_skb+0x94/0x150
[17751.098900]  __napi_alloc_skb+0x34/0x90
[17751.102776]  hns_nic_rx_poll_one+0x180/0xbc0
[17751.107097]  hns_nic_common_poll+0x94/0x140
[17751.111333]  net_rx_action+0x458/0x5e0
[17751.115123]  __do_softirq+0x1b8/0x480
[17751.118823]  run_ksoftirqd+0x64/0x80
[17751.122437]  smpboot_thread_fn+0x224/0x310
[17751.126575]  kthread+0x150/0x170
[17751.129838]  ret_from_fork+0x10/0x40
[17751.133454] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=19 cpu=7 pid=43
[17751.139951]  free_debug_processing+0x1d4/0x2c0
[17751.144436]  __slab_free+0x240/0x390
[17751.148051]  kmem_cache_free+0x24c/0x270
[17751.152014]  kfree_skbmem+0xa0/0xb0
[17751.155543]  __kfree_skb+0x28/0x40
[17751.159022]  napi_gro_receive+0x168/0x1c0
[17751.163074]  hns_nic_rx_up_pro+0x58/0x90
[17751.167041]  hns_nic_rx_poll_one+0x518/0xbc0
[17751.171358]  hns_nic_common_poll+0x94/0x140
[17751.175585]  net_rx_action+0x458/0x5e0
[17751.179373]  __do_softirq+0x1b8/0x480
[17751.183076]  run_ksoftirqd+0x64/0x80
[17751.186691]  smpboot_thread_fn+0x224/0x310
[17751.190826]  kthread+0x150/0x170
[17751.194093]  ret_from_fork+0x10/0x40

Fixes: 13ac695e7ea1 ("net:hns: Add support of Hip06 SoC to the Hislicon Network 
Subsystem")
Signed-off-by: Yunsheng Lin 
Signed-off-by: lipeng 
Reported-by: Jun He 
---
 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 ++
 drivers/net/ethernet/hisilicon/hns/hns_enet.h |  6 +++---
 2 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c 
b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index c6700b9..fe166e0 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -300,9 +300,9 @@ static void fill_tso_desc(struct hnae_ring *ring, void 
*priv,
 mtu);
 }
 
-int hns_nic_net_xmit_hw(struct net_device *ndev,
-   struct sk_buff *skb,
-   struct hns_nic_ring_data *ring_data)
+netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev,
+   struct sk_buff *skb,
+   struct hns_nic_ring_data *ring_data)
 {
struct hns_nic_priv *priv = netdev_priv(ndev);
struct hnae_ring *ring = ring_data->ring;
@@ -361,6 +361,10 @@ int hns_nic_net_xmit_hw(struct net_device *ndev,
dev_queue = netdev_get_tx_queue(ndev, 

[PATCH net V2 0/2] Bugfixs for hns ethernet driver

2017-07-05 Thread Lin Yun Sheng
This patchset fix skb used after free and C45 op code issues
in hns driver.

Patch V2:
1. Remove ndev->feature checking in TX description patch.
2. Add Fixes: Tag in patch description.

Patch V1:
Initial Submit

Yunsheng Lin (2):
  net: hns: Fix a wrong op phy C45 code
  net: hns: Fix a skb used after free bug

 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 ++
 drivers/net/ethernet/hisilicon/hns/hns_enet.h |  6 +++---
 drivers/net/ethernet/hisilicon/hns_mdio.c |  2 +-
 3 files changed, 14 insertions(+), 16 deletions(-)

-- 
1.9.1



[PATCH net 1/3] net: hns: Add TX CSUM check when fill TX description

2017-07-04 Thread Lin Yun Sheng
From: Yunsheng Lin 

If driver support checksum offload, should check netdev feature
before fill TX description and get CSUM err bit from RX
description. HNS driver do the check in RX derction but it doesn't
do the check in TX direction.

Signed-off-by: lipeng 
Reviewed-by: Daode Huang 
Reviewed-by: Yunsheng Lin 
---
 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 36 +++
 drivers/net/ethernet/hisilicon/hns/hns_enet.h |  2 +-
 2 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c 
b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index c6700b9..b1e7224 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -40,12 +40,14 @@
 #define SKB_TMP_LEN(SKB) \
(((SKB)->transport_header - (SKB)->mac_header) + tcp_hdrlen(SKB))
 
-static void fill_v2_desc(struct hnae_ring *ring, void *priv,
+static void fill_v2_desc(struct hns_nic_ring_data *ring_data, void *priv,
 int size, dma_addr_t dma, int frag_end,
 int buf_num, enum hns_desc_type type, int mtu)
 {
+   struct hnae_ring *ring = ring_data->ring;
struct hnae_desc *desc = >desc[ring->next_to_use];
struct hnae_desc_cb *desc_cb = >desc_cb[ring->next_to_use];
+   struct net_device *ndev = ring_data->napi.dev;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct sk_buff *skb;
@@ -90,8 +92,13 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 
if (skb->protocol == htons(ETH_P_IP)) {
iphdr = ip_hdr(skb);
-   hnae_set_bit(rrcfv, HNSV2_TXD_L3CS_B, 1);
-   hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
+
+   if (ndev->features & NETIF_F_IP_CSUM) {
+   hnae_set_bit(rrcfv, HNSV2_TXD_L3CS_B,
+1);
+   hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B,
+1);
+   }
 
/* check for tcp/udp header */
if (iphdr->protocol == IPPROTO_TCP &&
@@ -105,7 +112,10 @@ static void fill_v2_desc(struct hnae_ring *ring, void 
*priv,
} else if (skb->protocol == htons(ETH_P_IPV6)) {
hnae_set_bit(tvsvsn, HNSV2_TXD_IPV6_B, 1);
ipv6hdr = ipv6_hdr(skb);
-   hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
+
+   if (ndev->features & NETIF_F_IPV6_CSUM)
+   hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B,
+1);
 
/* check for tcp/udp header */
if (ipv6hdr->nexthdr == IPPROTO_TCP &&
@@ -140,12 +150,14 @@ static void fill_v2_desc(struct hnae_ring *ring, void 
*priv,
 };
 MODULE_DEVICE_TABLE(acpi, hns_enet_acpi_match);
 
-static void fill_desc(struct hnae_ring *ring, void *priv,
+static void fill_desc(struct hns_nic_ring_data *ring_data, void *priv,
  int size, dma_addr_t dma, int frag_end,
  int buf_num, enum hns_desc_type type, int mtu)
 {
+   struct hnae_ring *ring = ring_data->ring;
struct hnae_desc *desc = >desc[ring->next_to_use];
struct hnae_desc_cb *desc_cb = >desc_cb[ring->next_to_use];
+   struct net_device *ndev = ring_data->napi.dev;
struct sk_buff *skb;
__be16 protocol;
u32 ip_offset;
@@ -179,12 +191,14 @@ static void fill_desc(struct hnae_ring *ring, void *priv,
skb->protocol = protocol;
}
 
-   if (skb->protocol == htons(ETH_P_IP)) {
+   if (skb->protocol == htons(ETH_P_IP) &&
+   (ndev->features & NETIF_F_IP_CSUM)) {
flag_ipoffset |= 1 << HNS_TXD_L3CS_B;
/* check for tcp/udp header */
flag_ipoffset |= 1 << HNS_TXD_L4CS_B;
 
-   } else if (skb->protocol == htons(ETH_P_IPV6)) {
+   } else if (skb->protocol == htons(ETH_P_IPV6) &&
+  (ndev->features & NETIF_F_IPV6_CSUM)) {
/* ipv6 has not l3 cs, check for L4 header */
flag_ipoffset |= 1 << HNS_TXD_L4CS_B;
}
@@ -275,7 +289,7 @@ static int hns_nic_maybe_stop_tso(
return 0;
 }
 
-static void fill_tso_desc(struct hnae_ring *ring, void *priv,
+static void fill_tso_desc(struct 

[PATCH net 2/3] net: hns: Fix a wrong op phy C45 code

2017-07-04 Thread Lin Yun Sheng
From: Yunsheng Lin 

As the user manual described, the second step to write to C45 phy
by mdio should be data, but not address. Here we should fix this
issue.

Signed-off-by: Yankejian 
Reviewed-by: lipeng 
Reviewed-by: Yunsheng Lin 
---
 drivers/net/ethernet/hisilicon/hns_mdio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c 
b/drivers/net/ethernet/hisilicon/hns_mdio.c
index e5221d9..017e084 100644
--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -261,7 +261,7 @@ static int hns_mdio_write(struct mii_bus *bus,
 
/* config the data needed writing */
cmd_reg_cfg = devad;
-   op = MDIO_C45_WRITE_ADDR;
+   op = MDIO_C45_WRITE_DATA;
}
 
MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M,
-- 
1.9.1



[PATCH net 0/3] Bugfixs for hns ethernet driver

2017-07-04 Thread Lin Yun Sheng
This patchset fix skb uesd after used, C45 op code and
Tx description filling issues in hns driver.

Yunsheng Lin (3):
  net: hns: Add TX CSUM check when fill TX description
  net: hns: Fix a wrong op phy C45 code
  net: hns: Fix a skb used after free bug

 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 58 ---
 drivers/net/ethernet/hisilicon/hns/hns_enet.h |  8 ++--
 drivers/net/ethernet/hisilicon/hns_mdio.c |  2 +-
 3 files changed, 40 insertions(+), 28 deletions(-)

-- 
1.9.1



[PATCH net 3/3] net: hns: Fix a skb used after free bug

2017-07-04 Thread Lin Yun Sheng
From: Yunsheng Lin 

skb maybe freed in hns_nic_net_xmit_hw() and return NETDEV_TX_OK,
which cause hns_nic_net_xmit to use a freed skb.

BUG: KASAN: use-after-free in hns_nic_net_xmit_hw+0x62c/0x940...
[17659.112635]  alloc_debug_processing+0x18c/0x1a0
[17659.117208]  __slab_alloc+0x52c/0x560
[17659.120909]  kmem_cache_alloc_node+0xac/0x2c0
[17659.125309]  __alloc_skb+0x6c/0x260
[17659.128837]  tcp_send_ack+0x8c/0x280
[17659.132449]  __tcp_ack_snd_check+0x9c/0xf0
[17659.136587]  tcp_rcv_established+0x5a4/0xa70
[17659.140899]  tcp_v4_do_rcv+0x27c/0x620
[17659.144687]  tcp_prequeue_process+0x108/0x170
[17659.149085]  tcp_recvmsg+0x940/0x1020
[17659.152787]  inet_recvmsg+0x124/0x180
[17659.156488]  sock_recvmsg+0x64/0x80
[17659.160012]  SyS_recvfrom+0xd8/0x180
[17659.163626]  __sys_trace_return+0x0/0x4
[17659.167506] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=23 cpu=1 pid=13
[17659.174000]  free_debug_processing+0x1d4/0x2c0
[17659.178486]  __slab_free+0x240/0x390
[17659.182100]  kmem_cache_free+0x24c/0x270
[17659.186062]  kfree_skbmem+0xa0/0xb0
[17659.189587]  __kfree_skb+0x28/0x40
[17659.193025]  napi_gro_receive+0x168/0x1c0
[17659.197074]  hns_nic_rx_up_pro+0x58/0x90
[17659.201038]  hns_nic_rx_poll_one+0x518/0xbc0
[17659.205352]  hns_nic_common_poll+0x94/0x140
[17659.209576]  net_rx_action+0x458/0x5e0
[17659.213363]  __do_softirq+0x1b8/0x480
[17659.217062]  run_ksoftirqd+0x64/0x80
[17659.220679]  smpboot_thread_fn+0x224/0x310
[17659.224821]  kthread+0x150/0x170
[17659.228084]  ret_from_fork+0x10/0x40

BUG: KASAN: use-after-free in hns_nic_net_xmit+0x8c/0xc0...
[17751.080490]  __slab_alloc+0x52c/0x560
[17751.084188]  kmem_cache_alloc+0x244/0x280
[17751.088238]  __build_skb+0x40/0x150
[17751.091764]  build_skb+0x28/0x100
[17751.095115]  __alloc_rx_skb+0x94/0x150
[17751.098900]  __napi_alloc_skb+0x34/0x90
[17751.102776]  hns_nic_rx_poll_one+0x180/0xbc0
[17751.107097]  hns_nic_common_poll+0x94/0x140
[17751.111333]  net_rx_action+0x458/0x5e0
[17751.115123]  __do_softirq+0x1b8/0x480
[17751.118823]  run_ksoftirqd+0x64/0x80
[17751.122437]  smpboot_thread_fn+0x224/0x310
[17751.126575]  kthread+0x150/0x170
[17751.129838]  ret_from_fork+0x10/0x40
[17751.133454] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=19 cpu=7 pid=43
[17751.139951]  free_debug_processing+0x1d4/0x2c0
[17751.144436]  __slab_free+0x240/0x390
[17751.148051]  kmem_cache_free+0x24c/0x270
[17751.152014]  kfree_skbmem+0xa0/0xb0
[17751.155543]  __kfree_skb+0x28/0x40
[17751.159022]  napi_gro_receive+0x168/0x1c0
[17751.163074]  hns_nic_rx_up_pro+0x58/0x90
[17751.167041]  hns_nic_rx_poll_one+0x518/0xbc0
[17751.171358]  hns_nic_common_poll+0x94/0x140
[17751.175585]  net_rx_action+0x458/0x5e0
[17751.179373]  __do_softirq+0x1b8/0x480
[17751.183076]  run_ksoftirqd+0x64/0x80
[17751.186691]  smpboot_thread_fn+0x224/0x310
[17751.190826]  kthread+0x150/0x170
[17751.194093]  ret_from_fork+0x10/0x40

Reported-by: Jun He 
Signed-off-by: lipeng 
Reviewed-by: Yunsheng Lin 
---
 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 ++
 drivers/net/ethernet/hisilicon/hns/hns_enet.h |  6 +++---
 2 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c 
b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index b1e7224..8dfc220 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -314,9 +314,9 @@ static void fill_tso_desc(struct hns_nic_ring_data 
*ring_data, void *priv,
 mtu);
 }
 
-int hns_nic_net_xmit_hw(struct net_device *ndev,
-   struct sk_buff *skb,
-   struct hns_nic_ring_data *ring_data)
+netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev,
+   struct sk_buff *skb,
+   struct hns_nic_ring_data *ring_data)
 {
struct hns_nic_priv *priv = netdev_priv(ndev);
struct hnae_ring *ring = ring_data->ring;
@@ -375,6 +375,10 @@ int hns_nic_net_xmit_hw(struct net_device *ndev,
dev_queue = netdev_get_tx_queue(ndev, skb->queue_mapping);
netdev_tx_sent_queue(dev_queue, skb->len);
 
+   

[PATCH net-next v8 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-30 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hnae.h|   1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 105 ---
 2 files changed, 35 insertions(+), 71 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h 
b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 04211ac..7ba653a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -360,6 +360,7 @@ enum hnae_loop {
MAC_INTERNALLOOP_MAC = 0,
MAC_INTERNALLOOP_SERDES,
MAC_INTERNALLOOP_PHY,
+   MAC_LOOP_PHY_NONE,
MAC_LOOP_NONE,
 };
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index 00e57bb..a8db27e 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,67 +259,27 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
-
-   if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
-   return -ENOTSUPP;
+   int err;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   /* Doing phy loopback in offline state, phy resuming is
+* needed to power up the device.
+*/
+   err = phy_resume(phy_dev);
+   if (err)
+   goto out;
+
+   err = phy_loopback(phy_dev, true);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_loopback(phy_dev, false);
+   if (err)
+   goto out;
+
+   err = phy_suspend(phy_dev);
}
-   return 0;
+
+out:
+   return err;
 }
 
 static int __lb_setup(struct net_device *ndev,
@@ -332,10 +292,9 @@ static int __lb_setup(struct net_device *ndev,
 
switch (loop) {
case MAC_INTERNALLOOP_PHY:
-   if ((phy_dev) && (!phy_dev->is_c45)) {
-   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
-   ret |= h->dev->ops->set_loopback(h, loop, 0x1);
-   }
+   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+   if (!ret)
+   ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
case MAC_INTERNALLOOP_MAC:
if ((h->dev->ops->set_loopback) &&
@@ -346,17 +305,17 @@ static int __lb_setup(struct net_device *ndev,
if (h->dev->ops->set_loopback)
ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
+   case MAC_LOOP_PHY_NONE:
+   ret = hns_nic_config_phy_loopback(phy_dev,

[PATCH net-next v8 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-30 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Patch V8:
Respin the Patch based on net-next

Patch V7:
1. Add comment why resume the phy in hns_nic_config_phy_loopback.
2. Fix a typo error in patch description.

Patch V6:
Fix Or'ing error code in __lb_setup.

Patch V5:
Removing non loopback related code change.

Patch V4:
1. Remove c45 checking
2. Add -ENOTSUPP when function pointer is null,
   take mutex in phy_loopback.

Patch V3:
Calling phy_loopback enable and disable in pair in hns mac driver.

Patch V2:
1. Add phy_loopback in phy_device.c.
2. Do error checking and do the read and write once in
   genphy_loopback.
3. Remove gen10g_loopback in phy_device.c.

Patch V1:
Initial Submit

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hnae.h|   1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 105 ---
 drivers/net/phy/marvell.c|   1 +
 drivers/net/phy/phy_device.c |  51 +++
 include/linux/phy.h  |   5 ++
 5 files changed, 92 insertions(+), 71 deletions(-)

-- 
1.9.1



[PATCH net-next v8 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-30 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by MAC
driver to enable or disable phy loopback. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable loopback.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
Reviewed-by: Andrew Lunn <and...@lunn.ch>
Reviewed-by: Florian Fainelli <f.faine...@gmail.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 51 
 include/linux/phy.h  |  5 +
 3 files changed, 57 insertions(+)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 8400403..5d314f1 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2171,6 +2171,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index acf00f0..1790f7f 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1136,6 +1136,39 @@ int phy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_resume);
 
+int phy_loopback(struct phy_device *phydev, bool enable)
+{
+   struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+   int ret = 0;
+
+   mutex_lock(>lock);
+
+   if (enable && phydev->loopback_enabled) {
+   ret = -EBUSY;
+   goto out;
+   }
+
+   if (!enable && !phydev->loopback_enabled) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   if (phydev->drv && phydrv->set_loopback)
+   ret = phydrv->set_loopback(phydev, enable);
+   else
+   ret = -EOPNOTSUPP;
+
+   if (ret)
+   goto out;
+
+   phydev->loopback_enabled = enable;
+
+out:
+   mutex_unlock(>lock);
+   return ret;
+}
+EXPORT_SYMBOL(phy_loopback);
+
 /* Generic PHY support and helper functions */
 
 /**
@@ -1584,6 +1617,23 @@ int genphy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_resume);
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   value = phy_read(phydev, MII_BMCR);
+   if (value < 0)
+   return value;
+
+   if (enable)
+   value |= BMCR_LOOPBACK;
+   else
+   value &= ~BMCR_LOOPBACK;
+
+   return phy_write(phydev, MII_BMCR, value);
+}
+EXPORT_SYMBOL(genphy_loopback);
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1829,6 +1879,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 };
 
 static int __init phy_init(void)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 1d8d701..2a9567b 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -372,6 +372,7 @@ struct phy_c45_device_ids {
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
  * sysfs_links: Internal boolean tracking sysfs symbolic links setup/removal.
+ * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
  * link_timeout: The number of timer firings to wait before the
@@ -409,6 +410,7 @@ struct phy_device {
bool has_fixups;
bool suspended;
bool sysfs_links;
+   bool loopback_enabled;
 
enum phy_state state;
 
@@ -648,6 +650,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),
\
  struct phy_driver, mdiodrv)
@@ -793,6 +796,7 @@ static inline void phy_device_free(struct phy_device 
*phydev) { }
 int phy_init_hw(struct phy_device *phydev);
 int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
+int phy_loopback(struct phy_device *phydev, bool enable);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
  phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
@@ -847,6 +851,7 @@ void phy_attached_print(struct phy_device *phydev, const 
char *fmt, ...)

[PATCH NET V7 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-28 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by MAC
driver to enable or disable phy loopback. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable loopback.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 51 
 include/linux/phy.h  |  5 +
 3 files changed, 57 insertions(+)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 57297ba..01a1586 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2094,6 +2094,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1219eea..1e08d62 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1123,6 +1123,39 @@ int phy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_resume);
 
+int phy_loopback(struct phy_device *phydev, bool enable)
+{
+   struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+   int ret = 0;
+
+   mutex_lock(>lock);
+
+   if (enable && phydev->loopback_enabled) {
+   ret = -EBUSY;
+   goto out;
+   }
+
+   if (!enable && !phydev->loopback_enabled) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   if (phydev->drv && phydrv->set_loopback)
+   ret = phydrv->set_loopback(phydev, enable);
+   else
+   ret = -EOPNOTSUPP;
+
+   if (ret)
+   goto out;
+
+   phydev->loopback_enabled = enable;
+
+out:
+   mutex_unlock(>lock);
+   return ret;
+}
+EXPORT_SYMBOL(phy_loopback);
+
 /* Generic PHY support and helper functions */
 
 /**
@@ -1628,6 +1661,23 @@ static int gen10g_resume(struct phy_device *phydev)
return 0;
 }
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   value = phy_read(phydev, MII_BMCR);
+   if (value < 0)
+   return value;
+
+   if (enable)
+   value |= BMCR_LOOPBACK;
+   else
+   value &= ~BMCR_LOOPBACK;
+
+   return phy_write(phydev, MII_BMCR, value);
+}
+EXPORT_SYMBOL(genphy_loopback);
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1874,6 +1924,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 }, {
.phy_id = 0x,
.phy_id_mask= 0x,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e76e4ad..49c903dc 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -364,6 +364,7 @@ struct phy_c45_device_ids {
  * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
+ * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
  * link_timeout: The number of timer firings to wait before the
@@ -400,6 +401,7 @@ struct phy_device {
bool is_pseudo_fixed_link;
bool has_fixups;
bool suspended;
+   bool loopback_enabled;
 
enum phy_state state;
 
@@ -639,6 +641,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),
\
  struct phy_driver, mdiodrv)
@@ -774,6 +777,7 @@ static inline void phy_device_free(struct phy_device 
*phydev) { }
 int phy_init_hw(struct phy_device *phydev);
 int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
+int phy_loopback(struct phy_device *phydev, bool enable);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
  phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
@@ -825,6 +829,7 @@ void phy_attached_print(struct phy_device *phydev, const 
char *fmt, ...)
 int genphy_read_status(struct phy_device *phydev);
 int g

[PATCH NET V7 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-28 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hnae.h|   1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 105 ---
 2 files changed, 35 insertions(+), 71 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h 
b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 04211ac..7ba653a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -360,6 +360,7 @@ enum hnae_loop {
MAC_INTERNALLOOP_MAC = 0,
MAC_INTERNALLOOP_SERDES,
MAC_INTERNALLOOP_PHY,
+   MAC_LOOP_PHY_NONE,
MAC_LOOP_NONE,
 };
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index e95795b..92865cf 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,67 +259,27 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
-
-   if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
-   return -ENOTSUPP;
+   int err;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   /* Doing phy loopback in offline state, phy resuming is
+* needed to power up the device.
+*/
+   err = phy_resume(phy_dev);
+   if (err)
+   goto out;
+
+   err = phy_loopback(phy_dev, true);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_loopback(phy_dev, false);
+   if (err)
+   goto out;
+
+   err = phy_suspend(phy_dev);
}
-   return 0;
+
+out:
+   return err;
 }
 
 static int __lb_setup(struct net_device *ndev,
@@ -332,10 +292,9 @@ static int __lb_setup(struct net_device *ndev,
 
switch (loop) {
case MAC_INTERNALLOOP_PHY:
-   if ((phy_dev) && (!phy_dev->is_c45)) {
-   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
-   ret |= h->dev->ops->set_loopback(h, loop, 0x1);
-   }
+   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+   if (!ret)
+   ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
case MAC_INTERNALLOOP_MAC:
if ((h->dev->ops->set_loopback) &&
@@ -346,17 +305,17 @@ static int __lb_setup(struct net_device *ndev,
if (h->dev->ops->set_loopback)
ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
+   case MAC_LOOP_PHY_NONE:
+   ret = hns_nic_config_phy_loopback(phy_dev,

[PATCH NET V7 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-28 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Patch V7:
1. Add comment why resume the phy in hns_nic_config_phy_loopback.
2. Fix a typo error in patch description.

Patch V6:
Fix Or'ing error code in __lb_setup.

Patch V5:
Removing non loopback related code change.

Patch V4:
1. Remove c45 checking
2. Add -ENOTSUPP when function pointer is null,
   take mutex in phy_loopback.

Patch V3:
Calling phy_loopback enable and disable in pair in hns mac driver.

Patch V2:
1. Add phy_loopback in phy_device.c.
2. Do error checking and do the read and write once in
   genphy_loopback.
3. Remove gen10g_loopback in phy_device.c.

Patch V1:
Initial Submit

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hnae.h|   1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 105 ---
 drivers/net/phy/marvell.c|   1 +
 drivers/net/phy/phy_device.c |  51 +++
 include/linux/phy.h  |   5 ++
 5 files changed, 92 insertions(+), 71 deletions(-)

-- 
1.9.1



[PATCH NET V6 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-27 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by Mac
driver to enable or disable a phy. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable a phy.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 51 
 include/linux/phy.h  |  5 +
 3 files changed, 57 insertions(+)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 57297ba..01a1586 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2094,6 +2094,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1219eea..1e08d62 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1123,6 +1123,39 @@ int phy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_resume);
 
+int phy_loopback(struct phy_device *phydev, bool enable)
+{
+   struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+   int ret = 0;
+
+   mutex_lock(>lock);
+
+   if (enable && phydev->loopback_enabled) {
+   ret = -EBUSY;
+   goto out;
+   }
+
+   if (!enable && !phydev->loopback_enabled) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   if (phydev->drv && phydrv->set_loopback)
+   ret = phydrv->set_loopback(phydev, enable);
+   else
+   ret = -EOPNOTSUPP;
+
+   if (ret)
+   goto out;
+
+   phydev->loopback_enabled = enable;
+
+out:
+   mutex_unlock(>lock);
+   return ret;
+}
+EXPORT_SYMBOL(phy_loopback);
+
 /* Generic PHY support and helper functions */
 
 /**
@@ -1628,6 +1661,23 @@ static int gen10g_resume(struct phy_device *phydev)
return 0;
 }
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   value = phy_read(phydev, MII_BMCR);
+   if (value < 0)
+   return value;
+
+   if (enable)
+   value |= BMCR_LOOPBACK;
+   else
+   value &= ~BMCR_LOOPBACK;
+
+   return phy_write(phydev, MII_BMCR, value);
+}
+EXPORT_SYMBOL(genphy_loopback);
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1874,6 +1924,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 }, {
.phy_id = 0x,
.phy_id_mask= 0x,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e76e4ad..49c903dc 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -364,6 +364,7 @@ struct phy_c45_device_ids {
  * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
+ * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
  * link_timeout: The number of timer firings to wait before the
@@ -400,6 +401,7 @@ struct phy_device {
bool is_pseudo_fixed_link;
bool has_fixups;
bool suspended;
+   bool loopback_enabled;
 
enum phy_state state;
 
@@ -639,6 +641,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),
\
  struct phy_driver, mdiodrv)
@@ -774,6 +777,7 @@ static inline void phy_device_free(struct phy_device 
*phydev) { }
 int phy_init_hw(struct phy_device *phydev);
 int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
+int phy_loopback(struct phy_device *phydev, bool enable);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
  phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
@@ -825,6 +829,7 @@ void phy_attached_print(struct phy_device *phydev, const 
char *fmt, ...)
 int genphy_read_status(struct phy_device *phydev);
 int genphy_suspe

[PATCH NET V6 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-27 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hnae.h|   1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 102 +++
 2 files changed, 32 insertions(+), 71 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h 
b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 04211ac..7ba653a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -360,6 +360,7 @@ enum hnae_loop {
MAC_INTERNALLOOP_MAC = 0,
MAC_INTERNALLOOP_SERDES,
MAC_INTERNALLOOP_PHY,
+   MAC_LOOP_PHY_NONE,
MAC_LOOP_NONE,
 };
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index e95795b..7fdd26e 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,67 +259,24 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
-
-   if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
-   return -ENOTSUPP;
+   int err;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_resume(phy_dev);
+   if (err)
+   goto out;
+
+   err = phy_loopback(phy_dev, true);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_loopback(phy_dev, false);
+   if (err)
+   goto out;
+
+   err = phy_suspend(phy_dev);
}
-   return 0;
+
+out:
+   return err;
 }
 
 static int __lb_setup(struct net_device *ndev,
@@ -332,10 +289,9 @@ static int __lb_setup(struct net_device *ndev,
 
switch (loop) {
case MAC_INTERNALLOOP_PHY:
-   if ((phy_dev) && (!phy_dev->is_c45)) {
-   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
-   ret |= h->dev->ops->set_loopback(h, loop, 0x1);
-   }
+   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+   if (!ret)
+   ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
case MAC_INTERNALLOOP_MAC:
if ((h->dev->ops->set_loopback) &&
@@ -346,17 +302,17 @@ static int __lb_setup(struct net_device *ndev,
if (h->dev->ops->set_loopback)
ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
+   case MAC_LOOP_PHY_NONE:
+   ret = hns_nic_config_phy_loopback(phy_dev, 0x0);
case MAC_LOOP_NONE:
-   if ((phy_dev) && (!phy_dev->is_c45))
-   ret |= hns_nic_config_phy_loo

[PATCH NET V6 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-27 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Patch V6:
Fix Or'ing error code in __lb_setup.

Patch V5:
Removing non loopback related code change.

Patch V4:
1. Remove c45 checking
2. Add -ENOTSUPP when function pointer is null,
   take mutex in phy_loopback.

Patch V3:
Calling phy_loopback enable and disable in pair in hns mac driver.

Patch V2:
1. Add phy_loopback in phy_device.c.
2. Do error checking and do the read and write once in
   genphy_loopback.
3. Remove gen10g_loopback in phy_device.c.

Patch V1:
Initial Submit

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hnae.h|   1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 102 +++
 drivers/net/phy/marvell.c|   1 +
 drivers/net/phy/phy_device.c |  51 
 include/linux/phy.h  |   5 ++
 5 files changed, 89 insertions(+), 71 deletions(-)

-- 
1.9.1



[PATCH NET V5 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-25 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hnae.h|  1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 92 +++-
 2 files changed, 26 insertions(+), 67 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h 
b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 04211ac..7ba653a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -360,6 +360,7 @@ enum hnae_loop {
MAC_INTERNALLOOP_MAC = 0,
MAC_INTERNALLOOP_SERDES,
MAC_INTERNALLOOP_PHY,
+   MAC_LOOP_PHY_NONE,
MAC_LOOP_NONE,
 };
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index e95795b..10d82df 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,67 +259,24 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
-
-   if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
-   return -ENOTSUPP;
+   int err;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_resume(phy_dev);
+   if (err)
+   goto out;
+
+   err = phy_loopback(phy_dev, true);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_loopback(phy_dev, false);
+   if (err)
+   goto out;
+
+   err = phy_suspend(phy_dev);
}
-   return 0;
+
+out:
+   return err;
 }
 
 static int __lb_setup(struct net_device *ndev,
@@ -332,10 +289,8 @@ static int __lb_setup(struct net_device *ndev,
 
switch (loop) {
case MAC_INTERNALLOOP_PHY:
-   if ((phy_dev) && (!phy_dev->is_c45)) {
-   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
-   ret |= h->dev->ops->set_loopback(h, loop, 0x1);
-   }
+   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+   ret |= h->dev->ops->set_loopback(h, loop, 0x1);
break;
case MAC_INTERNALLOOP_MAC:
if ((h->dev->ops->set_loopback) &&
@@ -346,10 +301,9 @@ static int __lb_setup(struct net_device *ndev,
if (h->dev->ops->set_loopback)
ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
+   case MAC_LOOP_PHY_NONE:
+   ret |= hns_nic_config_phy_loopback(phy_dev, 0x0);
case MAC_LOOP_NONE:
-   if ((phy_dev) && (!phy_dev->is_c45))
-   ret |= hns_nic_config_phy_loopback(phy_dev, 0x0);
-

[PATCH NET V5 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-25 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by Mac
driver to enable or disable a phy. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable a phy.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 51 
 include/linux/phy.h  |  5 +
 3 files changed, 57 insertions(+)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 57297ba..01a1586 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2094,6 +2094,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1219eea..1e08d62 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1123,6 +1123,39 @@ int phy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_resume);
 
+int phy_loopback(struct phy_device *phydev, bool enable)
+{
+   struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+   int ret = 0;
+
+   mutex_lock(>lock);
+
+   if (enable && phydev->loopback_enabled) {
+   ret = -EBUSY;
+   goto out;
+   }
+
+   if (!enable && !phydev->loopback_enabled) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   if (phydev->drv && phydrv->set_loopback)
+   ret = phydrv->set_loopback(phydev, enable);
+   else
+   ret = -EOPNOTSUPP;
+
+   if (ret)
+   goto out;
+
+   phydev->loopback_enabled = enable;
+
+out:
+   mutex_unlock(>lock);
+   return ret;
+}
+EXPORT_SYMBOL(phy_loopback);
+
 /* Generic PHY support and helper functions */
 
 /**
@@ -1628,6 +1661,23 @@ static int gen10g_resume(struct phy_device *phydev)
return 0;
 }
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   value = phy_read(phydev, MII_BMCR);
+   if (value < 0)
+   return value;
+
+   if (enable)
+   value |= BMCR_LOOPBACK;
+   else
+   value &= ~BMCR_LOOPBACK;
+
+   return phy_write(phydev, MII_BMCR, value);
+}
+EXPORT_SYMBOL(genphy_loopback);
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1874,6 +1924,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 }, {
.phy_id = 0x,
.phy_id_mask= 0x,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e76e4ad..49c903dc 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -364,6 +364,7 @@ struct phy_c45_device_ids {
  * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
+ * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
  * link_timeout: The number of timer firings to wait before the
@@ -400,6 +401,7 @@ struct phy_device {
bool is_pseudo_fixed_link;
bool has_fixups;
bool suspended;
+   bool loopback_enabled;
 
enum phy_state state;
 
@@ -639,6 +641,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),
\
  struct phy_driver, mdiodrv)
@@ -774,6 +777,7 @@ static inline void phy_device_free(struct phy_device 
*phydev) { }
 int phy_init_hw(struct phy_device *phydev);
 int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
+int phy_loopback(struct phy_device *phydev, bool enable);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
  phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
@@ -825,6 +829,7 @@ void phy_attached_print(struct phy_device *phydev, const 
char *fmt, ...)
 int genphy_read_status(struct phy_device *phydev);
 int genphy_suspe

[PATCH NET V5 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-25 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Patch V5:
Removing non loopback related code change.

Patch V4:
1. Remove c45 checking
2. Add -ENOTSUPP when function pointer is null,
   take mutex in phy_loopback.

Patch V3:
Calling phy_loopback enable and disable in pair in hns mac driver.

Patch V2:
1. Add phy_loopback in phy_device.c.
2. Do error checking and do the read and write once in 
   genphy_loopback.
3. Remove gen10g_loopback in phy_device.c.

Patch V1:
Initial Submit

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hnae.h|  1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 92 +++-
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 51 +
 include/linux/phy.h  |  5 ++
 5 files changed, 83 insertions(+), 67 deletions(-)

-- 
1.9.1



[PATCH NET V4 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-24 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hnae.h|  1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 92 +++-
 2 files changed, 26 insertions(+), 67 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h 
b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 04211ac..7ba653a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -360,6 +360,7 @@ enum hnae_loop {
MAC_INTERNALLOOP_MAC = 0,
MAC_INTERNALLOOP_SERDES,
MAC_INTERNALLOOP_PHY,
+   MAC_LOOP_PHY_NONE,
MAC_LOOP_NONE,
 };
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index e95795b..10d82df 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,67 +259,24 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
-
-   if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
-   return -ENOTSUPP;
+   int err;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_resume(phy_dev);
+   if (err)
+   goto out;
+
+   err = phy_loopback(phy_dev, true);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_loopback(phy_dev, false);
+   if (err)
+   goto out;
+
+   err = phy_suspend(phy_dev);
}
-   return 0;
+
+out:
+   return err;
 }
 
 static int __lb_setup(struct net_device *ndev,
@@ -332,10 +289,8 @@ static int __lb_setup(struct net_device *ndev,
 
switch (loop) {
case MAC_INTERNALLOOP_PHY:
-   if ((phy_dev) && (!phy_dev->is_c45)) {
-   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
-   ret |= h->dev->ops->set_loopback(h, loop, 0x1);
-   }
+   ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+   ret |= h->dev->ops->set_loopback(h, loop, 0x1);
break;
case MAC_INTERNALLOOP_MAC:
if ((h->dev->ops->set_loopback) &&
@@ -346,10 +301,9 @@ static int __lb_setup(struct net_device *ndev,
if (h->dev->ops->set_loopback)
ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
+   case MAC_LOOP_PHY_NONE:
+   ret |= hns_nic_config_phy_loopback(phy_dev, 0x0);
case MAC_LOOP_NONE:
-   if ((phy_dev) && (!phy_dev->is_c45))
-   ret |= hns_nic_config_phy_loopback(phy_dev, 0x0);
-

[PATCH NET V4 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-24 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by Mac
driver to enable or disable a phy. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable a phy.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 55 ++--
 include/linux/phy.h  |  5 
 3 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 57297ba..01a1586 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2094,6 +2094,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1219eea..9dd8fc3 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1087,7 +1087,7 @@ int phy_suspend(struct phy_device *phydev)
 {
struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
-   int ret = 0;
+   int ret = -EOPNOTSUPP;
 
/* If the device has WOL enabled, we cannot suspend the PHY */
phy_ethtool_get_wol(phydev, );
@@ -1109,7 +1109,7 @@ int phy_suspend(struct phy_device *phydev)
 int phy_resume(struct phy_device *phydev)
 {
struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
-   int ret = 0;
+   int ret = -EOPNOTSUPP;
 
if (phydev->drv && phydrv->resume)
ret = phydrv->resume(phydev);
@@ -1123,6 +1123,39 @@ int phy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_resume);
 
+int phy_loopback(struct phy_device *phydev, bool enable)
+{
+   struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+   int ret = 0;
+
+   mutex_lock(>lock);
+
+   if (enable && phydev->loopback_enabled) {
+   ret = -EBUSY;
+   goto out;
+   }
+
+   if (!enable && !phydev->loopback_enabled) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   if (phydev->drv && phydrv->set_loopback)
+   ret = phydrv->set_loopback(phydev, enable);
+   else
+   ret = -EOPNOTSUPP;
+
+   if (ret)
+   goto out;
+
+   phydev->loopback_enabled = enable;
+
+out:
+   mutex_unlock(>lock);
+   return ret;
+}
+EXPORT_SYMBOL(phy_loopback);
+
 /* Generic PHY support and helper functions */
 
 /**
@@ -1628,6 +1661,23 @@ static int gen10g_resume(struct phy_device *phydev)
return 0;
 }
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   value = phy_read(phydev, MII_BMCR);
+   if (value < 0)
+   return value;
+
+   if (enable)
+   value |= BMCR_LOOPBACK;
+   else
+   value &= ~BMCR_LOOPBACK;
+
+   return phy_write(phydev, MII_BMCR, value);
+}
+EXPORT_SYMBOL(genphy_loopback);
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1874,6 +1924,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 }, {
.phy_id = 0x,
.phy_id_mask= 0x,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e76e4ad..49c903dc 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -364,6 +364,7 @@ struct phy_c45_device_ids {
  * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
+ * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
  * link_timeout: The number of timer firings to wait before the
@@ -400,6 +401,7 @@ struct phy_device {
bool is_pseudo_fixed_link;
bool has_fixups;
bool suspended;
+   bool loopback_enabled;
 
enum phy_state state;
 
@@ -639,6 +641,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_c

[PATCH NET V4 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-24 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Patch V4:
1. Remove c45 checking
2. Add -ENOTSUPP when function pointer is null,
   take mutex in phy_loopback. 

Patch V3:
Calling phy_loopback enable and disable in pair in hns mac driver.

Patch V2:
1. Add phy_loopback in phy_device.c.
2. Do error checking and do the read and write once in genphy_loopback.
3. Remove gen10g_loopback in phy_device.c.

Patch V1:
Initial Submit

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hnae.h|  1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 92 +++-
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 55 +-
 include/linux/phy.h  |  5 ++
 5 files changed, 85 insertions(+), 69 deletions(-)

-- 
1.9.1



[PATCH NET v3 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-23 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hnae.h|  1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 82 +++-
 2 files changed, 24 insertions(+), 59 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h 
b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 04211ac..7ba653a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -360,6 +360,7 @@ enum hnae_loop {
MAC_INTERNALLOOP_MAC = 0,
MAC_INTERNALLOOP_SERDES,
MAC_INTERNALLOOP_PHY,
+   MAC_LOOP_PHY_NONE,
MAC_LOOP_NONE,
 };
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index e95795b..1d54b14 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,67 +259,27 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
+   int err;
 
if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
return -ENOTSUPP;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_resume(phy_dev);
+   if (err)
+   goto out;
+
+   err = phy_loopback(phy_dev, true);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_loopback(phy_dev, false);
+   if (err)
+   goto out;
+
+   err = phy_suspend(phy_dev);
}
-   return 0;
+
+out:
+   return err;
 }
 
 static int __lb_setup(struct net_device *ndev,
@@ -346,10 +306,10 @@ static int __lb_setup(struct net_device *ndev,
if (h->dev->ops->set_loopback)
ret = h->dev->ops->set_loopback(h, loop, 0x1);
break;
-   case MAC_LOOP_NONE:
+   case MAC_LOOP_PHY_NONE:
if ((phy_dev) && (!phy_dev->is_c45))
ret |= hns_nic_config_phy_loopback(phy_dev, 0x0);
-
+   case MAC_LOOP_NONE:
if (h->dev->ops->set_loopback) {
if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII)
ret |= h->dev->ops->set_loopback(h,
@@ -582,13 +542,16 @@ static int __lb_run_test(struct net_device *ndev,
return ret_val;
 }
 
-static int __lb_down(struct net_device *ndev)
+static int __lb_down(struct net_device *ndev, enum hnae_loop loop)
 {
struct hns_nic_priv *priv = netdev_priv(ndev);
struct hnae_handle *h = priv->ae_handle;
int ret;
 
-   ret = __lb_setup(ndev, MAC_LOOP_NONE);
+   if (loop == MAC_INTERNALLOOP_PHY)
+ 

[PATCH NET v3 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-23 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by Mac
driver to enable or disable a phy. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable a phy.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 41 +
 include/linux/phy.h  |  5 +
 3 files changed, 47 insertions(+)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 57297ba..01a1586 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2094,6 +2094,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1219eea..1e8f800 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1123,6 +1123,29 @@ int phy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_resume);
 
+int phy_loopback(struct phy_device *phydev, bool enable)
+{
+   struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+   int ret = 0;
+
+   if (enable && phydev->loopback_enabled)
+   return -EBUSY;
+
+   if (!enable && !phydev->loopback_enabled)
+   return -EINVAL;
+
+   if (phydev->drv && phydrv->set_loopback)
+   ret = phydrv->set_loopback(phydev, enable);
+
+   if (ret)
+   return ret;
+
+   phydev->loopback_enabled = enable;
+
+   return 0;
+}
+EXPORT_SYMBOL(phy_loopback);
+
 /* Generic PHY support and helper functions */
 
 /**
@@ -1628,6 +1651,23 @@ static int gen10g_resume(struct phy_device *phydev)
return 0;
 }
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   value = phy_read(phydev, MII_BMCR);
+   if (value < 0)
+   return value;
+
+   if (enable)
+   value |= BMCR_LOOPBACK;
+   else
+   value &= ~BMCR_LOOPBACK;
+
+   return phy_write(phydev, MII_BMCR, value);
+}
+EXPORT_SYMBOL(genphy_loopback);
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1874,6 +1914,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 }, {
.phy_id = 0x,
.phy_id_mask= 0x,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e76e4ad..49c903dc 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -364,6 +364,7 @@ struct phy_c45_device_ids {
  * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
+ * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
  * link_timeout: The number of timer firings to wait before the
@@ -400,6 +401,7 @@ struct phy_device {
bool is_pseudo_fixed_link;
bool has_fixups;
bool suspended;
+   bool loopback_enabled;
 
enum phy_state state;
 
@@ -639,6 +641,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),
\
  struct phy_driver, mdiodrv)
@@ -774,6 +777,7 @@ static inline void phy_device_free(struct phy_device 
*phydev) { }
 int phy_init_hw(struct phy_device *phydev);
 int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
+int phy_loopback(struct phy_device *phydev, bool enable);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
  phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
@@ -825,6 +829,7 @@ void phy_attached_print(struct phy_device *phydev, const 
char *fmt, ...)
 int genphy_read_status(struct phy_device *phydev);
 int genphy_suspend(struct phy_device *phydev);
 int genphy_resume(struct phy_device *phydev);
+int genphy_loopback(struct phy_device *phydev, bool enable);
 int genphy_soft_reset(struct phy_device *phydev);
 sta

[PATCH NET v3 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-23 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Patch V3:
Calling phy_loopback enable and disable in pair in hns mac driver.

Patch V2:
1. Add phy_loopback in phy_device.c.
2. Do error checking and do the read and write once in genphy_loopback.
3. Remove gen10g_loopback in phy_device.c.

Patch V1:
Initial Submit

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hnae.h|  1 +
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 82 +++-
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 41 
 include/linux/phy.h  |  5 ++
 5 files changed, 71 insertions(+), 59 deletions(-)

-- 
1.9.1



[PATCH NET v2 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-23 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 68 +---
 1 file changed, 14 insertions(+), 54 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index e95795b..1cd5161 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,67 +259,27 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
+   int err;
 
if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
return -ENOTSUPP;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_resume(phy_dev);
+   if (err)
+   goto out;
+
+   err = phy_loopback(phy_dev, true);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   err = phy_loopback(phy_dev, false);
+   if (err)
+   goto out;
+
+   err = phy_suspend(phy_dev);
}
-   return 0;
+
+out:
+   return err;
 }
 
 static int __lb_setup(struct net_device *ndev,
-- 
1.9.1



[PATCH NET v2 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-23 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by Mac
driver to enable or disable a phy. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable a phy.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 41 +
 include/linux/phy.h  |  5 +
 3 files changed, 47 insertions(+)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 57297ba..01a1586 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2094,6 +2094,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1219eea..1e8f800 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1123,6 +1123,29 @@ int phy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_resume);
 
+int phy_loopback(struct phy_device *phydev, bool enable)
+{
+   struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+   int ret = 0;
+
+   if (enable && phydev->loopback_enabled)
+   return -EBUSY;
+
+   if (!enable && !phydev->loopback_enabled)
+   return -EINVAL;
+
+   if (phydev->drv && phydrv->set_loopback)
+   ret = phydrv->set_loopback(phydev, enable);
+
+   if (ret)
+   return ret;
+
+   phydev->loopback_enabled = enable;
+
+   return 0;
+}
+EXPORT_SYMBOL(phy_loopback);
+
 /* Generic PHY support and helper functions */
 
 /**
@@ -1628,6 +1651,23 @@ static int gen10g_resume(struct phy_device *phydev)
return 0;
 }
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   value = phy_read(phydev, MII_BMCR);
+   if (value < 0)
+   return value;
+
+   if (enable)
+   value |= BMCR_LOOPBACK;
+   else
+   value &= ~BMCR_LOOPBACK;
+
+   return phy_write(phydev, MII_BMCR, value);
+}
+EXPORT_SYMBOL(genphy_loopback);
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1874,6 +1914,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 }, {
.phy_id = 0x,
.phy_id_mask= 0x,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e76e4ad..49c903dc 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -364,6 +364,7 @@ struct phy_c45_device_ids {
  * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
+ * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
  * link_timeout: The number of timer firings to wait before the
@@ -400,6 +401,7 @@ struct phy_device {
bool is_pseudo_fixed_link;
bool has_fixups;
bool suspended;
+   bool loopback_enabled;
 
enum phy_state state;
 
@@ -639,6 +641,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),
\
  struct phy_driver, mdiodrv)
@@ -774,6 +777,7 @@ static inline void phy_device_free(struct phy_device 
*phydev) { }
 int phy_init_hw(struct phy_device *phydev);
 int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
+int phy_loopback(struct phy_device *phydev, bool enable);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
  phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
@@ -825,6 +829,7 @@ void phy_attached_print(struct phy_device *phydev, const 
char *fmt, ...)
 int genphy_read_status(struct phy_device *phydev);
 int genphy_suspend(struct phy_device *phydev);
 int genphy_resume(struct phy_device *phydev);
+int genphy_loopback(struct phy_device *phydev, bool enable);
 int genphy_soft_reset(struct phy_device *phydev);
 sta

[PATCH NET v2 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-23 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Patch V2:
1. Add phy_loopback in phy_device.c.
2. Do error checking and do the read and write once in genphy_loopback.
3. Remove gen10g_loopback in phy_device.c.

Patch V1: Initial Submit

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 68 +---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 41 ++
 include/linux/phy.h  |  5 ++
 4 files changed, 61 insertions(+), 54 deletions(-)

-- 
1.9.1



[PATCH NET 0/2] Add loopback support in phy_driver and hns ethtool fix

2017-06-22 Thread Lin Yun Sheng
This Patch Set add set_loopback in phy_driver and use it to setup loopback
when doing ethtool phy self_test.

Lin Yun Sheng (2):
  net: phy: Add phy loopback support in net phy framework
  net: hns: Use phy_driver to setup Phy loopback

 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 64 
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 23 +
 include/linux/phy.h  |  2 +
 4 files changed, 36 insertions(+), 54 deletions(-)

-- 
1.9.1



[PATCH NET 1/2] net: phy: Add phy loopback support in net phy framework

2017-06-22 Thread Lin Yun Sheng
This patch add set_loopback in phy_driver, which is used by Mac
driver to enable or disable a phy. it also add a generic
genphy_loopback function, which use BMCR loopback bit to enable
or disable a phy.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/phy/marvell.c|  1 +
 drivers/net/phy/phy_device.c | 23 +++
 include/linux/phy.h  |  2 ++
 3 files changed, 26 insertions(+)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 57297ba..01a1586 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2094,6 +2094,7 @@ static int m88e1510_probe(struct phy_device *phydev)
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
+   .set_loopback = genphy_loopback,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1219eea..13b36fa 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1628,6 +1628,27 @@ static int gen10g_resume(struct phy_device *phydev)
return 0;
 }
 
+int genphy_loopback(struct phy_device *phydev, bool enable)
+{
+   int value;
+
+   if (enable) {
+   value = phy_read(phydev, MII_BMCR);
+   phy_write(phydev, MII_BMCR, value | BMCR_LOOPBACK);
+   } else {
+   value = phy_read(phydev, MII_BMCR);
+   phy_write(phydev, MII_BMCR, value & ~BMCR_LOOPBACK);
+   }
+
+   return 0;
+}
+EXPORT_SYMBOL(genphy_loopback);
+
+static int gen10g_loopback(struct phy_device *phydev, bool enable)
+{
+   return 0;
+}
+
 static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
/* The default values for phydev->supported are provided by the PHY
@@ -1874,6 +1895,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= genphy_read_status,
.suspend= genphy_suspend,
.resume = genphy_resume,
+   .set_loopback   = genphy_loopback,
 }, {
.phy_id = 0x,
.phy_id_mask= 0x,
@@ -1885,6 +1907,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
.read_status= gen10g_read_status,
.suspend= gen10g_suspend,
.resume = gen10g_resume,
+   .set_loopback   = gen10g_loopback,
 } };
 
 static int __init phy_init(void)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e76e4ad..9362e22 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -639,6 +639,7 @@ struct phy_driver {
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
+   int (*set_loopback)(struct phy_device *dev, bool enable);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),
\
  struct phy_driver, mdiodrv)
@@ -825,6 +826,7 @@ void phy_attached_print(struct phy_device *phydev, const 
char *fmt, ...)
 int genphy_read_status(struct phy_device *phydev);
 int genphy_suspend(struct phy_device *phydev);
 int genphy_resume(struct phy_device *phydev);
+int genphy_loopback(struct phy_device *phydev, bool enable);
 int genphy_soft_reset(struct phy_device *phydev);
 static inline int genphy_no_soft_reset(struct phy_device *phydev)
 {
-- 
1.9.1



[PATCH NET 2/2] net: hns: Use phy_driver to setup Phy loopback

2017-06-22 Thread Lin Yun Sheng
Use function set_loopback in phy_driver to setup phy loopback
when doing ethtool self test.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 64 
 1 file changed, 10 insertions(+), 54 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index e95795b..660b51e 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -259,66 +259,22 @@ static int hns_nic_set_link_ksettings(struct net_device 
*net_dev,
 
 static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
 {
-#define COPPER_CONTROL_REG 0
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_LOOP_BACK BIT(14)
-   u16 val = 0;
 
-   if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */
+   if (phy_dev->is_c45 || !phy_dev->drv)
+   return -ENOTSUPP;
+
+   if (!phy_dev->drv->resume || !phy_dev->drv->suspend ||
+   !phy_dev->drv->set_loopback)
return -ENOTSUPP;
 
if (en) {
-   /* speed : 1000M */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 2);
-   phy_write(phy_dev, 21, 0x1046);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   /* Force Master */
-   phy_write(phy_dev, 9, 0x1F00);
-
-   /* Soft-reset */
-   phy_write(phy_dev, 0, 0x9140);
-   /* If autoneg disabled,two soft-reset operations */
-   phy_write(phy_dev, 0, 0x9140);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-
-   /* Default is 0x0400 */
-   phy_write(phy_dev, 1, 0x418);
-
-   /* Force 1000M Link, Default is 0x0200 */
-   phy_write(phy_dev, 7, 0x20C);
-
-   /* Powerup Fiber */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   /* Enable Phy Loopback */
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_LOOP_BACK;
-   val &= ~PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   phy_dev->drv->resume(phy_dev);
+   phy_dev->drv->set_loopback(phy_dev, 1);
} else {
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
-   phy_write(phy_dev, 1, 0x400);
-   phy_write(phy_dev, 7, 0x200);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
-
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
-   phy_write(phy_dev, 9, 0xF00);
-
-   val = phy_read(phy_dev, COPPER_CONTROL_REG);
-   val &= ~PHY_LOOP_BACK;
-   val |= PHY_POWER_DOWN;
-   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+   phy_dev->drv->set_loopback(phy_dev, 0);
+   phy_dev->drv->suspend(phy_dev);
}
+
return 0;
 }
 
-- 
1.9.1



[PATCH NET] net/hns:bugfix of ethtool -t phy self_test

2017-06-16 Thread Lin Yun Sheng
This patch fixes the phy loopback self_test failed issue. when
Marvell Phy Module is loaded, it will powerdown fiber when doing
phy loopback self test, which cause phy loopback self_test fail.

Signed-off-by: Lin Yun Sheng <linyunsh...@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c 
b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index b8fab14..e95795b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -288,9 +288,15 @@ static int hns_nic_config_phy_loopback(struct phy_device 
*phy_dev, u8 en)
 
/* Force 1000M Link, Default is 0x0200 */
phy_write(phy_dev, 7, 0x20C);
-   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
 
-   /* Enable PHY loop-back */
+   /* Powerup Fiber */
+   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
+   val = phy_read(phy_dev, COPPER_CONTROL_REG);
+   val &= ~PHY_POWER_DOWN;
+   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+
+   /* Enable Phy Loopback */
+   phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
val = phy_read(phy_dev, COPPER_CONTROL_REG);
val |= PHY_LOOP_BACK;
val &= ~PHY_POWER_DOWN;
@@ -299,6 +305,12 @@ static int hns_nic_config_phy_loopback(struct phy_device 
*phy_dev, u8 en)
phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA);
phy_write(phy_dev, 1, 0x400);
phy_write(phy_dev, 7, 0x200);
+
+   phy_write(phy_dev, HNS_PHY_PAGE_REG, 1);
+   val = phy_read(phy_dev, COPPER_CONTROL_REG);
+   val |= PHY_POWER_DOWN;
+   phy_write(phy_dev, COPPER_CONTROL_REG, val);
+
phy_write(phy_dev, HNS_PHY_PAGE_REG, 0);
phy_write(phy_dev, 9, 0xF00);
 
-- 
1.9.1