diff mbox series

[v2] lan743x: add virtual PHY for PHY-less devices

Message ID 20210122214247.6536-1-sbauer@blackbox.su (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [v2] lan743x: add virtual PHY for PHY-less devices | expand

Checks

Context Check Description
netdev/cover_letter success Link
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Guessed tree name to be net-next
netdev/subject_prefix warning Target tree name not specified in the subject
netdev/cc_maintainers warning 1 maintainers not CCed: nicolas.ferre@microchip.com
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Link
netdev/module_param fail Was 0 now: 1
netdev/build_32bit fail Errors and warnings before: 0 this patch: 2
netdev/kdoc success Errors and warnings before: 2 this patch: 0
netdev/verify_fixes success Link
netdev/checkpatch warning WARNING: From:/Signed-off-by: email name mismatch: 'From: "sbauer@blackbox.su" <sbauer@blackbox.su>' != 'Signed-off-by: Sergej Bauer <sbauer@blackbox.su>' WARNING: line length of 81 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns
netdev/build_allmodconfig_warn fail Errors and warnings before: 0 this patch: 2
netdev/header_inline success Link
netdev/stable success Stable not CCed

Commit Message

Sergej Bauer Jan. 22, 2021, 9:42 p.m. UTC
From: sbauer@blackbox.su

v1->v2:
	switch to using of fixed_phy as was suggested by Andrew and Florian
	also features-related parts are removed

Previous versions can be found at:
v1:
initial version
	https://lkml.org/lkml/2020/9/17/1272

Signed-off-by: Sergej Bauer <sbauer@blackbox.su>

Comments

Andrew Lunn Jan. 22, 2021, 10:08 p.m. UTC | #1
On Sat, Jan 23, 2021 at 12:42:41AM +0300, Sergej Bauer wrote:
> From: sbauer@blackbox.su
> 
> v1->v2:
> 	switch to using of fixed_phy as was suggested by Andrew and Florian
> 	also features-related parts are removed

This is not using fixed_phy, at least not in the normal way.

Take a look at bgmac_phy_connect_direct() for example. Call
fixed_phy_register(), and then phy_connect_direct() with the
phydev. End of story. Done.

> +int lan743x_set_link_ksettings(struct net_device *netdev,
> +			       const struct ethtool_link_ksettings *cmd)
> +{
> +	if (!netdev->phydev)
> +		return -ENETDOWN;
> +
> +	return phy_is_pseudo_fixed_link(netdev->phydev) ?
> +			lan743x_set_virtual_link_ksettings(netdev, cmd)
> +			: phy_ethtool_set_link_ksettings(netdev, cmd);
> +}

There should not be any need to do something different. The whole
point of fixed_phy is it looks like a PHY. So calling
phy_ethtool_set_link_ksettings() should work, nothing special needed.

> @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct lan743x_adapter *adapter)
>  	struct net_device *netdev = adapter->netdev;
>  
>  	phy_stop(netdev->phydev);
> -	phy_disconnect(netdev->phydev);
> -	netdev->phydev = NULL;
> +	if (phy_is_pseudo_fixed_link(netdev->phydev))
> +		lan743x_virtual_phy_disconnect(netdev->phydev);
> +	else
> +		phy_disconnect(netdev->phydev);

phy_disconnect() should work. You might want to call
fixed_phy_unregister() afterwards, so you do not leak memory.

> +		if (phy_is_pseudo_fixed_link(phydev)) {
> +			ret = phy_connect_direct(netdev, phydev,
> +						 lan743x_virtual_phy_status_change,
> +						 PHY_INTERFACE_MODE_MII);
> +		} else {
> +			ret = phy_connect_direct(netdev, phydev,
> +						 lan743x_phy_link_status_change,

There should not be any need for a special link change
callback. lan743x_phy_link_status_change() should work fine, the MAC
should have no idea it is using a fixed_phy.

> +						 PHY_INTERFACE_MODE_GMII);
> +		}
> +
>  		if (ret)
>  			goto return_error;
>  	}
> @@ -1031,6 +1049,15 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter)
>  	/* MAC doesn't support 1000T Half */
>  	phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
>  
> +	if (phy_is_pseudo_fixed_link(phydev)) {
> +		phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_TP_BIT);
> +		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
> +				 phydev->supported);
> +		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
> +				 phydev->supported);
> +		phy_advertise_supported(phydev);
> +	}

The fixed PHY driver will set these bits depending on the speed it has
been configured for. No need to change them. The MAC should also not
care if it is TP, AUI, Fibre or smoke signals.

     Andrew
Sergej Bauer Jan. 22, 2021, 10:11 p.m. UTC | #2
On Saturday, January 23, 2021 12:52:48 AM MSK Florian Fainelli wrote:
> On 1/22/2021 1:42 PM, Sergej Bauer wrote:
> > From: sbauer@blackbox.su
> > 
> > v1->v2:
> > 	switch to using of fixed_phy as was suggested by Andrew and Florian
> > 	also features-related parts are removed
> > 
> > Previous versions can be found at:
> > v1:
> > initial version
> > 
> > 	https://lkml.org/lkml/2020/9/17/1272
> > 
> > Signed-off-by: Sergej Bauer <sbauer@blackbox.su>
> 
> You are not explaining why you need this and why you are second guessing
> the fixed PHY MII emulation that already exists. You really need to do a
> better job at describing your changes and why the emulation offered by
> swphy.c is not enough for your use case.

ok, I'll try to accomplish it with swphy.
Sergej Bauer Jan. 22, 2021, 11:09 p.m. UTC | #3
On Saturday, January 23, 2021 1:08:03 AM MSK Andrew Lunn wrote:
> On Sat, Jan 23, 2021 at 12:42:41AM +0300, Sergej Bauer wrote:
> > From: sbauer@blackbox.su
> > 
> > v1->v2:
> > 	switch to using of fixed_phy as was suggested by Andrew and Florian
> > 	also features-related parts are removed
> 
> This is not using fixed_phy, at least not in the normal way.
> 
> Take a look at bgmac_phy_connect_direct() for example. Call
> fixed_phy_register(), and then phy_connect_direct() with the
> phydev. End of story. Done.
> 
> > +int lan743x_set_link_ksettings(struct net_device *netdev,
> > +			       const struct ethtool_link_ksettings *cmd)
> > +{
> > +	if (!netdev->phydev)
> > +		return -ENETDOWN;
> > +
> > +	return phy_is_pseudo_fixed_link(netdev->phydev) ?
> > +			lan743x_set_virtual_link_ksettings(netdev, cmd)
> > +			: phy_ethtool_set_link_ksettings(netdev, cmd);
> > +}
> 
> There should not be any need to do something different. The whole
> point of fixed_phy is it looks like a PHY. So calling
> phy_ethtool_set_link_ksettings() should work, nothing special needed.
> 
> > @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
> > lan743x_adapter *adapter)> 
> >  	struct net_device *netdev = adapter->netdev;
> >  	
> >  	phy_stop(netdev->phydev);
> > 
> > -	phy_disconnect(netdev->phydev);
> > -	netdev->phydev = NULL;
> > +	if (phy_is_pseudo_fixed_link(netdev->phydev))
> > +		lan743x_virtual_phy_disconnect(netdev->phydev);
> > +	else
> > +		phy_disconnect(netdev->phydev);
> 
> phy_disconnect() should work. You might want to call
Andrew, this is why I was playing with my own _connect/_disconnect 
realizations
It should work but it don't.
modprobe lan743x
rmmod lan743x
modprobe lan743x
leads to
"net eth7: could not add device link to fixed-0:06 err -17"
in dmesg (it does not removes corresponding phydev file in /sysfs)
moreover phy_disconnect leads to kernel panic
[82363.976726] BUG: kernel NULL pointer dereference, address: 00000000000003c4
[82363.977402] #PF: supervisor read access in kernel mode
[82363.978077] #PF: error_code(0x0000) - not-present page
[82363.978588] PGD 0 P4D 0 
[82363.978588] Oops: 0000 [#1] SMP NOPTI
[82363.978588] CPU: 3 PID: 2634 Comm: ifconfig Tainted: G           O      
5.11.0-rc4net-next-virtual_phy+ #3
[82363.978588] Hardware name: Gigabyte Technology Co., Ltd. H110-D3/H110-D3-
CF, BIOS F24 04/11/2018
[82363.978588] RIP: 0010:lan743x_phy_close.isra.26+0x28/0x40 [lan743x]
[82363.978588] Code: c3 90 0f 1f 44 00 00 53 48 89 fb 48 8b bf 28 08 00 00 e8 
ab 5e 86 ff 48 8b bb 28 08 00 00 e8 4f 92 86 ff 48 8b bb 28 08 00 00 <f6> 87 c4 
03 00 00 04 75 02 5b c3 5b e9 f7 35 ea ff 0f 1f 80 00 00
[82363.982448] RSP: 0018:ffffa528c04c7c38 EFLAGS: 00010246
[82363.982448] RAX: 000000000000000f RBX: ffff991a47e38000 RCX: 0000000000000027
[82363.982448] RDX: 0000000000000000 RSI: ffff991c76d98b30 RDI: 0000000000000000
[82363.982448] RBP: 0000000000000001 R08: 0000000000000000 R09: c0000000ffffefff
[82363.982448] R10: 0000000000000001 R11: ffffa528c04c7a48 R12: ffff991a47e388c0
[82363.986855] R13: ffff991a47e390b8 R14: ffff991a47e39050 R15: ffff991a47e388c0
[82363.986855] FS:  00007f7c3ebd6540(0000) GS:ffff991c76d80000(0000) knlGS:
0000000000000000
[82363.986855] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[82363.986855] CR2: 00000000000003c4 CR3: 000000001b2ac005 CR4: 
00000000003706e0
[82363.986855] Call Trace:
[82363.986855]  lan743x_netdev_close+0x223/0x250 [lan743x]
...

> fixed_phy_unregister() afterwards, so you do not leak memory.
> 
> > +		if (phy_is_pseudo_fixed_link(phydev)) {
> > +			ret = phy_connect_direct(netdev, phydev,
> > +						 lan743x_virtual_phy_status_change,
> > +						 PHY_INTERFACE_MODE_MII);
> > +		} else {
> > +			ret = phy_connect_direct(netdev, phydev,
> > +						 lan743x_phy_link_status_change,
> 
> There should not be any need for a special link change
> callback. lan743x_phy_link_status_change() should work fine, the MAC
> should have no idea it is using a fixed_phy.
> 
> > +						 PHY_INTERFACE_MODE_GMII);
> > +		}
> > +
> > 
> >  		if (ret)
> >  		
> >  			goto return_error;
> >  	
> >  	}
> > 
> > @@ -1031,6 +1049,15 @@ static int lan743x_phy_open(struct lan743x_adapter
> > *adapter)> 
> >  	/* MAC doesn't support 1000T Half */
> >  	phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
> > 
> > +	if (phy_is_pseudo_fixed_link(phydev)) {
> > +		phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_TP_BIT);
> > +		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
> > +				 phydev->supported);
> > +		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
> > +				 phydev->supported);
> > +		phy_advertise_supported(phydev);
> > +	}
> 
> The fixed PHY driver will set these bits depending on the speed it has
> been configured for. No need to change them. The MAC should also not
> care if it is TP, AUI, Fibre or smoke signals.
It was to make ethtool show full set of supported speeds and MII only in
supported ports (without TP and the no any ports in the bare card).

