* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14 21:16 Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2018-11-14 21:16 UTC (permalink / raw)
To: Igor Russkikh
Cc: David S . Miller, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, Dmitry Bezrukov
> > Thats again because of this product has tightly integrated MAC+Phy.
> > MAC FW controls system interface and reports/alters link state
> > as a joint state on copper and SIF (even in dpa direct phy mode).
> >
> > We can't extract phy api into a standalone fully functional phylib therefore.
> > Also as far as I know this particular phy is not available in the wild.
>
> So the point is that MAC firmware is managing SERDES and system interface link.
Linux can manage that SERDES link between the MAC and the PHY. There
are two ways this can go:
1) You use phylib. When the PHY reports link, the adjust_link callback
in the MAC is called. The phydev structure contains information about
how you should configure the SERDES, SGMII, 2500Base-X, 5000Base-X. It
works, but it is not so nice.
2) phylink gives you a much nicer API to do the same. Again, the PHY
reports the link is up. phylink will then tell the MAC how to
configure its end of the SERDES. The problem with phylink is that it
expects a DT building. You don't have that, since this is a USB
device. But you also don't need a lot of the features of phylink like
SFPs, the i2c bus for the SFPs, GPIOs etc. So it should not be to hard
to make this work without device tree.
By using core linux code, we avoid bugs in firmware which nobody can
fix. The Linux core code should be well tested and supported, but
phylink is rather new, so might still have some corner cases.
I also cannot imaging parts of the PHY driver will not be re-usable
for other Aquantia PHYs. I have a board with an AQCS109 under my desk
waiting for me to do something with it. I really would like a better
PHY driver for it than the kernel currently has. Hopefully there is
some code reuse possibilities here.
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-16 18:33 Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2018-11-16 18:33 UTC (permalink / raw)
To: Igor Russkikh
Cc: Florian Fainelli, David S . Miller, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, Dmitry Bezrukov
> Production dongles will always have firmware fully controlling all the phy.
> Thus, I think in next series we'll just cut off all the direct phy
> access code.
O.K, but that is also a shame. The PHY i have has all sorts of nice
things, MACSEC, temperature sensors, PTP, cable tests logic,
etc. Without having a proper PHY driver which can access the
registers, a lot of that is going to be very hard to use.
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread
* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-16 9:53 Igor Russkikh
0 siblings, 0 replies; 7+ messages in thread
From: Igor Russkikh @ 2018-11-16 9:53 UTC (permalink / raw)
To: Florian Fainelli, Andrew Lunn
Cc: David S . Miller, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, Dmitry Bezrukov
Hi Andrew, Florian,
>>>
>>> So the point is that MAC firmware is managing SERDES and system interface link.
>>
>> Linux can manage that SERDES link between the MAC and the PHY. There
>> are two ways this can go:
>>
>> 1) You use phylib. When the PHY reports link, the adjust_link callback
>> in the MAC is called. The phydev structure contains information about
>> how you should configure the SERDES, SGMII, 2500Base-X, 5000Base-X. It
>> works, but it is not so nice.
>>
>> 2) phylink gives you a much nicer API to do the same. Again, the PHY
>> reports the link is up. phylink will then tell the MAC how to
>> configure its end of the SERDES. The problem with phylink is that it
>> expects a DT building. You don't have that, since this is a USB
>> device. But you also don't need a lot of the features of phylink like
>> SFPs, the i2c bus for the SFPs, GPIOs etc. So it should not be to hard
>> to make this work without device tree.
>>
>> By using core linux code, we avoid bugs in firmware which nobody can
>> fix. The Linux core code should be well tested and supported, but
>> phylink is rather new, so might still have some corner cases.
>>
>> I also cannot imaging parts of the PHY driver will not be re-usable
>> for other Aquantia PHYs. I have a board with an AQCS109 under my desk
>> waiting for me to do something with it. I really would like a better
>> PHY driver for it than the kernel currently has. Hopefully there is
>> some code reuse possibilities here.
>
> Even if the firmware is helping, there is still value in using PHYLINK
> to report things to Linux as Andrew is saying in that you get a lot of
> things for free: auto-negotiation results, link_ksetttings_{get,set} etc.
Thanks for the detailed explanation, I agree separating phy logic would
really improve things.
But just in time we've got a new updates from HW management/system teams,
It looks like they are deprecating direct phy access firmware mode,
so the only thing we have to support in this driver is FW based interface
for the link management.
Production dongles will always have firmware fully controlling all the phy.
Thus, I think in next series we'll just cut off all the direct phy
access code.
I agree with Andrew we eventually need a better generic Aquantia PHYs support
in linux, hope to look into this matter soon.
Regards,
Igor
^ permalink raw reply [flat|nested] 7+ messages in thread* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14 22:53 Florian Fainelli
0 siblings, 0 replies; 7+ messages in thread
From: Florian Fainelli @ 2018-11-14 22:53 UTC (permalink / raw)
To: Andrew Lunn, Igor Russkikh
Cc: David S . Miller, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, Dmitry Bezrukov
On 11/14/18 1:16 PM, Andrew Lunn wrote:
>>> Thats again because of this product has tightly integrated MAC+Phy.
>>> MAC FW controls system interface and reports/alters link state
>>> as a joint state on copper and SIF (even in dpa direct phy mode).
>>>
>>> We can't extract phy api into a standalone fully functional phylib therefore.
>>> Also as far as I know this particular phy is not available in the wild.
>>
>> So the point is that MAC firmware is managing SERDES and system interface link.
>
> Linux can manage that SERDES link between the MAC and the PHY. There
> are two ways this can go:
>
> 1) You use phylib. When the PHY reports link, the adjust_link callback
> in the MAC is called. The phydev structure contains information about
> how you should configure the SERDES, SGMII, 2500Base-X, 5000Base-X. It
> works, but it is not so nice.
>
> 2) phylink gives you a much nicer API to do the same. Again, the PHY
> reports the link is up. phylink will then tell the MAC how to
> configure its end of the SERDES. The problem with phylink is that it
> expects a DT building. You don't have that, since this is a USB
> device. But you also don't need a lot of the features of phylink like
> SFPs, the i2c bus for the SFPs, GPIOs etc. So it should not be to hard
> to make this work without device tree.
>
> By using core linux code, we avoid bugs in firmware which nobody can
> fix. The Linux core code should be well tested and supported, but
> phylink is rather new, so might still have some corner cases.
>
> I also cannot imaging parts of the PHY driver will not be re-usable
> for other Aquantia PHYs. I have a board with an AQCS109 under my desk
> waiting for me to do something with it. I really would like a better
> PHY driver for it than the kernel currently has. Hopefully there is
> some code reuse possibilities here.
Even if the firmware is helping, there is still value in using PHYLINK
to report things to Linux as Andrew is saying in that you get a lot of
things for free: auto-negotiation results, link_ksetttings_{get,set} etc.
^ permalink raw reply [flat|nested] 7+ messages in thread* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14 7:44 Igor Russkikh
0 siblings, 0 replies; 7+ messages in thread
From: Igor Russkikh @ 2018-11-14 7:44 UTC (permalink / raw)
To: Andrew Lunn
Cc: David S . Miller, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, Dmitry Bezrukov
>>
>> Add full hardware initialization sequence and link configuration logic
>
> Hi Igor
>
> I'm still not convinced the PHY driver should be embedded in the MAC
> driver, rather than using phylink.
>
> If i remember correctly, it was because the MAC is involved in
> determining if the link is up? That is nothing new. phylink expects
> this. The MAC driver should call phylink_mac_change() when the MACs
> SERDES goes up/down.
Hi Andrew,
I'm actually still in doubt as well on this matter.
Of course thats quite possible.
Here was my original comment:
> Thats again because of this product has tightly integrated MAC+Phy.
> MAC FW controls system interface and reports/alters link state
> as a joint state on copper and SIF (even in dpa direct phy mode).
>
> We can't extract phy api into a standalone fully functional phylib therefore.
> Also as far as I know this particular phy is not available in the wild.
So the point is that MAC firmware is managing SERDES and system interface link.
Even if we cut out phy stuff into a separate phylink driver - that driver will
never be functional in standalone mode, without aqc111 mac driver.
It only may make sense from software decomposition perspective - to separate pieces of
phy code.
We'll discuss and reconsider this internally and will give you more comments,
Thanks,
Igor
^ permalink raw reply [flat|nested] 7+ messages in thread
* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-13 20:58 Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2018-11-13 20:58 UTC (permalink / raw)
To: Igor Russkikh
Cc: David S . Miller, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, Dmitry Bezrukov
On Tue, Nov 13, 2018 at 02:44:45PM +0000, Igor Russkikh wrote:
> From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
>
> Add full hardware initialization sequence and link configuration logic
Hi Igor
I'm still not convinced the PHY driver should be embedded in the MAC
driver, rather than using phylink.
If i remember correctly, it was because the MAC is involved in
determining if the link is up? That is nothing new. phylink expects
this. The MAC driver should call phylink_mac_change() when the MACs
SERDES goes up/down.
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-13 14:44 Igor Russkikh
0 siblings, 0 replies; 7+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org,
Dmitry Bezrukov, Igor Russkikh
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Add full hardware initialization sequence and link configuration logic
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
drivers/net/usb/aqc111.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 45 +++++++
2 files changed, 357 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index c91acb7b7c4e..2b78b5d7d29b 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -168,6 +168,122 @@ static int aqc111_mdio_write(struct usbnet *dev, u16 value,
return aqc111_write16_cmd(dev, AQ_PHY_CMD, value, index, data);
}
+static void aqc111_set_phy_speed_fw_iface(struct usbnet *dev,
+ struct aqc111_data *aqc111_data)
+{
+ aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg);
+}
+
+static void aqc111_set_phy_speed_direct(struct usbnet *dev,
+ struct aqc111_data *aqc111_data)
+{
+ u16 reg16_1 = 0;
+ u16 reg16_2 = 0;
+ u16 reg16_3 = 0;
+
+ /* Disable auto-negotiation */
+ reg16_1 = AQ_ANEG_EX_PAGE_CTRL;
+ aqc111_mdio_write(dev, AQ_AUTONEG_STD_CTRL_REG, AQ_PHY_AUTONEG_ADDR,
+ ®16_1);
+
+ reg16_1 = AQ_ANEG_EX_PHY_ID | AQ_ANEG_ADV_AQRATE;
+ if (aqc111_data->phy_cfg & AQ_DOWNSHIFT) {
+ reg16_1 |= AQ_ANEG_EN_DSH;
+ reg16_1 |= (aqc111_data->phy_cfg & AQ_DSH_RETRIES_MASK) >>
+ AQ_DSH_RETRIES_SHIFT;
+ }
+
+ reg16_2 = AQ_ANEG_ADV_LT;
+ if (aqc111_data->phy_cfg & AQ_PAUSE)
+ reg16_3 |= AQ_ANEG_PAUSE;
+
+ if (aqc111_data->phy_cfg & AQ_ASYM_PAUSE)
+ reg16_3 |= AQ_ANEG_ASYM_PAUSE;
+
+ if (aqc111_data->phy_cfg & AQ_ADV_5G) {
+ reg16_1 |= AQ_ANEG_ADV_5G_N;
+ reg16_2 |= AQ_ANEG_ADV_5G_T;
+ }
+ if (aqc111_data->phy_cfg & AQ_ADV_2G5) {
+ reg16_1 |= AQ_ANEG_ADV_2G5_N;
+ reg16_2 |= AQ_ANEG_ADV_2G5_T;
+ }
+ if (aqc111_data->phy_cfg & AQ_ADV_1G)
+ reg16_1 |= AQ_ANEG_ADV_1G;
+
+ if (aqc111_data->phy_cfg & AQ_ADV_100M)
+ reg16_3 |= AQ_ANEG_100M;
+
+ aqc111_mdio_write(dev, AQ_AUTONEG_VEN_PROV1_REG,
+ AQ_PHY_AUTONEG_ADDR, ®16_1);
+ aqc111_mdio_write(dev, AQ_AUTONEG_10GT_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, ®16_2);
+
+ aqc111_mdio_read(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+ ®16_1);
+ reg16_1 &= ~AQ_ANEG_ABILITY_MASK;
+ reg16_1 |= reg16_3;
+ aqc111_mdio_write(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+ ®16_1);
+
+ /* Restart auto-negotiation */
+ reg16_1 = AQ_ANEG_EX_PAGE_CTRL | AQ_ANEG_EN_ANEG |
+ AQ_ANEG_RESTART_ANEG;
+
+ aqc111_mdio_write(dev, AQ_AUTONEG_STD_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, ®16_1);
+}
+
+static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
+{
+ struct aqc111_data *aqc111_data = dev->driver_priv;
+
+ aqc111_data->phy_cfg &= ~AQ_ADV_MASK;
+ aqc111_data->phy_cfg |= AQ_PAUSE;
+ aqc111_data->phy_cfg |= AQ_ASYM_PAUSE;
+ aqc111_data->phy_cfg |= AQ_DOWNSHIFT;
+ aqc111_data->phy_cfg &= ~AQ_DSH_RETRIES_MASK;
+ aqc111_data->phy_cfg |= (3 << AQ_DSH_RETRIES_SHIFT) &
+ AQ_DSH_RETRIES_MASK;
+
+ if (autoneg == AUTONEG_ENABLE) {
+ switch (speed) {
+ case SPEED_5000:
+ aqc111_data->phy_cfg |= AQ_ADV_5G;
+ /* fall-through */
+ case SPEED_2500:
+ aqc111_data->phy_cfg |= AQ_ADV_2G5;
+ /* fall-through */
+ case SPEED_1000:
+ aqc111_data->phy_cfg |= AQ_ADV_1G;
+ /* fall-through */
+ case SPEED_100:
+ aqc111_data->phy_cfg |= AQ_ADV_100M;
+ /* fall-through */
+ }
+ } else {
+ switch (speed) {
+ case SPEED_5000:
+ aqc111_data->phy_cfg |= AQ_ADV_5G;
+ break;
+ case SPEED_2500:
+ aqc111_data->phy_cfg |= AQ_ADV_2G5;
+ break;
+ case SPEED_1000:
+ aqc111_data->phy_cfg |= AQ_ADV_1G;
+ break;
+ case SPEED_100:
+ aqc111_data->phy_cfg |= AQ_ADV_100M;
+ break;
+ }
+ }
+
+ if (aqc111_data->dpa)
+ aqc111_set_phy_speed_direct(dev, aqc111_data);
+ else
+ aqc111_set_phy_speed_fw_iface(dev, aqc111_data);
+}
+
static const struct net_device_ops aqc111_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
@@ -192,6 +308,7 @@ static void aqc111_read_fw_version(struct usbnet *dev,
static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
+ enum usb_device_speed usb_speed = udev->speed;
struct aqc111_data *aqc111_data;
int ret;
@@ -219,6 +336,9 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->netdev_ops = &aqc111_netdev_ops;
aqc111_read_fw_version(dev, aqc111_data);
+ aqc111_data->autoneg = AUTONEG_ENABLE;
+ aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ?
+ SPEED_5000 : SPEED_1000;
return 0;
}
@@ -243,6 +363,7 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0,
0, 1, ®8);
} else {
+ aqc111_data->phy_cfg &= ~AQ_ADV_MASK;
aqc111_data->phy_cfg |= AQ_LOW_POWER;
aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN;
aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
@@ -252,6 +373,187 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
kfree(aqc111_data);
}
+static void aqc111_status(struct usbnet *dev, struct urb *urb)
+{
+ struct aqc111_data *aqc111_data = dev->driver_priv;
+ u64 *event_data = NULL;
+ int link = 0;
+
+ if (urb->actual_length < sizeof(*event_data))
+ return;
+
+ event_data = urb->transfer_buffer;
+ le64_to_cpus(event_data);
+
+ if (*event_data & AQ_LS_MASK)
+ link = 1;
+ else
+ link = 0;
+
+ aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >>
+ AQ_SPEED_SHIFT;
+ aqc111_data->link = link;
+
+ if (netif_carrier_ok(dev->net) != link)
+ usbnet_defer_kevent(dev, EVENT_LINK_RESET);
+}
+
+static void aqc111_configure_rx(struct usbnet *dev,
+ struct aqc111_data *aqc111_data)
+{
+ enum usb_device_speed usb_speed = dev->udev->speed;
+ u16 link_speed = 0, usb_host = 0;
+ u8 buf[5] = { 0 };
+ u8 queue_num = 0;
+ u16 reg16 = 0;
+ u8 reg8 = 0;
+
+ buf[0] = 0x00;
+ buf[1] = 0xF8;
+ buf[2] = 0x07;
+ switch (aqc111_data->link_speed) {
+ case AQ_INT_SPEED_5G:
+ link_speed = 5000;
+ reg8 = 0x05;
+ reg16 = 0x001F;
+ break;
+ case AQ_INT_SPEED_2_5G:
+ link_speed = 2500;
+ reg16 = 0x003F;
+ break;
+ case AQ_INT_SPEED_1G:
+ link_speed = 1000;
+ reg16 = 0x009F;
+ break;
+ case AQ_INT_SPEED_100M:
+ link_speed = 100;
+ queue_num = 1;
+ reg16 = 0x063F;
+ buf[1] = 0xFB;
+ buf[2] = 0x4;
+ break;
+ }
+
+ if (aqc111_data->dpa) {
+ /* Set Phy Flow control */
+ aqc111_mdio_write(dev, AQ_GLB_ING_PAUSE_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, ®16);
+ aqc111_mdio_write(dev, AQ_GLB_EGR_PAUSE_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, ®16);
+ }
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0,
+ 1, 1, ®8);
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf);
+
+ switch (usb_speed) {
+ case USB_SPEED_SUPER:
+ usb_host = 3;
+ break;
+ case USB_SPEED_HIGH:
+ usb_host = 2;
+ break;
+ case USB_SPEED_FULL:
+ case USB_SPEED_LOW:
+ usb_host = 1;
+ queue_num = 0;
+ break;
+ default:
+ usb_host = 0;
+ break;
+ }
+
+ memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5);
+ /* RX bulk configuration */
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf);
+
+ /* Set high low water level */
+ reg16 = 0x0810;
+
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW,
+ 2, ®16);
+ netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host);
+}
+
+static int aqc111_link_reset(struct usbnet *dev)
+{
+ struct aqc111_data *aqc111_data = dev->driver_priv;
+ u16 reg16 = 0;
+ u8 reg8 = 0;
+
+ if (aqc111_data->link == 1) { /* Link up */
+ aqc111_configure_rx(dev, aqc111_data);
+
+ /* Vlan Tag Filter */
+ reg8 = SFR_VLAN_CONTROL_VSO;
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+ 1, 1, ®8);
+
+ reg8 = 0x0;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL,
+ 1, 1, ®8);
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL,
+ 1, 1, ®8);
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8);
+
+ reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB;
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16);
+
+ reg8 = SFR_RX_PATH_READY;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+ 1, 1, ®8);
+
+ reg8 = SFR_BULK_OUT_EFF_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+ 1, 1, ®8);
+
+ reg16 = 0;
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, ®16);
+
+ reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX;
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, ®16);
+
+ aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, ®16);
+
+ reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN |
+ SFR_MEDIUM_TXFLOW_CTRLEN;
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, ®16);
+
+ reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START;
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16);
+
+ netif_carrier_on(dev->net);
+ } else {
+ aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, ®16);
+ reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, ®16);
+
+ aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16);
+ reg16 &= ~SFR_RX_CTL_START;
+ aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16);
+
+ reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+ 1, 1, ®8);
+ reg8 = SFR_BULK_OUT_EFF_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+ 1, 1, ®8);
+
+ netif_carrier_off(dev->net);
+ }
+ return 0;
+}
+
static int aqc111_reset(struct usbnet *dev)
{
struct aqc111_data *aqc111_data = dev->driver_priv;
@@ -292,6 +594,12 @@ static int aqc111_reset(struct usbnet *dev)
SFR_MONITOR_MODE_RW_FLAG);
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8);
+ netif_carrier_off(dev->net);
+
+ /* Phy advertise */
+ aqc111_set_phy_speed(dev, aqc111_data->autoneg,
+ aqc111_data->advertised_speed);
+
return 0;
}
@@ -319,6 +627,8 @@ static int aqc111_stop(struct usbnet *dev)
&aqc111_data->phy_cfg);
}
+ netif_carrier_off(dev->net);
+
return 0;
}
@@ -326,6 +636,8 @@ static const struct driver_info aqc111_info = {
.description = "Aquantia AQtion USB to 5GbE Controller",
.bind = aqc111_bind,
.unbind = aqc111_unbind,
+ .status = aqc111_status,
+ .link_reset = aqc111_link_reset,
.reset = aqc111_reset,
.stop = aqc111_stop,
};
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index ac0bbeabf563..fd49a43e6d93 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -18,12 +18,44 @@
#define AQC111_PHY_ID 0x00
#define AQ_PHY_ADDR(mmd) ((AQC111_PHY_ID << 8) | mmd)
+#define AQ_PHY_AUTONEG_MMD 0x07
+#define AQ_PHY_AUTONEG_ADDR AQ_PHY_ADDR(AQ_PHY_AUTONEG_MMD)
+
+#define AQ_AUTONEG_STD_CTRL_REG 0x0000
+ #define AQ_ANEG_EX_PAGE_CTRL 0x2000
+ #define AQ_ANEG_EN_ANEG 0x1000
+ #define AQ_ANEG_RESTART_ANEG 0x0200
+
+#define AQ_AUTONEG_ADV_REG 0x0010
+ #define AQ_ANEG_100M 0x0100
+ #define AQ_ANEG_PAUSE 0x0400
+ #define AQ_ANEG_ASYM_PAUSE 0x0800
+ #define AQ_ANEG_ABILITY_MASK 0x0FE0
+
+#define AQ_AUTONEG_10GT_CTRL_REG 0x0020
+ #define AQ_ANEG_ADV_10G_T 0x1000
+ #define AQ_ANEG_ADV_5G_T 0x0100
+ #define AQ_ANEG_ADV_2G5_T 0x0080
+ #define AQ_ANEG_ADV_LT 0x0001
+
+#define AQ_AUTONEG_VEN_PROV1_REG 0xC400
+ #define AQ_ANEG_ADV_1G 0x8000
+ #define AQ_ANEG_ADV_AQRATE 0x1000
+ #define AQ_ANEG_ADV_5G_N 0x0800
+ #define AQ_ANEG_ADV_2G5_N 0x0400
+ #define AQ_ANEG_EX_PHY_ID 0x0040
+ #define AQ_ANEG_EN_DSH 0x0010
+ #define AQ_ANEG_DSH_RETRY 0x0003
+
#define AQ_PHY_GLOBAL_MMD 0x1E
#define AQ_PHY_GLOBAL_ADDR AQ_PHY_ADDR(AQ_PHY_GLOBAL_MMD)
#define AQ_GLB_STD_CTRL_REG 0x0000
#define AQ_PHY_LOW_POWER_MODE 0x0800
+#define AQ_GLB_ING_PAUSE_CTRL_REG 0x7148
+#define AQ_GLB_EGR_PAUSE_CTRL_REG 0x4148
+
#define AQ_USB_PHY_SET_TIMEOUT 10000
#define AQ_USB_SET_TIMEOUT 4000
@@ -123,6 +155,7 @@
#define AQ_ADV_1G BIT(1)
#define AQ_ADV_2G5 BIT(2)
#define AQ_ADV_5G BIT(3)
+#define AQ_ADV_MASK 0x0F
#define AQ_PAUSE BIT(16)
#define AQ_ASYM_PAUSE BIT(17)
@@ -137,6 +170,10 @@
/******************************************************************************/
struct aqc111_data {
+ u8 link_speed;
+ u8 link;
+ u8 autoneg;
+ u32 advertised_speed;
struct {
u8 major;
u8 minor;
@@ -146,6 +183,14 @@ struct aqc111_data {
u32 phy_cfg;
};
+#define AQ_LS_MASK 0x8000
+#define AQ_SPEED_MASK 0x7F00
+#define AQ_SPEED_SHIFT 0x0008
+#define AQ_INT_SPEED_5G 0x000F
+#define AQ_INT_SPEED_2_5G 0x0010
+#define AQ_INT_SPEED_1G 0x0011
+#define AQ_INT_SPEED_100M 0x0013
+
static struct {
unsigned char ctrl;
unsigned char timer_l;
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2018-11-16 18:33 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-11-14 21:16 [v2,net-next,06/21] net: usb: aqc111: Introduce link management Andrew Lunn
-- strict thread matches above, loose matches on Subject: below --
2018-11-16 18:33 Andrew Lunn
2018-11-16 9:53 Igor Russkikh
2018-11-14 22:53 Florian Fainelli
2018-11-14 7:44 Igor Russkikh
2018-11-13 20:58 Andrew Lunn
2018-11-13 14:44 Igor Russkikh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).