mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 10:38:47 +00:00
291 lines
8.7 KiB
Go
291 lines
8.7 KiB
Go
package phy
|
|
|
|
// See https://github.com/PieVo/mdio-tool/blob/master/mii.h
|
|
|
|
// Registers 0..15 as defined by 802.3.
|
|
const (
|
|
// First two registers are BMCR and BMSR. See below.
|
|
|
|
regPhyId1 = 0x02
|
|
regPhyId2 = 0x03
|
|
|
|
regAutoNegotiationAdvertisement = 0x04
|
|
regAutoNegotiationLinkPartnerAbility = 0x05
|
|
regAutoNegotiationExpansion = 0x06
|
|
regModeControlStatus = 0x11
|
|
regSpecialModes = 0x12
|
|
regSymbolErorCounter = 0x1a
|
|
regSpecialControlStatusIndications = 0x1b
|
|
regIRQSourceFlag = 0x1d
|
|
regIRQMask = 0x1e
|
|
regPhySpecialScontrolStatus = 0x1f
|
|
)
|
|
|
|
// BMCR represents the Basic Mode Control Register at address 0x00.
|
|
// Reference: IEEE 802.3 Clause 22.2.4.1
|
|
type BMCR uint16
|
|
|
|
const (
|
|
AddrBMCR = 0x00 // Address of Basic Mode Control Register.
|
|
|
|
BMCRSpeed1000 BMCR = 0x0040 // MSB of Speed (1000Mbps)
|
|
BMCRCollision BMCR = 0x0080 // Collision test
|
|
BMCRFullDuplex BMCR = 0x0100 // Full duplex mode
|
|
BMCRANRestart BMCR = 0x0200 // Restart auto-negotiation
|
|
BMCRIsolate BMCR = 0x0400 // Isolate PHY from MII
|
|
BMCRPowerDown BMCR = 0x0800 // Power down PHY
|
|
BMCRANEnable BMCR = 0x1000 // Enable auto-negotiation
|
|
BMCRSpeed100 BMCR = 0x2000 // Select 100Mbps
|
|
BMCRLoopback BMCR = 0x4000 // Enable TXD loopback
|
|
BMCRReset BMCR = 0x8000 // Software reset (self-clearing)
|
|
)
|
|
|
|
// BMSR represents the Basic Mode Status Register at address 0x01.
|
|
// Reference: IEEE 802.3 Clause 22.2.4.2
|
|
type BMSR uint16
|
|
|
|
const (
|
|
AddrBMSR = 0x01 // Address of Basic Mode Status Register.
|
|
|
|
BMSRExtCap BMSR = 0x0001 // Extended register capability
|
|
BMSRJabber BMSR = 0x0002 // Jabber detected
|
|
BMSRLinkStatus BMSR = 0x0004 // Link status (1=up)
|
|
BMSRANCap BMSR = 0x0008 // Auto-negotiation capable
|
|
BMSRRemoteFault BMSR = 0x0010 // Remote fault detected
|
|
BMSRANComplete BMSR = 0x0020 // Auto-negotiation complete
|
|
BMSRNoPreamble BMSR = 0x0040 // Preamble suppression capable
|
|
BMSRExtStatus BMSR = 0x0100 // Extended status in register 15
|
|
BMSR100Half2 BMSR = 0x0200 // 100BASE-T2 half-duplex capable
|
|
BMSR100Full2 BMSR = 0x0400 // 100BASE-T2 full-duplex capable
|
|
BMSR10Half BMSR = 0x0800 // 10Mbps half-duplex capable
|
|
BMSR10Full BMSR = 0x1000 // 10Mbps full-duplex capable
|
|
BMSR100Half BMSR = 0x2000 // 100Mbps half-duplex capable
|
|
BMSR100Full BMSR = 0x4000 // 100Mbps full-duplex capable
|
|
BMSR100Base4 BMSR = 0x8000 // 100BASE-T4 capable
|
|
)
|
|
|
|
// JabberDetected returns true if jabber condition was detected (bit 1).
|
|
// Jabber occurs when transmission exceeds the maximum allowed frame time.
|
|
// This bit is latched-high and cleared on read. Only meaningful for 10BASE-T.
|
|
func (b BMSR) JabberDetected() bool {
|
|
return b&BMSRJabber != 0
|
|
}
|
|
|
|
// RemoteFault returns true if the link partner has detected a fault (bit 4).
|
|
// This bit is latched-high and cleared on read.
|
|
func (b BMSR) RemoteFault() bool {
|
|
return b&BMSRRemoteFault != 0
|
|
}
|
|
|
|
// LinkUp returns true if link is established (bit 2).
|
|
func (b BMSR) LinkUp() bool {
|
|
return b&BMSRLinkStatus != 0
|
|
}
|
|
|
|
// AutoNegotiationComplete returns true if auto-negotiation has completed (bit 5).
|
|
func (b BMSR) AutoNegotiationComplete() bool {
|
|
return b&BMSRANComplete != 0
|
|
}
|
|
|
|
// ANAR represents the Auto-Negotiation Advertisement Register value at address 0x04.
|
|
// ANLPAR (Link Partner Ability Register at 0x05) shares the same bit layout.
|
|
// Reference: IEEE 802.3 Clause 28.2.4.1
|
|
type ANAR uint16
|
|
|
|
const (
|
|
AddrANAR = 0x04 // Address of Auto-Negotiation Advertisement Register.
|
|
AddrANLPAR = 0x05 // Address of Auto-Negotiation Link Partner Advertisement Register.
|
|
AddrANER = 0x06 // Address of Auto-Negotiation Error Register.
|
|
|
|
ANARSelector ANAR = 0x001f // Protocol selector mask
|
|
ANARSelector8023 ANAR = 0x0001 // IEEE 802.3 selector value (required)
|
|
ANAR10Half ANAR = 0x0020 // 10BASE-T half-duplex
|
|
ANAR10Full ANAR = 0x0040 // 10BASE-T full-duplex
|
|
ANAR100Half ANAR = 0x0080 // 100BASE-TX half-duplex
|
|
ANAR100Full ANAR = 0x0100 // 100BASE-TX full-duplex
|
|
ANAR100BaseT4 ANAR = 0x0200 // 100BASE-T4
|
|
ANARPause ANAR = 0x0400 // Pause capability
|
|
ANARPauseAsym ANAR = 0x0800 // Asymmetric pause
|
|
ANARRemoteFault ANAR = 0x2000 // Remote fault
|
|
ANARAck ANAR = 0x4000 // Acknowledge (ANLPAR only)
|
|
ANARNextPage ANAR = 0x8000 // Next page capable
|
|
|
|
// Convenience masks
|
|
ANARSpeedMask ANAR = ANAR10Half | ANAR10Full | ANAR100Half | ANAR100Full | ANAR100BaseT4
|
|
ANARPauseMask ANAR = ANARPause | ANARPauseAsym
|
|
)
|
|
|
|
// WithPause returns ANAR with pause bits set according to parameters.
|
|
//
|
|
// Flow control allows a receiver to signal the sender to pause transmission.
|
|
// Common combinations:
|
|
// - (true, false): Symmetric pause - both ends can pause each other
|
|
// - (true, true): Full flow control with asymmetric fallback
|
|
// - (false, true): Rx-only pause - we can be paused, won't pause partner
|
|
// - (false, false): No flow control
|
|
func (a ANAR) WithPause(symmetric, asymmetric bool) ANAR {
|
|
a &^= ANARPauseMask
|
|
if symmetric {
|
|
a |= ANARPause
|
|
}
|
|
if asymmetric {
|
|
a |= ANARPauseAsym
|
|
}
|
|
return a
|
|
}
|
|
|
|
// WithMaxSpeed returns ANAR with only speeds at or below maxMbps enabled.
|
|
// Preserves non-speed bits (pause, selector, etc).
|
|
func (a ANAR) WithMaxSpeed(maxMbps int) ANAR {
|
|
a &^= ANARSpeedMask
|
|
switch {
|
|
case maxMbps >= 100:
|
|
a |= ANAR100Half | ANAR100Full
|
|
fallthrough
|
|
case maxMbps >= 10:
|
|
a |= ANAR10Half | ANAR10Full
|
|
}
|
|
return a
|
|
}
|
|
|
|
// FullDuplexOnly returns ANAR with half-duplex modes cleared.
|
|
func (a ANAR) FullDuplexOnly() ANAR {
|
|
return a &^ (ANAR10Half | ANAR100Half)
|
|
}
|
|
|
|
// HalfDuplexOnly returns ANAR with full-duplex modes cleared.
|
|
func (a ANAR) HalfDuplexOnly() ANAR {
|
|
return a &^ (ANAR10Full | ANAR100Full)
|
|
}
|
|
|
|
// NewANAR returns an ANAR with the IEEE 802.3 selector set.
|
|
// Always start with this when building an advertisement value.
|
|
func NewANAR() ANAR {
|
|
return ANARSelector8023
|
|
}
|
|
|
|
// With10M returns ANAR with 10Mbps modes (half and full) enabled.
|
|
func (a ANAR) With10M() ANAR {
|
|
return a | ANAR10Half | ANAR10Full
|
|
}
|
|
|
|
// With100M returns ANAR with 100Mbps modes (half and full) enabled.
|
|
func (a ANAR) With100M() ANAR {
|
|
return a | ANAR100Half | ANAR100Full
|
|
}
|
|
|
|
// Without10M returns ANAR with 10Mbps modes cleared.
|
|
func (a ANAR) Without10M() ANAR {
|
|
return a &^ (ANAR10Half | ANAR10Full)
|
|
}
|
|
|
|
// Without100M returns ANAR with 100Mbps modes cleared.
|
|
func (a ANAR) Without100M() ANAR {
|
|
return a &^ (ANAR100Half | ANAR100Full | ANAR100BaseT4)
|
|
}
|
|
|
|
// 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() (l LinkMode) {
|
|
switch {
|
|
case a&ANAR100Full != 0:
|
|
l = Link100FDX
|
|
case a&ANAR100BaseT4 != 0:
|
|
l = Link100T4
|
|
case a&ANAR100Half != 0:
|
|
l = Link100HDX
|
|
case a&ANAR10Full != 0:
|
|
l = Link10FDX
|
|
case a&ANAR10Half != 0:
|
|
l = Link10HDX
|
|
default:
|
|
l = LinkDown
|
|
}
|
|
return l
|
|
}
|
|
|
|
// LinkMode represents the negotiated/force-set Ethernet link speed and duplex mode.
|
|
//
|
|
// Naming convention:
|
|
// - H/HDX: Half-duplex (one direction at a time)
|
|
// - F/FDX: Full-duplex (simultaneous bidirectional)
|
|
// - T4: 100BASE-T4 (100Mbps over 4 twisted pairs, legacy)
|
|
// - G: Gigabit, implies number is multiplied by 1000 (1G=1000M)
|
|
type LinkMode uint8
|
|
|
|
const (
|
|
LinkDown LinkMode = iota // down
|
|
Link10HDX // 10M-H
|
|
Link10FDX // 10M-F
|
|
Link100HDX // 100M-H
|
|
Link100FDX // 100M-F
|
|
Link100T4 // 100M-T4
|
|
Link1000HDX // 1000M-H
|
|
Link1000FDX // 1000M-F
|
|
|
|
// Clause 45 speeds (10Gbps+, full-duplex only):
|
|
|
|
Link2500FDX // 2.5G-F
|
|
Link5GFDX // 5G-F
|
|
Link10GFDX // 10G-F
|
|
Link25GFDX // 25G-F
|
|
Link40GFDX // 40G-F
|
|
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() (Mbps int) {
|
|
switch lm {
|
|
case Link10HDX, Link10FDX:
|
|
Mbps = 10
|
|
case Link100HDX, Link100FDX, Link100T4:
|
|
Mbps = 100
|
|
case Link1000HDX, Link1000FDX:
|
|
Mbps = 1000
|
|
case Link2500FDX:
|
|
Mbps = 2500
|
|
case Link5GFDX:
|
|
Mbps = 5000
|
|
case Link10GFDX:
|
|
Mbps = 10_000
|
|
case Link25GFDX:
|
|
Mbps = 25_000
|
|
case Link40GFDX:
|
|
Mbps = 40_000
|
|
case Link100GFDX:
|
|
Mbps = 100_000
|
|
default:
|
|
Mbps = 0
|
|
}
|
|
return Mbps
|
|
}
|
|
|
|
// IsFullDuplex returns true if the link mode is full duplex.
|
|
func (lm LinkMode) IsFullDuplex() bool {
|
|
switch lm {
|
|
case Link10FDX, Link100FDX, Link1000FDX,
|
|
Link2500FDX, Link5GFDX, Link10GFDX, Link25GFDX, Link40GFDX, Link100GFDX:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|