> 
>      Andrew

I think I should reproduce the panic with clean version of net-net

--
                                Regards,
                                    Sergej.
Andrew Lunn Jan. 22, 2021, 11:23 p.m. UTC | #4
> > > @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
> > > lan743x_adapter *adapter)> 
> > >  	struct net_device *netdev = adapter->netdev;
> > >  	
> > >  	phy_stop(netdev->phydev);
> > > 
> > > -	phy_disconnect(netdev->phydev);
> > > -	netdev->phydev = NULL;
> > > +	if (phy_is_pseudo_fixed_link(netdev->phydev))
> > > +		lan743x_virtual_phy_disconnect(netdev->phydev);
> > > +	else
> > > +		phy_disconnect(netdev->phydev);
> > 
> > phy_disconnect() should work. You might want to call

There are drivers which call phy_disconnect() on a fixed_link. e.g.

https://elixir.bootlin.com/linux/v5.11-rc4/source/drivers/net/usb/lan78xx.c#L3555.

It could be your missing call to fixed_phy_unregister() is leaving
behind bad state.

> It was to make ethtool show full set of supported speeds and MII only in
> supported ports (without TP and the no any ports in the bare card).

But fixed link does not support the full set of speed. It is fixed. It
supports only one speed it is configured with.  And by setting it
wrongly, you are going to allow the user to do odd things, like use
ethtool force the link speed to a speed which is not actually
supported.

    Andrew
Sergej Bauer Jan. 22, 2021, 11:58 p.m. UTC | #5
On Saturday, January 23, 2021 2:23:25 AM MSK Andrew Lunn wrote:
> > > > @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
> > > > lan743x_adapter *adapter)>
> > > > 
> > > >  	struct net_device *netdev = adapter->netdev;
> > > >  	
> > > >  	phy_stop(netdev->phydev);
> > > > 
> > > > -	phy_disconnect(netdev->phydev);
> > > > -	netdev->phydev = NULL;
> > > > +	if (phy_is_pseudo_fixed_link(netdev->phydev))
> > > > +		lan743x_virtual_phy_disconnect(netdev->phydev);
> > > > +	else
> > > > +		phy_disconnect(netdev->phydev);
> > > 
> > > phy_disconnect() should work. You might want to call
> 
> There are drivers which call phy_disconnect() on a fixed_link. e.g.
> 
> https://elixir.bootlin.com/linux/v5.11-rc4/source/drivers/net/usb/lan78xx.c#
> L3555.
> 

> It could be your missing call to fixed_phy_unregister() is leaving
> behind bad state.
>
lan743x_virtual_phy_disconnect removes sysfs-links and calls 
fixed_phy_unregister()
and the reason was phydev in sysfs.

> > It was to make ethtool show full set of supported speeds and MII only in
> > supported ports (without TP and the no any ports in the bare card).
> 
> But fixed link does not support the full set of speed. It is fixed. It
> supports only one speed it is configured with.
That's why I "re-implemented the fixed PHY driver" as Florian said.
The goal of virtual phy was to make an illusion of real device working in
loopback mode. So I could use ethtool and ioctl's to switch speed of device.

> And by setting it
> wrongly, you are going to allow the user to do odd things, like use
> ethtool force the link speed to a speed which is not actually
> supported.
I have lan743x only and in loopback mode it allows to use speeds 
10/100/1000MBps
in full-duplex mode only. But the highest speed I have achived was something 
near
752Mbps...
And I can switch speed on the fly, without reloading the module.

May by I should limit the list of acceptable devices?

> 
>     Andrew
Florian Fainelli Jan. 23, 2021, 12:01 a.m. UTC | #6
On 1/22/2021 3:58 PM, Sergej Bauer wrote:
> On Saturday, January 23, 2021 2:23:25 AM MSK Andrew Lunn wrote:
>>>>> @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
>>>>> lan743x_adapter *adapter)>
>>>>>
>>>>>  	struct net_device *netdev = adapter->netdev;
>>>>>  	
>>>>>  	phy_stop(netdev->phydev);
>>>>>
>>>>> -	phy_disconnect(netdev->phydev);
>>>>> -	netdev->phydev = NULL;
>>>>> +	if (phy_is_pseudo_fixed_link(netdev->phydev))
>>>>> +		lan743x_virtual_phy_disconnect(netdev->phydev);
>>>>> +	else
>>>>> +		phy_disconnect(netdev->phydev);
>>>>
>>>> phy_disconnect() should work. You might want to call
>>
>> There are drivers which call phy_disconnect() on a fixed_link. e.g.
>>
>> https://elixir.bootlin.com/linux/v5.11-rc4/source/drivers/net/usb/lan78xx.c#
>> L3555.
>>
> 
>> It could be your missing call to fixed_phy_unregister() is leaving
>> behind bad state.
>>
> lan743x_virtual_phy_disconnect removes sysfs-links and calls 
> fixed_phy_unregister()
> and the reason was phydev in sysfs.
> 
>>> It was to make ethtool show full set of supported speeds and MII only in
>>> supported ports (without TP and the no any ports in the bare card).
>>
>> But fixed link does not support the full set of speed. It is fixed. It
>> supports only one speed it is configured with.
> That's why I "re-implemented the fixed PHY driver" as Florian said.
> The goal of virtual phy was to make an illusion of real device working in
> loopback mode. So I could use ethtool and ioctl's to switch speed of device.
> 
>> And by setting it
>> wrongly, you are going to allow the user to do odd things, like use
>> ethtool force the link speed to a speed which is not actually
>> supported.
> I have lan743x only and in loopback mode it allows to use speeds 
> 10/100/1000MBps
> in full-duplex mode only. But the highest speed I have achived was something 
> near
> 752Mbps...
> And I can switch speed on the fly, without reloading the module.
> 
> May by I should limit the list of acceptable devices?

