mirror of
https://github.com/soypat/lneto.git
synced 2026-08-20 14:39:02 +00:00
refactor phy package
This commit is contained in:
@@ -24,11 +24,12 @@ func _() {
|
|||||||
_ = x[FieldClassAddress-13]
|
_ = x[FieldClassAddress-13]
|
||||||
_ = x[FieldClassBinaryText-14]
|
_ = x[FieldClassBinaryText-14]
|
||||||
_ = x[FieldClassOperation-15]
|
_ = x[FieldClassOperation-15]
|
||||||
|
_ = x[FieldClassTimestamp-16]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _FieldClass_name = "undefinedsourcedestinationprotocolversiontypesizeflagsidentificationchecksumoptionspayloadtextaddressbinary-textop"
|
const _FieldClass_name = "undefinedsourcedestinationprotocolversiontypesizeflagsidentificationchecksumoptionspayloadtextaddressbinary-textoptimestamp"
|
||||||
|
|
||||||
var _FieldClass_index = [...]uint8{0, 9, 15, 26, 34, 41, 45, 49, 54, 68, 76, 83, 90, 94, 101, 112, 114}
|
var _FieldClass_index = [...]uint8{0, 9, 15, 26, 34, 41, 45, 49, 54, 68, 76, 83, 90, 94, 101, 112, 114, 123}
|
||||||
|
|
||||||
func (i FieldClass) String() string {
|
func (i FieldClass) String() string {
|
||||||
if i >= FieldClass(len(_FieldClass_index)-1) {
|
if i >= FieldClass(len(_FieldClass_index)-1) {
|
||||||
|
|||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
package phy
|
|
||||||
|
|
||||||
// MDIOBus is a HAL for MDIO bus access supporting both Clause 22 and Clause 45 devices.
|
|
||||||
// Implementations should use devaddr to select the framing:
|
|
||||||
// - devaddr=0: Clause 22 framing (devaddr ignored in transaction)
|
|
||||||
// - devaddr>=1: Clause 45 framing (PMA/PMD=1, WIS=2, PCS=3, PHY XS=4, DTE XS=5, AN=7)
|
|
||||||
//
|
|
||||||
// Register address range: Clause 22 uses 0-31, Clause 45 uses 0-65535.
|
|
||||||
type MDIOBus interface {
|
|
||||||
// Read reads a 16-bit register from the PHY.
|
|
||||||
Read(phyAddr, devaddr uint8, regAddr uint16) (value uint16, err error)
|
|
||||||
// Write writes a 16-bit value to a PHY register.
|
|
||||||
Write(phyAddr, devaddr uint8, regAddr, value uint16) error
|
|
||||||
}
|
|
||||||
+182
-23
@@ -3,13 +3,33 @@
|
|||||||
// for configuring and monitoring physical layer transceivers.
|
// for configuring and monitoring physical layer transceivers.
|
||||||
package phy
|
package phy
|
||||||
|
|
||||||
|
// Add more stringers in linecomment mode by adding them to type flag (comma separated).
|
||||||
|
//go:generate stringer -type=LinkMode -linecomment -output=phy_stringers.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MDIOBus is a HAL for MDIO bus access supporting both Clause 22 and Clause 45 devices.
|
||||||
|
// Implementations should use devaddr to select the framing:
|
||||||
|
// - devaddr=0: Clause 22 framing (devaddr ignored in transaction)
|
||||||
|
// - devaddr>=1: Clause 45 framing (PMA/PMD=1, WIS=2, PCS=3, PHY XS=4, DTE XS=5, AN=7)
|
||||||
|
//
|
||||||
|
// Register address range: Clause 22 uses 0-31, Clause 45 uses 0-65535.
|
||||||
|
// Invalid combinations of devaddr and regAddr may or may not return an error
|
||||||
|
// depending on the implementation or result in undefined behavior.
|
||||||
|
// To avoid this wrap your MDIOBus interfaces with a wrapper type that checks validity of ranges.
|
||||||
|
type MDIOBus interface {
|
||||||
|
// Read reads a 16-bit register from the PHY.
|
||||||
|
Read(phyAddr, devAddr uint8, regAddr uint16) (value uint16, err error)
|
||||||
|
// Write writes a 16-bit value to a PHY register.
|
||||||
|
Write(phyAddr, devAddr uint8, regAddr, value uint16) error
|
||||||
|
}
|
||||||
|
|
||||||
// FindPHYs finds all regular non-clause45 PHYs on the MDIO bus and writes them to dst.
|
// FindPHYs finds all regular non-clause45 PHYs on the MDIO bus and writes them to dst.
|
||||||
func FindPHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
|
// FindClause22PHYs returns error only if unable to find no PHYs.
|
||||||
|
func FindClause22PHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
|
||||||
const maxAddr = 31
|
const maxAddr = 31
|
||||||
const regBasicStatus = 0x01
|
const regBasicStatus = 0x01
|
||||||
if len(dst) < 32 {
|
if len(dst) < 32 {
|
||||||
@@ -19,9 +39,7 @@ func FindPHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
|
|||||||
for addr := uint8(0); addr <= maxAddr; addr++ {
|
for addr := uint8(0); addr <= maxAddr; addr++ {
|
||||||
// Future proofing for supported clause 45.
|
// Future proofing for supported clause 45.
|
||||||
// Check PMA/PMD device (DEVAD 1), register 0 (control)
|
// Check PMA/PMD device (DEVAD 1), register 0 (control)
|
||||||
const devAddr = 1
|
val, err := mdio.Read(addr, 0, AddrBMSR)
|
||||||
var val uint16
|
|
||||||
val, err = mdio.Read(addr, devAddr, BMCRAddr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -32,36 +50,87 @@ func FindPHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
|
|||||||
}
|
}
|
||||||
time.Sleep(150 * time.Microsecond)
|
time.Sleep(150 * time.Microsecond)
|
||||||
}
|
}
|
||||||
|
if n <= 0 {
|
||||||
|
err = errors.New("no phy found")
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
mdio MDIOBus
|
mdio MDIOBus
|
||||||
phyaddr uint8
|
phyaddr uint8
|
||||||
// Is 1 for Clause 45 devices and 0 for clause 22 devices.
|
// isClause45 is 0 for clause 22 devices and 1 for clause45 devices.
|
||||||
clause45 uint8
|
isClause45 uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) BasicControl() (BMCR, error) {
|
// ConfigureAs22 resets all state of device to be used as a Clause22 device. Does not do a software reset.
|
||||||
ctl, err := d.rread(BMCRAddr)
|
func (phy *Device) ConfigureAs22(mdio MDIOBus, phyAddr uint8) {
|
||||||
|
if phyAddr > 31 || mdio == nil {
|
||||||
|
panic("invalid argument to phy.Device.Reset")
|
||||||
|
}
|
||||||
|
phy.mdio = mdio
|
||||||
|
phy.phyaddr = phyAddr
|
||||||
|
phy.isClause45 = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClause45 returns true if the device uses Clause 45 MDIO addressing (extended register access).
|
||||||
|
func (phy *Device) IsClause45() bool {
|
||||||
|
return phy.isClause45 == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHYAddr returns the PHY address on the MDIO bus (0-31).
|
||||||
|
func (phy *Device) PHYAddr() uint8 {
|
||||||
|
return phy.phyaddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// BasicControl reads the Basic Mode Control Register (BMCR, register 0).
|
||||||
|
func (phy *Device) BasicControl() (BMCR, error) {
|
||||||
|
ctl, err := phy.rread(AddrBMCR)
|
||||||
return BMCR(ctl), err
|
return BMCR(ctl), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) BasicStatus(phyaddr uint8) (BMSR, error) {
|
// BasicStatus reads the Basic Mode Status Register (BMSR, register 1).
|
||||||
stat, err := d.rread(BMSRAddr)
|
func (phy *Device) BasicStatus() (BMSR, error) {
|
||||||
|
stat, err := phy.rread(AddrBMSR)
|
||||||
return BMSR(stat), err
|
return BMSR(stat), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) ID1() (uint16, error) {
|
// EnableAutoNegotiation enables or disables PHY auto-negotiation and verifies the change took effect.
|
||||||
return d.rread(regPhyId1)
|
func (phy *Device) EnableAutoNegotiation(b bool) error {
|
||||||
|
ctl, err := phy.BasicControl()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if b {
|
||||||
|
ctl |= BMCRANEnable
|
||||||
|
} else {
|
||||||
|
ctl &^= BMCRANEnable
|
||||||
|
}
|
||||||
|
err = phy.rwrite(AddrBMCR, uint16(ctl))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctl, err = phy.BasicControl()
|
||||||
|
if (ctl&BMCRANEnable != 0) != b {
|
||||||
|
return errors.New("unable to set control enable bit")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) ID2() (uint16, error) {
|
// ID1 reads the PHY Identifier 1 register (register 2), containing bits 3-18 of the OUI.
|
||||||
return d.rread(regPhyId2)
|
func (phy *Device) ID1() (uint16, error) {
|
||||||
|
return phy.rread(regPhyId1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) Reset(phyaddr uint8) error {
|
// ID2 reads the PHY Identifier 2 register (register 3), containing bits 19-24 of the OUI and model/revision.
|
||||||
err := d.rwrite(BMCRAddr, uint16(BMCRReset))
|
func (phy *Device) ID2() (uint16, error) {
|
||||||
|
return phy.rread(regPhyId2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetPHY performs a software reset and waits for completion.
|
||||||
|
// Returns an error on IO error on MDIO bus or on timeout during wait for register reset.
|
||||||
|
func (phy *Device) ResetPHY() (err error) {
|
||||||
|
err = phy.rwrite(AddrBMCR, uint16(BMCRReset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -69,9 +138,10 @@ func (d *Device) Reset(phyaddr uint8) error {
|
|||||||
// IEEE 802.3 allows up to 500ms.
|
// IEEE 802.3 allows up to 500ms.
|
||||||
const maxPolls = 50
|
const maxPolls = 50
|
||||||
const resetTimeout = 500 * time.Millisecond // As per standard.
|
const resetTimeout = 500 * time.Millisecond // As per standard.
|
||||||
|
var ctl BMCR
|
||||||
for i := 0; i < maxPolls; i++ {
|
for i := 0; i < maxPolls; i++ {
|
||||||
time.Sleep(resetTimeout / maxPolls)
|
time.Sleep(resetTimeout / maxPolls)
|
||||||
ctl, err := d.BasicControl()
|
ctl, err = phy.BasicControl()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -79,15 +149,104 @@ func (d *Device) Reset(phyaddr uint8) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return errors.New("PHY reset timeout")
|
return errors.New("PHY reset timeout")
|
||||||
}
|
}
|
||||||
|
|
||||||
// rwrite mdio register write.
|
// SetupForced disables auto-negotiation and forces a specific link mode.
|
||||||
func (d *Device) rwrite(addr uint16, value uint16) error {
|
//
|
||||||
return d.mdio.Write(d.phyaddr, d.clause45, addr, value)
|
// Inspired by drivers/net/phy/phy_device.c
|
||||||
|
func (phy *Device) SetupForced(mode LinkMode) error {
|
||||||
|
var ctl BMCR
|
||||||
|
switch mode.SpeedMbps() {
|
||||||
|
case 1000:
|
||||||
|
ctl |= BMCRSpeed1000
|
||||||
|
case 100:
|
||||||
|
ctl |= BMCRSpeed100
|
||||||
|
case 10:
|
||||||
|
// No speed bits = 10Mbps
|
||||||
|
default:
|
||||||
|
return errors.New("unsupported forced link mode")
|
||||||
|
}
|
||||||
|
if mode.IsFullDuplex() {
|
||||||
|
ctl |= BMCRFullDuplex
|
||||||
|
}
|
||||||
|
// Note: BMCRANEnable is NOT set, disabling auto-negotiation
|
||||||
|
return phy.rwrite(AddrBMCR, uint16(ctl))
|
||||||
}
|
}
|
||||||
|
|
||||||
// rread mdio register read.
|
// Advertisement reads the current Auto-Negotiation Advertisement Register.
|
||||||
func (d *Device) rread(addr uint16) (value uint16, _ error) {
|
func (phy *Device) Advertisement() (ANAR, error) {
|
||||||
return d.mdio.Read(d.phyaddr, d.clause45, addr)
|
val, err := phy.rread(AddrANAR)
|
||||||
|
return ANAR(val), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAdvertisement writes to the Auto-Negotiation Advertisement Register.
|
||||||
|
// Does NOT restart auto-negotiation; call RestartAutoNeg() after if needed.
|
||||||
|
func (phy *Device) SetAdvertisement(ad ANAR) error {
|
||||||
|
return phy.rwrite(AddrANAR, uint16(ad))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LinkPartnerAdvertisement reads what the link partner is advertising (ANLPAR).
|
||||||
|
func (phy *Device) LinkPartnerAdvertisement() (ANAR, error) {
|
||||||
|
val, err := phy.rread(AddrANLPAR)
|
||||||
|
return ANAR(val), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestartAutoNeg enables auto-negotiation and restarts it.
|
||||||
|
func (phy *Device) RestartAutoNeg() error {
|
||||||
|
ctl, err := phy.BasicControl()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctl |= BMCRANEnable | BMCRANRestart
|
||||||
|
return phy.rwrite(AddrBMCR, uint16(ctl))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLinkUp returns true if link is established.
|
||||||
|
func (phy *Device) IsLinkUp() (bool, error) {
|
||||||
|
status, err := phy.BasicStatus()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return status&BMSRLinkStatus != 0, 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.
|
||||||
|
func (phy *Device) NegotiatedLink() (LinkMode, error) {
|
||||||
|
// First check if auto-negotiation is complete
|
||||||
|
status, err := phy.BasicStatus()
|
||||||
|
if err != nil {
|
||||||
|
return LinkDown, err
|
||||||
|
}
|
||||||
|
if status&BMSRANComplete == 0 {
|
||||||
|
return LinkDown, errors.New("auto-negotiation not complete")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read our advertisement
|
||||||
|
anar, err := phy.Advertisement()
|
||||||
|
if err != nil {
|
||||||
|
return LinkDown, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read link partner's advertisement
|
||||||
|
anlpar, err := phy.LinkPartnerAdvertisement()
|
||||||
|
if err != nil {
|
||||||
|
return LinkDown, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common capabilities = what both sides support
|
||||||
|
common := anar & anlpar
|
||||||
|
return common.LinkMode(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (phy *Device) rread(regaddr uint16) (uint16, error) {
|
||||||
|
return phy.mdio.Read(phy.phyaddr, phy.isClause45, regaddr)
|
||||||
|
}
|
||||||
|
func (phy *Device) rwrite(regaddr, value uint16) error {
|
||||||
|
return phy.mdio.Write(phy.phyaddr, phy.isClause45, regaddr, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// Code generated by "stringer -type=LinkMode -linecomment -output=phy_stringers.go"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package phy
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[LinkDown-0]
|
||||||
|
_ = x[Link10HDX-1]
|
||||||
|
_ = x[Link10FDX-2]
|
||||||
|
_ = x[Link100HDX-3]
|
||||||
|
_ = x[Link100FDX-4]
|
||||||
|
_ = x[Link100T4-5]
|
||||||
|
_ = x[Link1000HDX-6]
|
||||||
|
_ = x[Link1000FDX-7]
|
||||||
|
_ = x[Link2500FDX-8]
|
||||||
|
_ = x[Link5GFDX-9]
|
||||||
|
_ = x[Link10GFDX-10]
|
||||||
|
_ = x[Link25GFDX-11]
|
||||||
|
_ = x[Link40GFDX-12]
|
||||||
|
_ = x[Link100GFDX-13]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _LinkMode_name = "down10M-H10M-F100M-H100M-F100M-T41000M-H1000M-F2.5G-F5G-F10G-F25G-F40G-F100G-F"
|
||||||
|
|
||||||
|
var _LinkMode_index = [...]uint8{0, 4, 9, 14, 20, 26, 33, 40, 47, 53, 57, 62, 67, 72, 78}
|
||||||
|
|
||||||
|
func (i LinkMode) String() string {
|
||||||
|
if i >= LinkMode(len(_LinkMode_index)-1) {
|
||||||
|
return "LinkMode(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _LinkMode_name[_LinkMode_index[i]:_LinkMode_index[i+1]]
|
||||||
|
}
|
||||||
+203
-2
@@ -1,5 +1,7 @@
|
|||||||
package phy
|
package phy
|
||||||
|
|
||||||
|
// See https://github.com/PieVo/mdio-tool/blob/master/mii.h
|
||||||
|
|
||||||
// Registers 0..15 as defined by 802.3.
|
// Registers 0..15 as defined by 802.3.
|
||||||
const (
|
const (
|
||||||
// First two registers are BMCR and BMSR. See below.
|
// First two registers are BMCR and BMSR. See below.
|
||||||
@@ -24,7 +26,7 @@ const (
|
|||||||
type BMCR uint16
|
type BMCR uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BMCRAddr = 0x00
|
AddrBMCR = 0x00 // Address of Basic Mode Control Register.
|
||||||
|
|
||||||
BMCRSpeed1000 BMCR = 0x0040 // MSB of Speed (1000Mbps)
|
BMCRSpeed1000 BMCR = 0x0040 // MSB of Speed (1000Mbps)
|
||||||
BMCRCollision BMCR = 0x0080 // Collision test
|
BMCRCollision BMCR = 0x0080 // Collision test
|
||||||
@@ -43,7 +45,7 @@ const (
|
|||||||
type BMSR uint16
|
type BMSR uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BMSRAddr = 0x01
|
AddrBMSR = 0x01 // Address of Basic Mode Status Register.
|
||||||
|
|
||||||
BMSRExtCap BMSR = 0x0001 // Extended register capability
|
BMSRExtCap BMSR = 0x0001 // Extended register capability
|
||||||
BMSRJabber BMSR = 0x0002 // Jabber detected
|
BMSRJabber BMSR = 0x0002 // Jabber detected
|
||||||
@@ -61,3 +63,202 @@ const (
|
|||||||
BMSR100Full BMSR = 0x4000 // 100Mbps full-duplex capable
|
BMSR100Full BMSR = 0x4000 // 100Mbps full-duplex capable
|
||||||
BMSR100Base4 BMSR = 0x8000 // 100BASE-T4 capable
|
BMSR100Base4 BMSR = 0x8000 // 100BASE-T4 capable
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
)
|
||||||
|
|
||||||
|
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.
|
||||||
|
// 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() LinkMode {
|
||||||
|
switch {
|
||||||
|
case a&ANAR100Full != 0:
|
||||||
|
return Link100FDX
|
||||||
|
case a&ANAR100BaseT4 != 0:
|
||||||
|
return Link100T4
|
||||||
|
case a&ANAR100Half != 0:
|
||||||
|
return Link100HDX
|
||||||
|
case a&ANAR10Full != 0:
|
||||||
|
return Link10FDX
|
||||||
|
case a&ANAR10Half != 0:
|
||||||
|
return Link10HDX
|
||||||
|
default:
|
||||||
|
return LinkDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
)
|
||||||
|
|
||||||
|
// SpeedMbps returns the link speed in megabits per second.
|
||||||
|
func (lm LinkMode) SpeedMbps() int {
|
||||||
|
switch lm {
|
||||||
|
case Link10HDX, Link10FDX:
|
||||||
|
return 10
|
||||||
|
case Link100HDX, Link100FDX, Link100T4:
|
||||||
|
return 100
|
||||||
|
case Link1000HDX, Link1000FDX:
|
||||||
|
return 1000
|
||||||
|
case Link2500FDX:
|
||||||
|
return 2500
|
||||||
|
case Link5GFDX:
|
||||||
|
return 5000
|
||||||
|
case Link10GFDX:
|
||||||
|
return 10_000
|
||||||
|
case Link25GFDX:
|
||||||
|
return 25_000
|
||||||
|
case Link40GFDX:
|
||||||
|
return 40_000
|
||||||
|
case Link100GFDX:
|
||||||
|
return 100_000
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+4
-2
@@ -196,11 +196,13 @@ func _() {
|
|||||||
var x [1]struct{}
|
var x [1]struct{}
|
||||||
_ = x[ErrPacketDrop-1]
|
_ = x[ErrPacketDrop-1]
|
||||||
_ = x[ErrBadCRC-2]
|
_ = x[ErrBadCRC-2]
|
||||||
|
_ = x[ErrZeroSource-3]
|
||||||
|
_ = x[ErrZeroDestination-4]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _errGeneric_name = "packet droppedincorrect checksum"
|
const _errGeneric_name = "packet droppedincorrect checksumzero source(port/addr)zero destination(port/addr)"
|
||||||
|
|
||||||
var _errGeneric_index = [...]uint8{0, 14, 32}
|
var _errGeneric_index = [...]uint8{0, 14, 32, 54, 81}
|
||||||
|
|
||||||
func (i errGeneric) String() string {
|
func (i errGeneric) String() string {
|
||||||
i -= 1
|
i -= 1
|
||||||
|
|||||||
Reference in New Issue
Block a user