mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 10:38:47 +00:00
improvements to phy package
This commit is contained in:
+62
-3
@@ -56,6 +56,10 @@ func FindClause22PHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
var (
|
||||
errInvalidPhyAddr = errors.New("invalid phy addr")
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
mdio MDIOBus
|
||||
phyaddr uint8
|
||||
@@ -64,13 +68,17 @@ type Device struct {
|
||||
}
|
||||
|
||||
// ConfigureAs22 resets all state of device to be used as a Clause22 device. Does not do a software reset.
|
||||
func (phy *Device) ConfigureAs22(mdio MDIOBus, phyAddr uint8) {
|
||||
if phyAddr > 31 || mdio == nil {
|
||||
panic("invalid argument to phy.Device.Reset")
|
||||
func (phy *Device) ConfigureAs22(mdio MDIOBus, phyAddr uint8) error {
|
||||
if phyAddr > 31 {
|
||||
return errInvalidPhyAddr
|
||||
|
||||
} else if mdio == nil {
|
||||
return errors.New("nil mdio bus")
|
||||
}
|
||||
phy.mdio = mdio
|
||||
phy.phyaddr = phyAddr
|
||||
phy.isClause45 = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsClause45 returns true if the device uses Clause 45 MDIO addressing (extended register access).
|
||||
@@ -214,6 +222,57 @@ func (phy *Device) IsLinkUp() (bool, error) {
|
||||
return status&BMSRLinkStatus != 0, nil
|
||||
}
|
||||
|
||||
// WaitForLinkWithDeadline waits for link to establish until the deadline.
|
||||
// If auto-negotiation is enabled (BMCR.ANEnable=1), waits for AN to complete first.
|
||||
// Returns true if link is up, false if deadline exceeded.
|
||||
//
|
||||
// Per IEEE 802.3:
|
||||
// - BMSR.LinkStatus is latched-low, so first read clears any previous fault
|
||||
// - BMSR.ANComplete must be set before link parameters are valid (when AN enabled)
|
||||
// - link_fail_inhibit_timer (50-75ms) delays link indication after AN completes
|
||||
func (phy *Device) WaitForLinkWithDeadline(deadline time.Time) (bool, error) {
|
||||
const pollInterval = 50 * time.Millisecond
|
||||
// Check current PHY configuration.
|
||||
// Early exit: link impossible if PHY isolated or powered down.
|
||||
ctl, err := phy.BasicControl()
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if ctl&BMCRIsolate != 0 {
|
||||
return false, errors.New("PHY isolated from MII")
|
||||
} else if ctl&BMCRPowerDown != 0 {
|
||||
return false, errors.New("PHY powered down")
|
||||
}
|
||||
|
||||
// First read clears latched-low bits (LinkStatus, ANComplete).
|
||||
// This ensures we get fresh status on subsequent reads.
|
||||
_, _ = phy.BasicStatus()
|
||||
anEnabled := ctl&BMCRANEnable != 0
|
||||
for time.Now().Before(deadline) {
|
||||
status, err := phy.BasicStatus()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// If AN enabled, must wait for it to complete first.
|
||||
// No point checking link status until AN is done.
|
||||
if anEnabled && !status.AutoNegotiationComplete() {
|
||||
time.Sleep(pollInterval)
|
||||
continue
|
||||
}
|
||||
// AN complete (or disabled). Check link status.
|
||||
if status.LinkUp() {
|
||||
return true, nil
|
||||
}
|
||||
time.Sleep(pollInterval)
|
||||
}
|
||||
|
||||
// Final check after deadline.
|
||||
status, err := phy.BasicStatus()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return status.LinkUp(), nil
|
||||
}
|
||||
|
||||
// NegotiatedLink returns the auto-negotiated link mode using standard MII registers.
|
||||
// Returns LinkMode based on ANAR (our advertisement) AND ANLPAR (link partner ability).
|
||||
// Priority order per IEEE 802.3 Annex 28B.3.
|
||||
|
||||
+38
-35
@@ -11,7 +11,7 @@ const (
|
||||
|
||||
regAutoNegotiationAdvertisement = 0x04
|
||||
regAutoNegotiationLinkPartnerAbility = 0x05
|
||||
regAutoNegotiationExpansion = 0x05
|
||||
regAutoNegotiationExpansion = 0x06
|
||||
regModeControlStatus = 0x11
|
||||
regSpecialModes = 0x12
|
||||
regSymbolErorCounter = 0x1a
|
||||
@@ -115,22 +115,6 @@ const (
|
||||
ANARPauseMask ANAR = ANARPause | ANARPauseAsym
|
||||
)
|
||||
|
||||
func (l LinkMode) ANAR() (a ANAR) {
|
||||
switch l {
|
||||
case Link10HDX:
|
||||
a = ANAR10Half
|
||||
case Link10FDX:
|
||||
a = ANAR10Full
|
||||
case Link100HDX:
|
||||
a = ANAR100Half
|
||||
case Link100FDX:
|
||||
a = ANAR100Full
|
||||
case Link100T4:
|
||||
a = ANAR100BaseT4
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// WithPause returns ANAR with pause bits set according to parameters.
|
||||
//
|
||||
// Flow control allows a receiver to signal the sender to pause transmission.
|
||||
@@ -203,21 +187,22 @@ func (a ANAR) Without100M() ANAR {
|
||||
// LinkMode returns the highest priority LinkMode from the ANAR speed bits.
|
||||
// Priority order per IEEE 802.3 Annex 28B.3.
|
||||
// Returns LinkDown if no speed bits are set.
|
||||
func (a ANAR) LinkMode() LinkMode {
|
||||
func (a ANAR) LinkMode() (l LinkMode) {
|
||||
switch {
|
||||
case a&ANAR100Full != 0:
|
||||
return Link100FDX
|
||||
l = Link100FDX
|
||||
case a&ANAR100BaseT4 != 0:
|
||||
return Link100T4
|
||||
l = Link100T4
|
||||
case a&ANAR100Half != 0:
|
||||
return Link100HDX
|
||||
l = Link100HDX
|
||||
case a&ANAR10Full != 0:
|
||||
return Link10FDX
|
||||
l = Link10FDX
|
||||
case a&ANAR10Half != 0:
|
||||
return Link10HDX
|
||||
l = Link10HDX
|
||||
default:
|
||||
return LinkDown
|
||||
l = LinkDown
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// LinkMode represents the negotiated/force-set Ethernet link speed and duplex mode.
|
||||
@@ -249,30 +234,48 @@ const (
|
||||
Link100GFDX // 100G-F
|
||||
)
|
||||
|
||||
func (l LinkMode) ANAR() (a ANAR) {
|
||||
a = NewANAR()
|
||||
switch l {
|
||||
case Link10HDX:
|
||||
a |= ANAR10Half
|
||||
case Link10FDX:
|
||||
a |= ANAR10Full
|
||||
case Link100HDX:
|
||||
a |= ANAR100Half
|
||||
case Link100FDX:
|
||||
a |= ANAR100Full
|
||||
case Link100T4:
|
||||
a |= ANAR100BaseT4
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// SpeedMbps returns the link speed in megabits per second.
|
||||
func (lm LinkMode) SpeedMbps() int {
|
||||
func (lm LinkMode) SpeedMbps() (Mbps int) {
|
||||
switch lm {
|
||||
case Link10HDX, Link10FDX:
|
||||
return 10
|
||||
Mbps = 10
|
||||
case Link100HDX, Link100FDX, Link100T4:
|
||||
return 100
|
||||
Mbps = 100
|
||||
case Link1000HDX, Link1000FDX:
|
||||
return 1000
|
||||
Mbps = 1000
|
||||
case Link2500FDX:
|
||||
return 2500
|
||||
Mbps = 2500
|
||||
case Link5GFDX:
|
||||
return 5000
|
||||
Mbps = 5000
|
||||
case Link10GFDX:
|
||||
return 10_000
|
||||
Mbps = 10_000
|
||||
case Link25GFDX:
|
||||
return 25_000
|
||||
Mbps = 25_000
|
||||
case Link40GFDX:
|
||||
return 40_000
|
||||
Mbps = 40_000
|
||||
case Link100GFDX:
|
||||
return 100_000
|
||||
Mbps = 100_000
|
||||
default:
|
||||
return 0
|
||||
Mbps = 0
|
||||
}
|
||||
return Mbps
|
||||
}
|
||||
|
||||
// IsFullDuplex returns true if the link mode is full duplex.
|
||||
|
||||
Reference in New Issue
Block a user