It is not clear what your use case is so maybe start with explaining it
and we can help you define something that may be acceptable for upstream
inclusion.
Sergej Bauer Jan. 23, 2021, 1:01 a.m. UTC | #7
On Saturday, January 23, 2021 3:01:47 AM MSK Florian Fainelli wrote:
> On 1/22/2021 3:58 PM, Sergej Bauer wrote:
> > On Saturday, January 23, 2021 2:23:25 AM MSK Andrew Lunn wrote:
> >>>>> @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
> >>>>> lan743x_adapter *adapter)>
> >>>>> 
> >>>>>  	struct net_device *netdev = adapter->netdev;
> >>>>>  	
> >>>>>  	phy_stop(netdev->phydev);
> >>>>> 
> >>>>> -	phy_disconnect(netdev->phydev);
> >>>>> -	netdev->phydev = NULL;
> >>>>> +	if (phy_is_pseudo_fixed_link(netdev->phydev))
> >>>>> +		lan743x_virtual_phy_disconnect(netdev->phydev);
> >>>>> +	else
> >>>>> +		phy_disconnect(netdev->phydev);
> >>>> 
> >>>> phy_disconnect() should work. You might want to call
> >> 
> >> There are drivers which call phy_disconnect() on a fixed_link. e.g.
> >> 
> >> https://elixir.bootlin.com/linux/v5.11-rc4/source/drivers/net/usb/lan78xx
> >> .c# L3555.
> >> 
> >> 
> >> It could be your missing call to fixed_phy_unregister() is leaving
> >> behind bad state.
> > 
> > lan743x_virtual_phy_disconnect removes sysfs-links and calls
> > fixed_phy_unregister()
> > and the reason was phydev in sysfs.
> > 
> >>> It was to make ethtool show full set of supported speeds and MII only in
> >>> supported ports (without TP and the no any ports in the bare card).
> >> 
> >> But fixed link does not support the full set of speed. It is fixed. It
> >> supports only one speed it is configured with.
> > 
> > That's why I "re-implemented the fixed PHY driver" as Florian said.
> > The goal of virtual phy was to make an illusion of real device working in
> > loopback mode. So I could use ethtool and ioctl's to switch speed of
> > device.> 
> >> And by setting it
> >> wrongly, you are going to allow the user to do odd things, like use
> >> ethtool force the link speed to a speed which is not actually
> >> supported.
> > 
> > I have lan743x only and in loopback mode it allows to use speeds
> > 10/100/1000MBps
> > in full-duplex mode only. But the highest speed I have achived was
> > something near
> > 752Mbps...
> > And I can switch speed on the fly, without reloading the module.
> > 
> > May by I should limit the list of acceptable devices?
> 
> It is not clear what your use case is so maybe start with explaining it
> and we can help you define something that may be acceptable for upstream
> inclusion.
it migth be helpful for developers work on userspace networking tools with
PHY-less lan743x (the interface even could not be brought up)
of course, there nothing much to do without TP port but the difference is
representative.

sbauer@metamini ~$ sudo ethtool eth7
Settings for eth7:
Cannot get device settings: No such device
        Supports Wake-on: pumbag
        Wake-on: d
        Current message level: 0x00000137 (311)
                               drv probe link ifdown ifup tx_queued
        Link detected: no
sbauer@metamini ~$ sudo ifup eth7
sbauer@metamini ~$ sudo ethtool eth7
Settings for eth7:
        Supported ports: [ MII ]
        Supported link modes:   10baseT/Full 
                                100baseT/Full 
                                1000baseT/Full 
        Supported pause frame use: Symmetric Receive-only
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  10baseT/Full 
                                100baseT/Full 
                                1000baseT/Full 
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Speed: 1000Mb/s
        Duplex: Full
        Port: MII
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: pumbag
        Wake-on: d
        Current message level: 0x00000137 (311)
                               drv probe link ifdown ifup tx_queued
        Link detected: yes
sbauer@metamini ~$ sudo mii-tool -vv eth7
Using SIOCGMIIPHY=0x8947
eth7: negotiated 1000baseT-FD, link ok
  registers for MII PHY 0: 
    5140 512d 7431 0011 4140 4140 000d 0000
    0000 0200 7800 0000 0000 0000 0000 2000
    0000 0000 0000 0000 0000 0000 0000 0000
    0000 0000 0000 0000 0000 0000 0000 0000
  product info: vendor 1d:0c:40, model 1 rev 1
  basic mode:   loopback, autonegotiation enabled
  basic status: autonegotiation complete, link ok
  capabilities: 1000baseT-FD 100baseTx-FD 10baseT-FD
  advertising:  1000baseT-FD 100baseTx-FD 10baseT-FD
  link partner: 1000baseT-FD 100baseTx-FD 10baseT-FD

							   Regards,
							       Sergej.
Andrew Lunn Jan. 23, 2021, 1:32 a.m. UTC | #8
> it migth be helpful for developers work on userspace networking tools with
> PHY-less lan743x

(the interface even could not be brought up)
> of course, there nothing much to do without TP port but the difference is
> representative.
> 
> sbauer@metamini ~$ sudo ethtool eth7
> Settings for eth7:
> Cannot get device settings: No such device
>         Supports Wake-on: pumbag
>         Wake-on: d
>         Current message level: 0x00000137 (311)
>                                drv probe link ifdown ifup tx_queued
>         Link detected: no
> sbauer@metamini ~$ sudo ifup eth7
> sbauer@metamini ~$ sudo ethtool eth7
> Settings for eth7:
>         Supported ports: [ MII ]
>         Supported link modes:   10baseT/Full 
>                                 100baseT/Full 
>                                 1000baseT/Full 
>         Supported pause frame use: Symmetric Receive-only
>         Supports auto-negotiation: Yes
>         Supported FEC modes: Not reported
>         Advertised link modes:  10baseT/Full 
>                                 100baseT/Full 
>                                 1000baseT/Full 
>         Advertised pause frame use: Symmetric Receive-only
>         Advertised auto-negotiation: Yes
>         Advertised FEC modes: Not reported
>         Speed: 1000Mb/s
>         Duplex: Full
>         Port: MII
>         PHYAD: 0
>         Transceiver: internal
>         Auto-negotiation: on
>         Supports Wake-on: pumbag
>         Wake-on: d
>         Current message level: 0x00000137 (311)
>                                drv probe link ifdown ifup tx_queued
>         Link detected: yes
> sbauer@metamini ~$ sudo mii-tool -vv eth7
> Using SIOCGMIIPHY=0x8947
> eth7: negotiated 1000baseT-FD, link ok
>   registers for MII PHY 0: 
>     5140 512d 7431 0011 4140 4140 000d 0000
>     0000 0200 7800 0000 0000 0000 0000 2000
>     0000 0000 0000 0000 0000 0000 0000 0000
>     0000 0000 0000 0000 0000 0000 0000 0000
>   product info: vendor 1d:0c:40, model 1 rev 1
>   basic mode:   loopback, autonegotiation enabled
>   basic status: autonegotiation complete, link ok
>   capabilities: 1000baseT-FD 100baseTx-FD 10baseT-FD
>   advertising:  1000baseT-FD 100baseTx-FD 10baseT-FD
>   link partner: 1000baseT-FD 100baseTx-FD 10baseT-FD

You have not shown anything i cannot do with the ethernet interfaces i
have in my laptop. And since ethtool is pretty standardized, what
lan743x offers should be pretty much the same as any 1G Ethernet MAC
using most 1G PHYs.

      Andrew
Florian Fainelli Jan. 23, 2021, 1:39 a.m. UTC | #9
On 1/22/2021 5:01 PM, Sergej Bauer wrote:
> On Saturday, January 23, 2021 3:01:47 AM MSK Florian Fainelli wrote:
>> On 1/22/2021 3:58 PM, Sergej Bauer wrote:
>>> On Saturday, January 23, 2021 2:23:25 AM MSK Andrew Lunn wrote:
>>>>>>> @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
>>>>>>> lan743x_adapter *adapter)>
>>>>>>>
>>>>>>>  	struct net_device *netdev = adapter->netdev;
>>>>>>>  	
>>>>>>>  	phy_stop(netdev->phydev);
>>>>>>>
>>>>>>> -	phy_disconnect(netdev->phydev);
>>>>>>> -	netdev->phydev = NULL;
>>>>>>> +	if (phy_is_pseudo_fixed_link(netdev->phydev))
>>>>>>> +		lan743x_virtual_phy_disconnect(netdev->phydev);
>>>>>>> +	else
>>>>>>> +		phy_disconnect(netdev->phydev);
>>>>>>
>>>>>> phy_disconnect() should work. You might want to call
>>>>
>>>> There are drivers which call phy_disconnect() on a fixed_link. e.g.
>>>>
>>>> https://elixir.bootlin.com/linux/v5.11-rc4/source/drivers/net/usb/lan78xx
>>>> .c# L3555.
>>>>
>>>>
>>>> It could be your missing call to fixed_phy_unregister() is leaving
>>>> behind bad state.
>>>
>>> lan743x_virtual_phy_disconnect removes sysfs-links and calls
>>> fixed_phy_unregister()
>>> and the reason was phydev in sysfs.
>>>
>>>>> It was to make ethtool show full set of supported speeds and MII only in
>>>>> supported ports (without TP and the no any ports in the bare card).
>>>>
>>>> But fixed link does not support the full set of speed. It is fixed. It
>>>> supports only one speed it is configured with.
>>>
>>> That's why I "re-implemented the fixed PHY driver" as Florian said.
>>> The goal of virtual phy was to make an illusion of real device working in
>>> loopback mode. So I could use ethtool and ioctl's to switch speed of
>>> device.> 
>>>> And by setting it
>>>> wrongly, you are going to allow the user to do odd things, like use
>>>> ethtool force the link speed to a speed which is not actually
>>>> supported.
>>>
>>> I have lan743x only and in loopback mode it allows to use speeds
>>> 10/100/1000MBps
>>> in full-duplex mode only. But the highest speed I have achived was
>>> something near
>>> 752Mbps...
>>> And I can switch speed on the fly, without reloading the module.
>>>
>>> May by I should limit the list of acceptable devices?
>>
>> It is not clear what your use case is so maybe start with explaining it
>> and we can help you define something that may be acceptable for upstream
>> inclusion.
> it migth be helpful for developers work on userspace networking tools with
> PHY-less lan743x (the interface even could not be brought up)
> of course, there nothing much to do without TP port but the difference is
> representative.

You are still not explaining why fixed PHY is not a suitable emulation
and what is different, providing the output of ethtool does not tell me
how you are using it.

Literally everyone using Ethernet switches or MAC to MAC Ethernet
connections uses fixed PHY and is reasonably happy with it.
Sergej Bauer Jan. 23, 2021, 4:01 a.m. UTC | #10
resending answer to all:
On Saturday, January 23, 2021 4:32:38 AM MSK Andrew Lunn wrote:
> > it migth be helpful for developers work on userspace networking tools with
> > PHY-less lan743x
> 
> (the interface even could not be brought up)
> 
> > of course, there nothing much to do without TP port but the difference is
> > representative.
> > 
> > sbauer@metamini ~$ sudo ethtool eth7
> > Settings for eth7:
> > Cannot get device settings: No such device
> > 
> >         Supports Wake-on: pumbag
> >         Wake-on: d
> >         Current message level: 0x00000137 (311)
> >         
> >                                drv probe link ifdown ifup tx_queued
> >         
> >         Link detected: no
> > 
> > sbauer@metamini ~$ sudo ifup eth7
> > sbauer@metamini ~$ sudo ethtool eth7
> > 
> > Settings for eth7:
> >         Supported ports: [ MII ]
> >         Supported link modes:   10baseT/Full
> >         
> >                                 100baseT/Full
> >                                 1000baseT/Full
> >         
> >         Supported pause frame use: Symmetric Receive-only
> >         Supports auto-negotiation: Yes
> >         Supported FEC modes: Not reported
> >         Advertised link modes:  10baseT/Full
> >         
> >                                 100baseT/Full
> >                                 1000baseT/Full
> >         
> >         Advertised pause frame use: Symmetric Receive-only
> >         Advertised auto-negotiation: Yes
> >         Advertised FEC modes: Not reported
> >         Speed: 1000Mb/s
> >         Duplex: Full
> >         Port: MII
> >         PHYAD: 0
> >         Transceiver: internal
> >         Auto-negotiation: on
> >         Supports Wake-on: pumbag
> >         Wake-on: d
> >         Current message level: 0x00000137 (311)
> >         
> >                                drv probe link ifdown ifup tx_queued
> >         
> >         Link detected: yes
> > 
> > sbauer@metamini ~$ sudo mii-tool -vv eth7
> > Using SIOCGMIIPHY=0x8947
> > eth7: negotiated 1000baseT-FD, link ok
> > 
> >   registers for MII PHY 0:
> >     5140 512d 7431 0011 4140 4140 000d 0000
> >     0000 0200 7800 0000 0000 0000 0000 2000
> >     0000 0000 0000 0000 0000 0000 0000 0000
> >     0000 0000 0000 0000 0000 0000 0000 0000
> >   
> >   product info: vendor 1d:0c:40, model 1 rev 1
> >   basic mode:   loopback, autonegotiation enabled
> >   basic status: autonegotiation complete, link ok
> >   capabilities: 1000baseT-FD 100baseTx-FD 10baseT-FD
> >   advertising:  1000baseT-FD 100baseTx-FD 10baseT-FD
> >   link partner: 1000baseT-FD 100baseTx-FD 10baseT-FD
> 
> You have not shown anything i cannot do with the ethernet interfaces i
> have in my laptop. And since ethtool is pretty standardized, what
> lan743x offers should be pretty much the same as any 1G Ethernet MAC
> using most 1G PHYs.
> 
>       Andrew

Andrew, I can reproduce segfault with following changes:
sbauer@metamini ~/devel/kernel-works/net-next.git master$ git diff .
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/
ethernet/microchip/lan743x_main.c
index 3804310c853a..6e2961f47211 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -1001,6 +1001,8 @@ static void lan743x_phy_close(struct lan743x_adapter 
*adapter)
 
        phy_stop(netdev->phydev);
        phy_disconnect(netdev->phydev);
+       if (phy_is_pseudo_fixed_link(netdev->phydev))
+               fixed_phy_unregister(netdev->phydev);
        netdev->phydev = NULL;
 }
 
@@ -1018,9 +1020,21 @@ static int lan743x_phy_open(struct lan743x_adapter 
*adapter)
        if (!phydev) {
                /* try internal phy */
                phydev = phy_find_first(adapter->mdiobus);
-               if (!phydev)
-                       goto return_error;
-
+               if (!phydev) {
+                       struct fixed_phy_status status = {
+                               .link = 1,
+                               .speed = SPEED_1000,
+                               .duplex = DUPLEX_FULL,
+                               .asym_pause = 1,
+                       };
+
+                       phydev = fixed_phy_register(PHY_POLL, &status, NULL);
+                       if (!phydev || IS_ERR(phydev)) {
+                               netif_err(adapter, probe, netdev,
+                                         "Failed to register fixed PHY 
device\n");
+                               goto return_error;
+                       }
+               }
                ret = phy_connect_direct(netdev, phydev,
                                         lan743x_phy_link_status_change,
                                         PHY_INTERFACE_MODE_GMII);

sbauer@metamini ~/devel/kernel-works/net-next.git master$ sudo modprobe 
lan743x
sbauer@metamini ~/devel/kernel-works/net-next.git master$ sudo ifup eth7
sbauer@metamini ~/devel/kernel-works/net-next.git master$ ethtool eth7
Settings for eth7:
        Supported ports: [ TP MII ]
        Supported link modes:   1000baseT/Full 
        Supported pause frame use: Symmetric Receive-only
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  1000baseT/Full 
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Speed: 1000Mb/s
        Duplex: Full
        Port: MII
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
Cannot get wake-on-lan settings: Operation not permitted
        Current message level: 0x00000137 (311)
                               drv probe link ifdown ifup tx_queued
        Link detected: yes
sbauer@metamini ~/devel/kernel-works/net-next.git master$ sudo ifdown eth7
Killed
---

dmesg:
[  365.856455] lan743x 0000:06:00.0 eth7: Link is Down
[  365.856542] BUG: kernel NULL pointer dereference, address: 00000000000003c4
[  365.856611] #PF: supervisor read access in kernel mode
[  365.856705] #PF: error_code(0x0000) - not-present page
[  365.856772] PGD 0 P4D 0 
[  365.856832] Oops: 0000 [#1] SMP NOPTI
[  365.856898] CPU: 0 PID: 21779 Comm: ip Tainted: G           O      5.11.0-
rc4net-next+ #4
[  365.857018] Hardware name: Gigabyte Technology Co., Ltd. H110-D3/H110-D3-
CF, BIOS F24 04/11/2018
[  365.857111] RIP: 0010:lan743x_phy_close.isra.26+0x28/0x50 [lan743x]
[  365.857208] Code: c3 90 0f 1f 44 00 00 53 48 89 fb 48 8b bf 28 08 00 00 e8 
ab 3e da ff 48 8b bb 28 08 00 00 e8 bf 67 da ff 48 8b bb 28 08 00 00 <f6> 87 c4 
03 00 00 04 75 0d 48 c7 83 28 08 00 00 00 00 00 00 5b c3
[  365.857332] RSP: 0018:ffffb6560468b508 EFLAGS: 00010246
[  365.857397] RAX: 0000000000000003 RBX: ffff8cfacbe30000 RCX: 0000000000000000
[  365.857466] RDX: ffffffffc00ae2d8 RSI: 0000000000000001 RDI: 0000000000000000
[  365.857537] RBP: 0000000000000008 R08: 0000000000000000 R09: ffffffffb2d6dee0
[  365.857632] R10: ffff8cfb45f69bff R11: ffff8cfb057c829b R12: ffff8cfacbe308c0
[  365.857697] R13: ffff8cfacbe310b8 R14: ffff8cfacbe31050 R15: ffff8cfacbe308c0
[  365.857762] FS:  00007f4318318e40(0000) GS:ffff8cfbf6c00000(0000) knlGS:
0000000000000000
[  365.857844] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  365.857907] CR2: 00000000000003c4 CR3: 0000000145a80001 CR4: 
00000000003706f0
[  365.857972] Call Trace:
[  365.858029]  lan743x_netdev_close+0x223/0x250 [lan743x]
[  365.858094]  __dev_close_many+0x96/0x100
[  365.858170]  __dev_change_flags+0xdc/0x210
[  365.858264]  dev_change_flags+0x21/0x60
[  365.858325]  do_setlink+0x347/0x10e0
[  365.858385]  ? __nla_validate_parse+0x5f/0xaf0
[  365.858447]  __rtnl_newlink+0x541/0x8d0
[  365.858508]  ? get_page_from_freelist+0x1194/0x1310
[  365.858574]  ? mutex_spin_on_owner+0x5c/0xb0
[  365.858635]  ? __mutex_lock.isra.9+0x46e/0x4b0
[  365.858696]  ? asm_exc_page_fault+0x1e/0x30
[  365.858757]  rtnl_newlink+0x43/0x60
[  365.858817]  rtnetlink_rcv_msg+0x134/0x380
[  365.858878]  ? _cond_resched+0x15/0x30
[  365.858937]  ? kmem_cache_alloc+0x3cf/0x7d0
[  365.858997]  ? rtnl_calcit.isra.38+0x110/0x110
[  365.859058]  netlink_rcv_skb+0x50/0x100
[  365.859118]  netlink_unicast+0x1a5/0x280
[  365.859178]  netlink_sendmsg+0x23d/0x470
[  365.859237]  sock_sendmsg+0x5b/0x60
[  365.859298]  ____sys_sendmsg+0x1ef/0x260
[  365.859358]  ? copy_msghdr_from_user+0x5c/0x90
[  365.859418]  ? mntput_no_expire+0x47/0x240
[  365.859478]  ___sys_sendmsg+0x7c/0xc0
[  365.859537]  ? tomoyo_path_number_perm+0x68/0x1e0
[  365.859600]  ? __sk_destruct+0x129/0x1b0
[  365.859660]  ? var_wake_function+0x20/0x20
[  365.859720]  ? fsnotify_grab_connector+0x46/0x80
[  365.859782]  __sys_sendmsg+0x57/0xa0
[  365.859841]  do_syscall_64+0x33/0x80
[  365.859900]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
--- 
(gdb) l *lan743x_netdev_close+0x223
0x1f43 is in lan743x_netdev_close (drivers/net/ethernet/microchip//
lan743x_main.c:2521).
2516
2517            lan743x_ptp_close(adapter);
2518
2519            lan743x_phy_close(adapter);
2520
2521            lan743x_mac_close(adapter);
2522
2523            lan743x_intr_close(adapter);
2524
2525            return 0;
(gdb)
Sergej Bauer Jan. 25, 2021, 8:57 a.m. UTC | #11
On Saturday, January 23, 2021 4:32:38 AM MSK Andrew Lunn wrote:
> > it migth be helpful for developers work on userspace networking tools with
> > PHY-less lan743x
> 
> (the interface even could not be brought up)
> 
> > of course, there nothing much to do without TP port but the difference is
> > representative.
> > 
> > sbauer@metamini ~$ sudo ethtool eth7
> > Settings for eth7:
> > Cannot get device settings: No such device
> > 
> >         Supports Wake-on: pumbag
> >         Wake-on: d
> >         Current message level: 0x00000137 (311)
> >         
> >                                drv probe link ifdown ifup tx_queued
> >         
> >         Link detected: no
> > 
> > sbauer@metamini ~$ sudo ifup eth7
> > sbauer@metamini ~$ sudo ethtool eth7
> > 
> > Settings for eth7:
> >         Supported ports: [ MII ]
> >         Supported link modes:   10baseT/Full
> >         
> >                                 100baseT/Full
> >                                 1000baseT/Full
> >         
> >         Supported pause frame use: Symmetric Receive-only
> >         Supports auto-negotiation: Yes
> >         Supported FEC modes: Not reported
> >         Advertised link modes:  10baseT/Full
> >         
> >                                 100baseT/Full
> >                                 1000baseT/Full
> >         
> >         Advertised pause frame use: Symmetric Receive-only
> >         Advertised auto-negotiation: Yes
> >         Advertised FEC modes: Not reported
> >         Speed: 1000Mb/s
> >         Duplex: Full
> >         Port: MII
> >         PHYAD: 0
> >         Transceiver: internal
> >         Auto-negotiation: on
> >         Supports Wake-on: pumbag
> >         Wake-on: d
> >         Current message level: 0x00000137 (311)
> >         
> >                                drv probe link ifdown ifup tx_queued
> >         
> >         Link detected: yes
> > 
> > sbauer@metamini ~$ sudo mii-tool -vv eth7
> > Using SIOCGMIIPHY=0x8947
> > eth7: negotiated 1000baseT-FD, link ok
> > 
> >   registers for MII PHY 0:
> >     5140 512d 7431 0011 4140 4140 000d 0000
> >     0000 0200 7800 0000 0000 0000 0000 2000
> >     0000 0000 0000 0000 0000 0000 0000 0000
> >     0000 0000 0000 0000 0000 0000 0000 0000
> >   
> >   product info: vendor 1d:0c:40, model 1 rev 1
> >   basic mode:   loopback, autonegotiation enabled
> >   basic status: autonegotiation complete, link ok
> >   capabilities: 1000baseT-FD 100baseTx-FD 10baseT-FD
> >   advertising:  1000baseT-FD 100baseTx-FD 10baseT-FD
> >   link partner: 1000baseT-FD 100baseTx-FD 10baseT-FD
> 
> You have not shown anything i cannot do with the ethernet interfaces i
> have in my laptop. And since ethtool is pretty standardized, what
> lan743x offers should be pretty much the same as any 1G Ethernet MAC
> using most 1G PHYs.
> 
>       Andrew

Andrew, for this moment with lan743x we can get only this:
sbauer@metamini ~/devel/kernel-works/net-next.git master$ sudo ethtool eth7
Settings for eth7:
Cannot get device settings: No such device
        Supports Wake-on: pumbag
        Wake-on: d
        Current message level: 0x00000137 (311)
                               drv probe link ifdown ifup tx_queued
        Link detected: no
sbauer@metamini ~/devel/kernel-works/net-next.git master$ sudo mii-tool -vv 
eth7
Using SIOCGMIIPHY=0x8947
SIOCGMIIPHY on 'eth7' failed: Invalid argument
Sergej Bauer Jan. 25, 2021, 8:57 a.m. UTC | #12
On Saturday, January 23, 2021 4:39:47 AM MSK Florian Fainelli wrote:
> On 1/22/2021 5:01 PM, Sergej Bauer wrote:
> > On Saturday, January 23, 2021 3:01:47 AM MSK Florian Fainelli wrote:
> >> On 1/22/2021 3:58 PM, Sergej Bauer wrote:
> >>> On Saturday, January 23, 2021 2:23:25 AM MSK Andrew Lunn wrote:
> >>>>>>> @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
> >>>>>>> lan743x_adapter *adapter)>
> >>>>>>> 
> >>>>>>>  	struct net_device *netdev = adapter->netdev;
> >>>>>>>  	
> >>>>>>>  	phy_stop(netdev->phydev);
> >>>>>>> 
> >>>>>>> -	phy_disconnect(netdev->phydev);
> >>>>>>> -	netdev->phydev = NULL;
> >>>>>>> +	if (phy_is_pseudo_fixed_link(netdev->phydev))
> >>>>>>> +		lan743x_virtual_phy_disconnect(netdev->phydev);
> >>>>>>> +	else
> >>>>>>> +		phy_disconnect(netdev->phydev);
> >>>>>> 
> >>>>>> phy_disconnect() should work. You might want to call
> >>>> 
> >>>> There are drivers which call phy_disconnect() on a fixed_link. e.g.
> >>>> 
> >>>> https://elixir.bootlin.com/linux/v5.11-rc4/source/drivers/net/usb/lan78
> >>>> xx
> >>>> .c# L3555.
> >>>> 
> >>>> 
> >>>> It could be your missing call to fixed_phy_unregister() is leaving
> >>>> behind bad state.
> >>> 
> >>> lan743x_virtual_phy_disconnect removes sysfs-links and calls
> >>> fixed_phy_unregister()
> >>> and the reason was phydev in sysfs.
> >>> 
> >>>>> It was to make ethtool show full set of supported speeds and MII only
> >>>>> in
> >>>>> supported ports (without TP and the no any ports in the bare card).
> >>>> 
> >>>> But fixed link does not support the full set of speed. It is fixed. It
> >>>> supports only one speed it is configured with.
> >>> 
> >>> That's why I "re-implemented the fixed PHY driver" as Florian said.
> >>> The goal of virtual phy was to make an illusion of real device working
> >>> in
> >>> loopback mode. So I could use ethtool and ioctl's to switch speed of
> >>> device.>
> >>> 
> >>>> And by setting it
> >>>> wrongly, you are going to allow the user to do odd things, like use
> >>>> ethtool force the link speed to a speed which is not actually
> >>>> supported.
> >>> 
> >>> I have lan743x only and in loopback mode it allows to use speeds
> >>> 10/100/1000MBps
> >>> in full-duplex mode only. But the highest speed I have achived was
> >>> something near
> >>> 752Mbps...
> >>> And I can switch speed on the fly, without reloading the module.
> >>> 
> >>> May by I should limit the list of acceptable devices?
> >> 
> >> It is not clear what your use case is so maybe start with explaining it
> >> and we can help you define something that may be acceptable for upstream
> >> inclusion.
> > 
> > it migth be helpful for developers work on userspace networking tools with
> > PHY-less lan743x (the interface even could not be brought up)
> > of course, there nothing much to do without TP port but the difference is
> > representative.
> 
> You are still not explaining why fixed PHY is not a suitable emulation
> and what is different, providing the output of ethtool does not tell me
> how you are using it.
> 
> Literally everyone using Ethernet switches or MAC to MAC Ethernet
> connections uses fixed PHY and is reasonably happy with it.

Florian, the key idea is to make virtual phy device which acts as real 802.11
standard  phy.

original fixed_phy and swphy are little bit useless as they do not support
write operation. in contrast of them virtual_phy supports write to all
registers. and can change the speed of interface by means of SIOCSMIIREG ioctl
call either ethtool.
changing of appropriate bits in register 0 will change speed reflecting in 
ethtool
and vise versa.
Sergej Bauer Jan. 25, 2021, 10:23 a.m. UTC | #13
On Saturday, January 23, 2021 2:23:25 AM MSK Andrew Lunn wrote:
> > > > @@ -1000,8 +1005,10 @@ static void lan743x_phy_close(struct
> > > > lan743x_adapter *adapter)>
> > > > 
> > > >  	struct net_device *netdev = adapter->netdev;
> > > >  	
> > > >  	phy_stop(netdev->phydev);
> > > > 
> > > > -	phy_disconnect(netdev->phydev);
> > > > -	netdev->phydev = NULL;
> > > > +	if (phy_is_pseudo_fixed_link(netdev->phydev))
> > > > +		lan743x_virtual_phy_disconnect(netdev->phydev);
> > > > +	else
> > > > +		phy_disconnect(netdev->phydev);
> > > 
> > > phy_disconnect() should work. You might want to call
> 
> There are drivers which call phy_disconnect() on a fixed_link. e.g.
> 
> https://elixir.bootlin.com/linux/v5.11-rc4/source/drivers/net/usb/lan78xx.c#
> L3555.
> 
> It could be your missing call to fixed_phy_unregister() is leaving
> behind bad state.
> 
fixed_phy_unregister() were inside of lan743x_virtual_phy_disconnect()

> > It was to make ethtool show full set of supported speeds and MII only in
> > supported ports (without TP and the no any ports in the bare card).
> 
> But fixed link does not support the full set of speed. It is fixed. It
> supports only one speed it is configured with.  And by setting it
> wrongly, you are going to allow the user to do odd things, like use
> ethtool force the link speed to a speed which is not actually
> supported.
when writing virtual phy i have used "Microchip AN2948 Configuration Registers
of LAN743x" document and the lan743x is designed only for LAN7430 either
LAN7431 as it pointed in the document and in lan743x_pcidev_tbl. which both
support speeds 10/100/1000 Mbps.
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 650deb973913..86304efd7691 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11699,6 +11699,12 @@  L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/ethernet/microchip/lan743x_*
 
+MICROCHIP LAN743X VIRTUAL PHY
+M:	Sergej Bauer <sbauer@blackbox.su>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/ethernet/microchip/lan743x_virtual_phy.*
+
 MICROCHIP LCDFB DRIVER
 M:	Nicolas Ferre <nicolas.ferre@microchip.com>
 L:	linux-fbdev@vger.kernel.org
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index d0f6dfe0dcf3..fbc94cf115bd 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -48,6 +48,7 @@  config LAN743X
 	select PHYLIB
 	select CRC16
 	select CRC32
+	select FIXED_PHY
 	help
 	  Support for the Microchip LAN743x PCI Express Gigabit Ethernet chip
 
diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index da603540ca57..dc3a2d66c286 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -7,4 +7,4 @@  obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_ENCX24J600) += encx24j600.o encx24j600-regmap.o
 obj-$(CONFIG_LAN743X) += lan743x.o
 
-lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
+lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o lan743x_virtual_phy.o
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index c5de8f46cdd3..22636366d0db 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -816,6 +816,17 @@  static int lan743x_ethtool_set_wol(struct net_device *netdev,
 }
 #endif /* CONFIG_PM */
 
+int lan743x_set_link_ksettings(struct net_device *netdev,
+			       const struct ethtool_link_ksettings *cmd)
+{
+	if (!netdev->phydev)
+		return -ENETDOWN;
+
+	return phy_is_pseudo_fixed_link(netdev->phydev) ?
+			lan743x_set_virtual_link_ksettings(netdev, cmd)
+			: phy_ethtool_set_link_ksettings(netdev, cmd);
+}
+
 const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_drvinfo = lan743x_ethtool_get_drvinfo,
 	.get_msglevel = lan743x_ethtool_get_msglevel,
@@ -839,7 +850,7 @@  const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_eee = lan743x_ethtool_get_eee,
 	.set_eee = lan743x_ethtool_set_eee,
 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
-	.set_link_ksettings = phy_ethtool_set_link_ksettings,
+	.set_link_ksettings = lan743x_set_link_ksettings,
 #ifdef CONFIG_PM
 	.get_wol = lan743x_ethtool_get_wol,
 	.set_wol = lan743x_ethtool_set_wol,
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.h b/drivers/net/ethernet/microchip/lan743x_ethtool.h
index d0d11a777a58..7287474d4a5c 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.h
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.h
@@ -8,4 +8,7 @@ 
 
 extern const struct ethtool_ops lan743x_ethtool_ops;
 
+int lan743x_set_virtual_link_ksettings(struct net_device *netdev,
+				       const struct ethtool_link_ksettings *cmd);
+
 #endif /* _LAN743X_ETHTOOL_H */
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 3804310c853a..d8c00fa298d0 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -17,6 +17,11 @@ 
 #include <linux/crc16.h>
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
+#include "lan743x_virtual_phy.h"
+
+static char *mii_regs[32];
+static int mii_regs_count;
+module_param_array(mii_regs, charp, &mii_regs_count, 0644);
 
 static void lan743x_pci_cleanup(struct lan743x_adapter *adapter)
 {
@@ -821,7 +826,7 @@  static int lan743x_mac_init(struct lan743x_adapter *adapter)
 	return 0;
 }
 
-static int lan743x_mac_open(struct lan743x_adapter *adapter)
+int lan743x_mac_open(struct lan743x_adapter *adapter)
 {
 	u32 temp;
 
@@ -832,7 +837,7 @@  static int lan743x_mac_open(struct lan743x_adapter *adapter)
 	return 0;
 }
 
-static void lan743x_mac_close(struct lan743x_adapter *adapter)
+void lan743x_mac_close(struct lan743x_adapter *adapter)
 {
 	u32 temp;
 
@@ -1000,8 +1005,10 @@  static void lan743x_phy_close(struct lan743x_adapter *adapter)
 	struct net_device *netdev = adapter->netdev;
 
 	phy_stop(netdev->phydev);
-	phy_disconnect(netdev->phydev);
-	netdev->phydev = NULL;
+	if (phy_is_pseudo_fixed_link(netdev->phydev))
+		lan743x_virtual_phy_disconnect(netdev->phydev);
+	else
+		phy_disconnect(netdev->phydev);
 }
 
 static int lan743x_phy_open(struct lan743x_adapter *adapter)
@@ -1019,11 +1026,22 @@  static int lan743x_phy_open(struct lan743x_adapter *adapter)
 		/* try internal phy */
 		phydev = phy_find_first(adapter->mdiobus);
 		if (!phydev)
+			phydev = lan743x_virtual_phy(adapter, mii_regs,
+						     mii_regs_count);
+
+		if (!phydev || IS_ERR(phydev))
 			goto return_error;
 
-		ret = phy_connect_direct(netdev, phydev,
-					 lan743x_phy_link_status_change,
-					 PHY_INTERFACE_MODE_GMII);
+		if (phy_is_pseudo_fixed_link(phydev)) {
+			ret = phy_connect_direct(netdev, phydev,
+						 lan743x_virtual_phy_status_change,
+						 PHY_INTERFACE_MODE_MII);
+		} else {
+			ret = phy_connect_direct(netdev, phydev,
+						 lan743x_phy_link_status_change,
+						 PHY_INTERFACE_MODE_GMII);
+		}
+
 		if (ret)
 			goto return_error;
 	}
@@ -1031,6 +1049,15 @@  static int lan743x_phy_open(struct lan743x_adapter *adapter)
 	/* MAC doesn't support 1000T Half */
 	phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
 
+	if (phy_is_pseudo_fixed_link(phydev)) {
+		phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_TP_BIT);
+		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+				 phydev->supported);
+		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+				 phydev->supported);
+		phy_advertise_supported(phydev);
+	}
+
 	/* support both flow controls */
 	phy_support_asym_pause(phydev);
 	phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
@@ -2580,11 +2607,20 @@  static netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb,
 static int lan743x_netdev_ioctl(struct net_device *netdev,
 				struct ifreq *ifr, int cmd)
 {
+	int ret;
+
 	if (!netif_running(netdev))
 		return -EINVAL;
+
 	if (cmd == SIOCSHWTSTAMP)
 		return lan743x_ptp_ioctl(netdev, ifr, cmd);
-	return phy_mii_ioctl(netdev->phydev, ifr, cmd);
+
+	if (phy_is_pseudo_fixed_link(netdev->phydev))
+		ret = lan743x_virtual_phy_mii_ioctl(netdev->phydev, ifr, cmd);
+	else
+		ret = phy_mii_ioctl(netdev->phydev, ifr, cmd);
+
+	return ret;
 }
 
 static void lan743x_netdev_set_multicast(struct net_device *netdev)
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 404af3f4635e..8e16fd0f166a 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -109,6 +109,7 @@ 
 #define MAC_CR_EEE_EN_			BIT(17)
 #define MAC_CR_ADD_			BIT(12)
 #define MAC_CR_ASD_			BIT(11)
+#define MAC_CR_INT_LOOPBACK_		BIT(10)
 #define MAC_CR_CNTR_RST_		BIT(5)
 #define MAC_CR_DPX_			BIT(3)
 #define MAC_CR_CFG_H_			BIT(2)
diff --git a/drivers/net/ethernet/microchip/lan743x_virtual_phy.c b/drivers/net/ethernet/microchip/lan743x_virtual_phy.c
new file mode 100644
index 000000000000..b6bf7c016448
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_virtual_phy.c
@@ -0,0 +1,335 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2021 Sergej Bauer
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+#include "lan743x_main.h"
+#include "lan743x_ethtool.h"
+#include "lan743x_virtual_phy.h"
+
+static u16 regs802p3[32];
+
+int lan743x_virtual_phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr,
+				  int cmd)
+{
+	struct ethtool_link_ksettings ksettings;
+	struct net_device *netdev = phydev->attached_dev;
+	struct mii_ioctl_data *mii_data = if_mii(ifr);
+	int ret = 0;
+	u16 val = mii_data->val_in;
+	u16 reg_num = mii_data->reg_num;
+
+	if (reg_num > 0x1f)
+		return -ERANGE;
+
+	memset(&ksettings, 0, sizeof(ksettings));
+	phy_ethtool_get_link_ksettings(netdev, &ksettings);
+	ksettings.base.autoneg = AUTONEG_ENABLE;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		break;
+	case SIOCGMIIREG:
+		mii_data->val_out = regs802p3[reg_num];
+		break;
+	case SIOCSMIIREG:
+		switch (reg_num) {
+		case MII_BMCR:
+			val &= ~BMCR_RESET;
+			if (!(val & BMCR_FULLDPLX))
+				val |= BMCR_FULLDPLX;
+			val &= ~0x1f;
+
+			if (val & BMCR_ANRESTART)
+				val &= ~BMCR_ANRESTART;
+
+			if ((val & BMCR_SPEED1000) && (val & BMCR_SPEED100)) {
+				ret = -EINVAL;
+				netdev_err(netdev, "invalid bits 0.6 and 0.13");
+				break;
+			}
+
+			ksettings.base.duplex = DUPLEX_FULL;
+
+			if (val & BMCR_SPEED1000)
+				ksettings.base.speed = SPEED_1000;
+			else if (val & BMCR_SPEED100)
+				ksettings.base.speed = SPEED_100;
+			else
+				ksettings.base.speed = SPEED_10;
+
+			break;
+
+		case 1:
+		case 2:
+		case 3:
+		case 15:
+		default:
+			regs802p3[reg_num] = val;
+			break;
+		}
+		ret = lan743x_set_virtual_link_ksettings(netdev, &ksettings);
+		if (ret == 0)
+			regs802p3[reg_num] = val;
+
+		break;
+	default:
+		netdev_err(netdev, "not supported ioctl %X\n", cmd);
+		ret = -EOPNOTSUPP;
+	};
+
+	return ret;
+}
+
+void lan743x_virtual_phy_disconnect(struct phy_device *phydev)
+{
+	struct net_device *attached_dev = phydev->attached_dev;
+
+	if (phydev->sysfs_links) {
+		if (phydev->attached_dev)
+			sysfs_remove_link(&attached_dev->dev.kobj,
+					  "phydev");
+		sysfs_remove_link(&phydev->mdio.dev.kobj,
+				  "attached_dev");
+	}
+
+	fixed_phy_unregister(phydev);
+}
+
+void lan743x_virtual_phy_status_change(struct net_device *netdev)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	struct phy_device *phydev = netdev->phydev;
+	u32 data;
+
+	if (!netdev->phydev)
+		return;
+
+	if (phydev->state == PHY_RUNNING) {
+		data = lan743x_csr_read(adapter, MAC_CR);
+		data |= MAC_CR_INT_LOOPBACK_;
+		data &= ~MAC_CR_MII_EN_;
+		data |= MAC_CR_DPX_;
+
+		switch (phydev->speed) {
+		case SPEED_10:
+			data &= ~MAC_CR_CFG_H_;
+			data &= ~MAC_CR_CFG_L_;
+		break;
+		case SPEED_100:
+			data &= ~MAC_CR_CFG_H_;
+			data |= MAC_CR_CFG_L_;
+		break;
+		case SPEED_1000:
+			data |= MAC_CR_CFG_H_;
+			data &= ~MAC_CR_CFG_L_;
+		break;
+		}
+		lan743x_csr_write(adapter, MAC_CR, data);
+	}
+	phy_print_status(phydev);
+}
+
+struct phy_device *lan743x_virtual_phy(struct lan743x_adapter *adapter,
+				       char *mii_regs[], int mii_regs_count)
+{
+	struct phy_device *phydev = NULL;
+	struct net_device *netdev = adapter->netdev;
+	struct mii_ioctl_data mii_data;
+	struct ifreq ifr;
+	long res;
+	int ret, i;
+
+	struct fixed_phy_status status = {
+		.link = 1,
+		.speed = SPEED_1000,
+		.duplex = DUPLEX_FULL,
+		.asym_pause = 1,
+	};
+
+	phydev = fixed_phy_register(PHY_POLL, &status, NULL);
+	if (!phydev || IS_ERR(phydev)) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "failed to regiter fixed_phy\n");
+		goto out;
+	}
+	phydev->attached_dev = netdev;
+	netdev->phydev = phydev;
+
+	linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+			   phydev->supported);
+	linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+			   phydev->supported);
+	linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+			   phydev->supported);
+
+	if (mii_regs_count > 0) {
+		for (i = 0; i < mii_regs_count; i++) {
+			mii_data.reg_num = i;
+			ret = kstrtol(mii_regs[i], 16, &res);
+
+			if (ret == 0)
+				mii_data.val_in = res;
+			else
+				mii_data.val_in = 0xffff;
+
+			memcpy(&ifr.ifr_ifru.ifru_data, &mii_data,
+			       sizeof(mii_data));
+			ret = lan743x_virtual_phy_mii_ioctl(phydev, &ifr,
+							    SIOCSMIIREG);
+			if (ret < 0)
+				return NULL;
+		}
+	} else {
+		mii_data.reg_num = MII_BMSR;
+		mii_data.val_in = BMSR_100FULL | BMSR_10FULL | BMSR_ESTATEN |
+			BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS |
+			BMSR_ERCAP;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_PHYSID1;
+		mii_data.val_in = (adapter->csr.id_rev & ID_REV_ID_MASK_) >> 16;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_PHYSID2;
+		mii_data.val_in = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_ADVERTISE;
+		mii_data.val_in = ADVERTISE_100FULL | ADVERTISE_10FULL |
+			ADVERTISE_LPACK;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_LPA;
+		mii_data.val_in = ADVERTISE_100FULL | ADVERTISE_10FULL |
+			ADVERTISE_LPACK;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_EXPANSION;
+		mii_data.val_in = EXPANSION_NWAY | EXPANSION_ENABLENPAGE |
+			EXPANSION_NPCAPABLE;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_CTRL1000;
+		mii_data.val_in = ADVERTISE_1000FULL;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_STAT1000;
+		mii_data.val_in = LPA_1000FULL | LPA_1000REMRXOK |
+			LPA_1000LOCALRXOK | LPA_1000MSRES;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_ESTATUS;
+		mii_data.val_in = ESTATUS_1000_TFULL;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+
+		mii_data.reg_num = MII_BMCR;
+		mii_data.val_in = BMCR_SPEED1000 | BMCR_FULLDPLX |
+			BMCR_LOOPBACK | BMCR_ANENABLE;
+		memcpy(&ifr.ifr_ifru.ifru_data, &mii_data, sizeof(mii_data));
+		lan743x_virtual_phy_mii_ioctl(phydev, &ifr, SIOCSMIIREG);
+	}
+
+	phydev->attached_dev = NULL;
+out:
+	return phydev;
+}
+
+int lan743x_set_virtual_link_ksettings(struct net_device *netdev,
+				       const struct ethtool_link_ksettings *cmd)
+{
+	struct ethtool_link_ksettings *cmd_ref =
+		(struct ethtool_link_ksettings *)cmd;
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	u32 speed = cmd->base.speed;
+	u8 duplex = cmd->base.duplex;
+	u16 v = 0;
+	u32 data;
+
+	if (!netdev->phydev)
+		return -ENETDOWN;
+	if (speed &&
+	    speed != SPEED_10 && speed != SPEED_100 && speed != SPEED_1000) {
+		netdev_err(netdev, "%s: unknown speed %d\n", netdev->name,
+			   speed);
+		return -EINVAL;
+	}
+
+	v = regs802p3[0];
+	v &= ~(BMCR_SPEED1000 | BMCR_SPEED100);
+	data = lan743x_csr_read(adapter, MAC_CR);
+	duplex = DUPLEX_FULL;
+
+	if (speed != adapter->netdev->phydev->speed) {
+		lan743x_mac_close(adapter);
+		switch (speed) {
+		case 0:
+			break;
+		case SPEED_10:
+			data &= ~(MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
+			lan743x_csr_write(adapter, MAC_CR, data);
+
+			regs802p3[MII_ADVERTISE] = ADVERTISE_10FULL |
+				ADVERTISE_100FULL |
+				ADVERTISE_LPACK;
+			regs802p3[MII_LPA] = LPA_10FULL | LPA_LPACK;
+			regs802p3[MII_EXPANSION] = ESTATUS_1000_TFULL;
+			regs802p3[MII_CTRL1000] = ADVERTISE_1000FULL;
+			regs802p3[MII_STAT1000] = 0;
+			break;
+		case SPEED_100:
+			v |= BMCR_SPEED100;
+			data &= ~MAC_CR_CFG_H_;
+			data |= MAC_CR_CFG_L_;
+			lan743x_csr_write(adapter, MAC_CR, data);
+
+			regs802p3[MII_ADVERTISE] = ADVERTISE_10FULL |
+				ADVERTISE_100FULL |
+				ADVERTISE_LPACK;
+			regs802p3[MII_LPA] = LPA_10FULL | LPA_100FULL |
+				LPA_LPACK;
+			regs802p3[MII_EXPANSION] = ESTATUS_1000_TFULL;
+			regs802p3[MII_CTRL1000] = ADVERTISE_1000FULL;
+			regs802p3[MII_STAT1000] = 0;
+			break;
+		case SPEED_1000:
+			v |= BMCR_SPEED1000;
+			data |= MAC_CR_CFG_H_;
+			data &= ~MAC_CR_CFG_L_;
+			lan743x_csr_write(adapter, MAC_CR, data);
+
+			regs802p3[MII_ADVERTISE] = ADVERTISE_10FULL |
+				ADVERTISE_100FULL |
+				ADVERTISE_LPACK;
+			regs802p3[MII_LPA] = LPA_10FULL | LPA_100FULL |
+				LPA_LPACK;
+			regs802p3[MII_EXPANSION] = ESTATUS_1000_TFULL;
+			regs802p3[MII_CTRL1000] = ADVERTISE_1000FULL;
+			regs802p3[MII_STAT1000] = LPA_1000FULL |
+				LPA_1000REMRXOK | LPA_1000LOCALRXOK |
+				LPA_1000MSRES;
+			break;
+		};
+		lan743x_mac_open(adapter);
+
+		v |= BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_ANENABLE;
+		regs802p3[0] = v;
+	}
+
+	cmd_ref->base.duplex = duplex;
+	cmd_ref->base.autoneg = AUTONEG_ENABLE;
+
+	return phy_ethtool_set_link_ksettings(netdev, cmd_ref);
+}
+
diff --git a/drivers/net/ethernet/microchip/lan743x_virtual_phy.h b/drivers/net/ethernet/microchip/lan743x_virtual_phy.h
new file mode 100644
index 000000000000..caef07d73d74
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_virtual_phy.h
@@ -0,0 +1,20 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2021 Sergej Bauer */
+#ifndef LAN743X_FAKE_PHY_H
+#define LAN743X_FAKE_PHY_H
+
+#include "lan743x_main.h"
+
+struct phy_device *lan743x_virtual_phy(struct lan743x_adapter *adapter,
+				       char *mii_regs[], int mii_regs_count);
+void lan743x_virtual_phy_disconnect(struct phy_device *phydev);
+int lan743x_virtual_phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr,
+				  int cmd);
+void lan743x_virtual_phy_status_change(struct net_device *netdev);
+int lan743x_set_virtual_link_ksettings(struct net_device *netdev,
+				       const struct ethtool_link_ksettings *cmd);
+
+int lan743x_mac_open(struct lan743x_adapter *adapter);
+void lan743x_mac_close(struct lan743x_adapter *adapter);
+
+#endif