Tüm eğitimler
TEKNİK REHBER GÖMÜLÜ LİNUX AĞ SÜRÜCÜSÜ 2026

Ethernet PHY & phylink
Donanım Ağ Katmanı

Linux Ethernet PHY subsystem'ini, MDIO bus mekanizmasını, phylib/phylink çerçevelerini ve üretim kalitesinde PHY sürücüsü yazmayı adım adım öğrenin.

00 Ethernet PHY nedir — MAC/PHY/MII

Ethernet iletişimi iki ayrı katmana bölünmüştür: MAC (Media Access Controller) ve PHY (Physical Layer). Bu iki katmanın aralarındaki standart arayüzleri anlamak, Linux ağ sürücüsü geliştirmenin temel taşıdır.

MAC ve PHY ayrımı

MAC katmanı Ethernet çerçevelerini (frame) oluşturur, CRC hesaplar ve zamanlama yönetimini yapar. PHY katmanı ise bu dijital sinyali fiziksel ortama (bakır, fiber) uygun analog sinyale dönüştürür. SoC'lerde MAC genellikle entegre gelir; PHY ise ayrı bir yonga olarak devreye bağlanır.

Uygulama Katmanı
       │
    TCP/UDP
       │
       IP
       │
 Linux net stack (sk_buff)
       │
   MAC sürücüsü (GMAC, stmmac…)
       │  ← MII/RMII/RGMII/SGMII arayüzü
    PHY yonga (DP83867, KSZ9031…)
       │
  Fiziksel ortam (RJ45, SFP…)

MII aile arayüzleri

ArayüzHızPin sayısıSaatTipik kullanım
MII10/100 Mb/s1825 MHzEski entegrasyonlar
RMII10/100 Mb/s950 MHz (tek saat)Düşük pin sayısı gereken SoC
GMII10/100/1000 Mb/s24125 MHzGigabit, nadiren kullanılır
RGMII10/100/1000 Mb/s12125 MHz, DDRGigabit embedded, en yaygın
SGMII1 Gb/s (seri)4 (diff)SerDesSFP, FPGA, yüksek yoğunluk
USXGMII1/2.5/5/10 Gb/s4 (diff)SerDesMulti-Gig SFP+

RGMII zamanlama — RX/TX gecikme

RGMII'de veri 125 MHz saat sinyalinin yükselen ve düşen kenarlarında gönderilir (DDR). MAC veya PHY tarafında 2 ns'lik gecikme (delay) uygulanması gerekir; bu gecikme cihaz ağacında ya da PHY registerlarında ayarlanır.

rgmii-idMAC hem TX hem RX gecikmesini uygular; PHY'de gecikme yoktur
rgmii-rxidYalnızca RX gecikme MAC tarafında; TX gecikmesini PHY uygular
rgmii-txidYalnızca TX gecikme MAC tarafında; RX gecikmesini PHY uygular
rgmiiHiçbir gecikme eklenmez; PCB tasarımıyla çözülür

Bu bölümde

  • MAC dijital çerçeveleri oluşturur; PHY analog iletimi sağlar
  • RGMII en yaygın Gigabit arayüzüdür: 12 pin, 125 MHz DDR saat
  • SGMII diferansiyel seri hat — SFP modülleri ve FPGA arayüzleri için tercih edilir
  • RGMII gecikmesi doğru ayarlanmazsa link kurulmaz veya hata paketleri oluşur

01 MDIO bus — clause 22 ve 45

MDIO (Management Data Input/Output), MAC'in PHY register'larını okumasını ve yazmasını sağlayan 2 telli yönetim veri yoludur. Linux'ta mdiobus alt sistemi bu yolu soyutlar.

MDIO sinyalleri

MDIO yalnızca iki sinyal kullanır: MDC (saat, MAC tarafından üretilir, maksimum 2.5 MHz) ve MDIO (çift yönlü veri). Tek bir MDC/MDIO çiftine 32 farklı PHY adresi (0–31) bağlanabilir.

Clause 22 — standart PHY register erişimi

IEEE 802.3 Clause 22, 5 bitlik PHY adresi (PRTAD) ve 5 bitlik register adresi (DEVAD) içerir; toplamda 32 register erişimi sağlar.

RegisterAdresİşlev
BMCR0x00Temel Mod Kontrol — auto-neg, reset, hız
BMSR0x01Temel Mod Durum — link, auto-neg tamamlandı
PHYIDR10x02PHY ID üst 16 bit (OUI)
PHYIDR20x03PHY ID alt 16 bit (model, revizyon)
ANAR0x04Auto-neg Duyuru — desteklenen hızlar
ANLPAR0x05Link Partner Yeteneği
1000BASET_CTRL0x091000BASE-T kontrol (Gigabit PHY)

Clause 45 — genişletilmiş register uzayı

10GbE ve daha yüksek hızlar, 32 register ile yetinmez. Clause 45 bu sorunu 5 bitlik MMD (MDIO Manageable Device) ve 16 bitlik register adresiyle çözer; 65536 register/MMD erişimi sağlar.

Linux'ta mdiobus_register

c
/* MAC sürücüsünde MDIO bus oluşturma */
static int my_mac_mdio_probe(struct platform_device *pdev)
{
    struct mii_bus *bus;
    int ret;

    bus = devm_mdiobus_alloc(&pdev->dev);
    if (!bus)
        return -ENOMEM;

    bus->name      = "my-mdio-bus";
    bus->read      = my_mdio_read;    /* Clause 22 okuma */
    bus->write     = my_mdio_write;   /* Clause 22 yazma */
    bus->read_c45  = my_mdio_read_c45;  /* Clause 45 — isteğe bağlı */
    bus->write_c45 = my_mdio_write_c45;
    bus->parent    = &pdev->dev;
    snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);

    ret = of_mdiobus_register(bus, pdev->dev.of_node);
    if (ret) {
        dev_err(&pdev->dev, "MDIO bus kaydı başarısız: %d\n", ret);
        return ret;
    }
    return 0;
}

/* Clause 22 okuma örneği */
static int my_mdio_read(struct mii_bus *bus, int phy_addr, int reg)
{
    struct my_priv *priv = bus->priv;
    u32 cmd, val;
    int timeout = 1000;

    cmd = MDIO_RD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16);
    writel(cmd, priv->base + MDIO_CMD);

    while (timeout-- && (readl(priv->base + MDIO_STATUS) & MDIO_BUSY))
        udelay(1);

    if (timeout < 0)
        return -ETIMEDOUT;

    val = readl(priv->base + MDIO_DATA);
    return val & 0xffff;
}

mdio_read / mdio_write yardımcı fonksiyonları

c
/* Kullanıcı alanından da mdio_read/write çağrılabilir */
/* Kernel içinde direkt: */
int val = mdiobus_read(bus, phy_addr, MII_BMSR);
mdiobus_write(bus, phy_addr, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_PAUSE_CAP);

/* Clause 45: */
int val = mdiobus_c45_read(bus, phy_addr, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
mdiobus_c45_write(bus, phy_addr, MDIO_MMD_PMAPMD, MDIO_CTRL1, MDIO_CTRL1_RESET);

Bu bölümde

  • MDIO: MDC (saat) + MDIO (veri), 32 PHY adresi, 2.5 MHz maks.
  • Clause 22: 32 register; Clause 45: 65536 register/MMD — 10G+ için zorunlu
  • of_mdiobus_register() cihaz ağacından PHY adreslerini otomatik tarar

02 phylib — phy_device ve bağlantı yönetimi

phylib, Linux'ta Ethernet PHY sürücülerinin standart çerçevesidir. Her fiziksel PHY için bir phy_device nesnesi oluşturur ve durum makinesini yönetir.

phy_device yaşam döngüsü

mdiobus_scan()
    │
    ├─ phy_device_create()   ← PHY ID okunur, phy_device ayrılır
    │
    phy_connect()            ← MAC sürücüsü PHY'ye bağlanır
    │
    phy_start()              ← durum makinesi başlar
    │
    ┌─ PHY_DOWN → PHY_NOLINK → PHY_RUNNING
    │        link değişiminde adjust_link() çağrılır
    │
    phy_stop()               ← durum makinesi durdurulur
    │
    phy_disconnect()         ← bağlantı kopar

phy_connect ve adjust_link

c
/* MAC sürücüsünde PHY bağlantısı */
static void my_adjust_link(struct net_device *ndev)
{
    struct my_priv *priv = netdev_priv(ndev);
    struct phy_device *phydev = ndev->phydev;
    bool changed = false;

    if (priv->speed != phydev->speed) {
        priv->speed = phydev->speed;
        changed = true;
    }
    if (priv->duplex != phydev->duplex) {
        priv->duplex = phydev->duplex;
        changed = true;
    }

    if (changed || priv->link != phydev->link) {
        priv->link = phydev->link;
        if (phydev->link)
            my_mac_set_speed(priv, phydev->speed, phydev->duplex);
        else
            my_mac_link_down(priv);
        phy_print_status(phydev);
    }
}

static int my_open(struct net_device *ndev)
{
    struct my_priv *priv = netdev_priv(ndev);
    struct phy_device *phydev;

    phydev = of_phy_connect(ndev,
                            priv->phy_node,
                            my_adjust_link,
                            0,
                            PHY_INTERFACE_MODE_RGMII_ID);
    if (IS_ERR(phydev))
        return PTR_ERR(phydev);

    phy_start(phydev);
    return 0;
}

static int my_stop(struct net_device *ndev)
{
    phy_stop(ndev->phydev);
    phy_disconnect(ndev->phydev);
    return 0;
}

PHY durum makinesi

PHY_DOWNPHY henüz başlatılmamış veya bağlantı kesilmiş
PHY_NOLINKPHY çalışıyor, bağlantı yok; periyodik polling devam eder
PHY_RUNNINGLink aktif; adjust_link() çağrılmış, trafik iletimi mümkün
PHY_HALTEDphy_stop() çağrıldı; anket ve interrupt devre dışı
PHY_ERRORRead/write hatası; sürücü yeniden başlatma deneyebilir

genphy_* yardımcı fonksiyonları

Özel bir PHY sürücüsü yazılmadığında Linux, BMSR/BMCR register'larını standart okuma kabiliyetine sahip genphy sürücüsünü kullanır. Özel sürücüler bu fonksiyonları çağırabilir:

c
genphy_config_init(phydev);      /* Özellik maskesi — 1G/100M/10M */
genphy_config_aneg(phydev);      /* Auto-negotiation başlat */
genphy_update_link(phydev);      /* BMSR okunur, link durumu güncellenir */
genphy_read_status(phydev);      /* Hız, duplex, link durumu toplu güncelle */
genphy_restart_aneg(phydev);     /* Auto-neg yeniden başlat (BMCR ANRESTART) */
genphy_suspend(phydev);          /* PHY'yi güç tasarruf moduna al */
genphy_resume(phydev);           /* PHY'yi uyandır */

Bu bölümde

  • phy_connect()phy_start() → link değişiminde adjust_link()
  • phylib durum makinesi polling veya interrupt ile çalışabilir
  • genphy_* fonksiyonları standart Clause 22 işlemlerini kapsüller

03 phylink — modern MAC-PHY adaptör katmanı

phylink, 2016'dan itibaren eklenen yeni bir API'dir; MAC ve PHY'yi daha sıkı entegre eder, SFP modüllerini ve birden fazla link modu olasılığını zarif şekilde yönetir.

phylib ile phylink karşılaştırması

Özellikphylib (eski)phylink (yeni)
SFP desteğiYokYerleşik sfp-bus entegrasyonu
MAC konfigürasyonuadjust_link() callbackmac_config() + mac_link_up()
Birden fazla arayüz moduSınırlıEvet, runtime değişim
Fixed-linkSınırlıDoğrudan desteklenir
PAUSE çerçevesi yönetimiManuelOtomatik
InBand signallingYok1000BASE-X, SGMII desteği

phylink_ops — MAC tarafı callback'ler

c
static void my_mac_validate(struct phylink_config *config,
                             unsigned long *supported,
                             struct phylink_link_state *state)
{
    __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };

    /* MAC'in desteklediği modları belirt */
    phylink_set(mask, Autoneg);
    phylink_set(mask, Pause);
    phylink_set(mask, Asym_Pause);
    phylink_set_port_modes(mask);
    phylink_set(mask, 1000baseT_Full);
    phylink_set(mask, 100baseT_Full);
    phylink_set(mask, 10baseT_Half);
    phylink_set(mask, 10baseT_Full);

    if (state->interface == PHY_INTERFACE_MODE_RGMII ||
        state->interface == PHY_INTERFACE_MODE_RGMII_ID) {
        phylink_set(mask, 1000baseT_Full);
    }

    linkmode_and(supported, supported, mask);
    linkmode_and(state->advertising, state->advertising, mask);
}

static void my_mac_config(struct phylink_config *config, unsigned int mode,
                           const struct phylink_link_state *state)
{
    struct my_priv *priv = container_of(config, struct my_priv, phylink_config);
    /* Hız/duplex değiştiğinde MAC register'larını güncelle */
    my_mac_update_registers(priv, state->speed, state->duplex, state->pause);
}

static void my_mac_link_down(struct phylink_config *config, unsigned int mode,
                              phy_interface_t interface)
{
    struct my_priv *priv = container_of(config, struct my_priv, phylink_config);
    my_mac_disable_tx_rx(priv);
}

static void my_mac_link_up(struct phylink_config *config,
                            struct phy_device *phy,
                            unsigned int mode, phy_interface_t interface,
                            int speed, int duplex,
                            bool tx_pause, bool rx_pause)
{
    struct my_priv *priv = container_of(config, struct my_priv, phylink_config);
    my_mac_set_speed_duplex(priv, speed, duplex);
    my_mac_set_pause(priv, tx_pause, rx_pause);
    my_mac_enable_tx_rx(priv);
}

static const struct phylink_mac_ops my_phylink_ops = {
    .validate        = my_mac_validate,
    .mac_config      = my_mac_config,
    .mac_link_down   = my_mac_link_down,
    .mac_link_up     = my_mac_link_up,
};

phylink oluşturma ve başlatma

c
static int my_probe(struct platform_device *pdev)
{
    struct my_priv *priv = /* ... */;
    struct phylink *pl;

    priv->phylink_config.dev = &ndev->dev;
    priv->phylink_config.type = PHYLINK_NETDEV;

    pl = phylink_create(&priv->phylink_config,
                        of_fwnode_handle(pdev->dev.of_node),
                        priv->phy_mode,
                        &my_phylink_ops);
    if (IS_ERR(pl))
        return PTR_ERR(pl);

    priv->phylink = pl;
    return 0;
}

/* ndo_open içinde */
phylink_start(priv->phylink);

/* ndo_stop içinde */
phylink_stop(priv->phylink);
phylink_disconnect_phy(priv->phylink);

Bu bölümde

  • phylink; SFP, fixed-link ve normal PHY'yi tek API ile yönetir
  • MAC tarafı: validate, mac_config, mac_link_down, mac_link_up
  • Yeni sürücüler phylib yerine phylink kullanmalıdır

04 PHY sürücüsü yazmak

Standart genphy sürücüsü çoğu PHY için yeterlidir. Ancak özel register'lar, vendor-specific özellikler veya enerji tasarrufu modu gerektiren durumlarda özel bir PHY sürücüsü yazılır.

phy_driver yapısı

c
/* drivers/net/phy/myvendor.c */
#include <linux/phy.h>
#include <linux/module.h>

/* Vendor PHY ID — PHYIDR1:PHYIDR2 register'larından alınır */
#define MYPHY_ID       0x0283BC30
#define MYPHY_ID_MASK  0xFFFFFFF0

/* Vendor özel register'lar */
#define MYPHY_EXT_CTRL       0x17
#define MYPHY_EXT_CTRL_CLKOUT  BIT(0)
#define MYPHY_LED_CTRL       0x18
#define MYPHY_LED_LINK_ACT   (0x6 << 4)

static int myphy_config_init(struct phy_device *phydev)
{
    int val, ret;

    /* Standart başlatma */
    ret = genphy_config_init(phydev);
    if (ret < 0)
        return ret;

    /* Enerji tasarruf modunu etkinleştir */
    val = phy_read(phydev, MYPHY_EXT_CTRL);
    if (val < 0)
        return val;

    val |= MYPHY_EXT_CTRL_CLKOUT;
    ret = phy_write(phydev, MYPHY_EXT_CTRL, val);
    if (ret)
        return ret;

    /* LED modunu ayarla: Link/Activity */
    ret = phy_write(phydev, MYPHY_LED_CTRL, MYPHY_LED_LINK_ACT);
    return ret;
}

static int myphy_read_status(struct phy_device *phydev)
{
    int ret;

    /* Standart okuma + vendor-specific durum 
     * Burada EEE (Energy Efficient Ethernet) kontrolü de yapılabilir */
    ret = genphy_read_status(phydev);
    if (ret)
        return ret;

    /* Vendor özel kablo tanısı — isteğe bağlı */
    phydev->mdix = ETH_TP_MDI_AUTO;
    return 0;
}

static int myphy_config_aneg(struct phy_device *phydev)
{
    /* Vendor özel ayarlar yapıldıktan sonra standart auto-neg */
    return genphy_config_aneg(phydev);
}

static struct phy_driver myphy_drivers[] = {
    {
        PHY_ID_MATCH_MODEL(MYPHY_ID),
        .name           = "MyVendor PHY",
        .features       = PHY_GBIT_FEATURES,
        .flags          = PHY_HAS_INTERRUPT,
        .config_init    = myphy_config_init,
        .config_aneg    = myphy_config_aneg,
        .read_status    = myphy_read_status,
        .ack_interrupt  = myphy_ack_interrupt,
        .config_intr    = myphy_config_intr,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
    },
};

module_phy_driver(myphy_drivers);

static const struct mdio_device_id __maybe_unused myphy_tbl[] = {
    { MYPHY_ID, MYPHY_ID_MASK },
    { }
};
MODULE_DEVICE_TABLE(mdio, myphy_tbl);
MODULE_AUTHOR("Emirhan Pehlevan");
MODULE_DESCRIPTION("MyVendor PHY sürücüsü");
MODULE_LICENSE("GPL");

PHY ID nasıl bulunur

PHYIDR1 (register 0x02) üst 16 bit OUI içerir; PHYIDR2 (0x03) model ve revizyon bilgisi taşır. ethtool -i ethX komutu veya cat /sys/bus/mdio_bus/devices/*/phy_id bu değeri verir. Veri sayfasında "PHY Identifier Register" başlığı altında kontrol edilmelidir.

Bu bölümde

  • PHY ID: PHYIDR1 + PHYIDR2 registerlarından oluşur, mask ile eşleştirilir
  • phy_driver struct: config_init, read_status, config_aneg minimum alanları
  • Çoğu durumda genphy_* çağırıp vendor özelliklerini eklemek yeterlidir

05 PHY interrupt ve link değişimi

PHY link değişimini algılamanın iki yolu vardır: periyodik polling (basit ama CPU'yu meşgul eder) ve interrupt tabanlı yaklaşım (verimli, donanım desteği gerekir).

Polling vs interrupt

YöntemAvantajDezavantaj
Polling (PHY_POLL)Tüm PHY'lerde çalışır, basitHer 1s'de schedule_delayed_work, CPU kullanımı
InterruptAnlık tepki, CPU tasarrufuPHY'nin interrupt çıkışı olmalı, GPIO bağlantısı gerekir

Interrupt callback'leri

c
/* PHY interrupt kaynağını temizle (ack) */
static int myphy_ack_interrupt(struct phy_device *phydev)
{
    int val;
    /* Interrupt Status Register okunarak bit'ler temizlenir */
    val = phy_read(phydev, MYPHY_ISR);
    return (val < 0) ? val : 0;
}

/* Interrupt'ı etkinleştir/devre dışı bırak */
static int myphy_config_intr(struct phy_device *phydev)
{
    int val, ret;

    if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
        ret = myphy_ack_interrupt(phydev);
        if (ret)
            return ret;
        /* IMR register'ına link up/down mask'ı yaz */
        val = MYPHY_IMR_LINK_UP | MYPHY_IMR_LINK_DOWN;
        ret = phy_write(phydev, MYPHY_IMR, val);
    } else {
        ret = phy_write(phydev, MYPHY_IMR, 0);
        if (ret)
            return ret;
        ret = myphy_ack_interrupt(phydev);
    }
    return ret;
}

/* Yeni API: handle_interrupt (Linux 5.12+) */
static irqreturn_t myphy_handle_interrupt(struct phy_device *phydev)
{
    int irq_status;

    irq_status = phy_read(phydev, MYPHY_ISR);
    if (irq_status < 0) {
        phy_error(phydev);
        return IRQ_NONE;
    }

    if (!(irq_status & (MYPHY_ISR_LINK_UP | MYPHY_ISR_LINK_DOWN)))
        return IRQ_NONE;

    phy_trigger_machine(phydev);
    return IRQ_HANDLED;
}

genphy_update_link detayı

genphy_update_link() BMSR register'ını iki kez okur (latch-low bit için). İkinci okuma gerçek değeri yansıtır. Link takibinde bu davranış kritiktir; tek okuma yanlış link down bildirebilir.

c
/* Kernel kaynak: drivers/net/phy/phy_device.c */
int genphy_update_link(struct phy_device *phydev)
{
    int status, bmcr;

    bmcr = phy_read(phydev, MII_BMCR);
    if (bmcr < 0)
        return bmcr;

    /* Loopback modda link her zaman var */
    if (bmcr & BMCR_LOOPBACK) {
        phydev->link = 1;
        return 0;
    }

    /* Birinci okuma latch-low bit'i temizler */
    status = phy_read(phydev, MII_BMSR);
    if (status < 0)
        return status;

    /* İkinci okuma gerçek anlık değeri döndürür */
    status = phy_read(phydev, MII_BMSR);
    if (status < 0)
        return status;

    if (status & BMSR_LSTATUS)
        phydev->link = 1;
    else
        phydev->link = 0;
    return 0;
}

Bu bölümde

  • PHY_HAS_INTERRUPT bayrak — interrupt etkin; yoksa PHY_POLL modu (1 sn polling)
  • Linux 5.12+: handle_interrupt callback; eski API: ack_interrupt + config_intr
  • BMSR iki kez okunmalı: birinci okuma "latch-low" bit'i temizler

06 SFP modül desteği

SFP (Small Form-factor Pluggable) modüller, fiber ve bakır arayüzler arasında hot-plug geçiş imkânı sunar. Linux phylink ile sfp-bus alt sistemi bu modülleri otomatik yönetir.

SFP-bus mimarisi

SFP konnektör (I2C + MDIO + GPIO)
         │
    sfp_bus (drivers/net/sfp-bus.c)
         │
    ┌────┴────────────┐
    │                 │
 SFP sürücüsü     phylink upstream
 (sfp.c)          (MAC sürücüsü)
    │                 │
  EEPROM           mac_config()
  SFP+1000BASE-SX  mac_link_up()

sfp_register_upstream

c
/* phylink oluşturduktan sonra SFP upstream kaydı */
static int my_probe(struct platform_device *pdev)
{
    struct my_priv *priv;
    struct sfp_bus *sfp_bus;
    int ret;

    /* ... phylink oluştur ... */

    /* Cihaz ağacında sfp = <&sfp_node> varsa otomatik bağlanır */
    ret = phylink_of_phy_connect(priv->phylink,
                                  pdev->dev.of_node, 0);
    if (ret)
        return ret;

    return 0;
}

/* Düşük seviyeli sfp_bus doğrudan kullanım (nadiren gerekir): */
sfp_bus = sfp_register_upstream(fwnode, &priv->phylink_config, upstream_ops);
if (IS_ERR(sfp_bus))
    return PTR_ERR(sfp_bus);
priv->sfp_bus = sfp_bus;

SFP EEPROM ve modül türleri

1000BASE-SXÇok modlu fiber, 850 nm, <550 m; SFP EEPROM byte 6 bit 0
1000BASE-LXTek modlu fiber, 1310 nm, <10 km; uzak mesafe endüstriyel
1000BASE-TBakır (copper) SFP; PHY entegre, MDIO ile yönetilir
SFP+ 10GBase-SR10 Gb/s kısa mesafe; sfp-bus bunu destekler, MAC 10G uyumlu olmalı
DACDirect Attach Copper; kısa bakır kablo, SFP+ konnektörle bitmiş

Device Tree SFP tanımı

dts
sfp0: sfp-connector {
    compatible = "sff,sfp";
    i2c-bus = <&i2c1>;
    los-gpios   = <&gpio 14 GPIO_ACTIVE_HIGH>;
    mod-def0-gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
    tx-fault-gpios = <&gpio 16 GPIO_ACTIVE_HIGH>;
    tx-disable-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
    maximum-power-milliwatt = <1000>;
};

&gmac0 {
    phy-mode = "sgmii";
    sfp = <&sfp0>;
    managed = "in-band-status";
};

Bu bölümde

  • sfp-bus, modül takma/çıkarma olaylarını yakalar ve phylink'e bildirir
  • SFP EEPROM (I2C adres 0x50) modül türü, güç, alıcı özelliklerini içerir
  • LOS, MOD-DEF0, TX-FAULT GPIO'ları cihaz ağacında tanımlanmalıdır

07 Device Tree binding

Ethernet PHY'lerin donanım açıklaması, cihaz ağacında (Device Tree) standartlaşmış bir bağlama (binding) ile yapılır. Bu bölümde yaygın senaryolar ve dikkat edilmesi gereken noktalar açıklanır.

Temel MDIO + PHY binding

dts
/* MAC düğümü */
&gmac {
    status = "okay";
    phy-mode = "rgmii-id";          /* RGMII, MAC her iki gecikmeyi uygular */
    phy-handle = <&phy0>;          /* Hangi PHY'ye bağlı */
    pinctrl-names = "default";
    pinctrl-0 = <&gmac_pins>;
};

/* MDIO bus */
&mdio {
    status = "okay";
    /* PHY reset GPIO — zorunlu değil ama önerilir */
    reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
    reset-deassert-us = <10000>;
    reset-post-delay-us = <100000>;

    phy0: ethernet-phy@0 {          /* @N = MDIO adresi */
        reg = <0>;                  /* MDIO adres 0 */
        compatible = "ethernet-phy-id0283.bc30",  /* PHYID ile eşleşme */
                     "ethernet-phy-ieee802.3-c22"; /* Clause 22 fallback */
        interrupt-parent = <&gpio>;
        interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
        /* RGMII gecikme ayarları (DP83867 özel özelliği) */
        ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
        ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
        ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
    };
};

fixed-link — PHY olmayan bağlantılar

Switch chip'e sabit bağlı bir MAC gibi MDIO erişimi olmayan durumlar için fixed-link kullanılır:

dts
&gmac1 {
    status = "okay";
    phy-mode = "rgmii";
    fixed-link {
        speed    = <1000>;
        full-duplex;
        pause;
        asym-pause;
    };
};

Önemli DT özellik tablosu

ÖzellikDeğer örneğiAçıklama
phy-mode"rgmii-id"MAC-PHY arayüz modu
phy-handle<&phy0>MDIO bus'taki PHY phandle referansı
managed"in-band-status"SGMII/1000BASE-X in-band link bilgisi
reset-gpios<&gpio 10 ACTIVE_LOW>PHY hardware reset pini
reset-deassert-us<10000>Reset deassert bekleme süresi (µs)
max-speed<100>Hız kısıtı — 100 Mb/s ile sınırla
ethernet-phy-id0x0283bc30Vendor-specific uyumluluk dizgisi

Bu bölümde

  • ethernet-phy@N düğümünde reg MDIO adresini verir
  • reset-gpios + zamanlamalar — kararlı başlatma için mutlaka ekleyin
  • fixed-link switch-entegre bağlantılarda MDIO gerektirmez

08 Hata ayıklama

PHY ve phylink sorunlarını izlemek için çekirdek içi araçlardan kullanıcı alanı yardımcı programlarına kadar kapsamlı bir araç seti mevcuttur.

ethtool ile temel tanılama

bash
# Bağlantı hızı, duplex, auto-neg durumu
ethtool eth0

# Sürücü bilgisi ve bus-info
ethtool -i eth0

# PHY register'larını oku (clause 22)
ethtool -d eth0

# Belirli MII register oku (BMSR = reg 1)
ethtool --dump-module eth0

# Hız ve duplex zorla (auto-neg bypass)
ethtool -s eth0 speed 100 duplex full autoneg off

# PHY istatistikleri
ethtool --phy-statistics eth0

# EEE (Energy Efficient Ethernet) durumu
ethtool --show-eee eth0

mii-tool ile düşük seviye okuma

bash
# Bağlantı durumu
mii-tool eth0

# Ayrıntılı çıktı
mii-tool -v eth0

# Auto-neg yeniden başlat
mii-tool -r eth0

/sys/bus/mdio_bus ile register keşfi

bash
# Sistemdeki MDIO bus'ları listele
ls /sys/bus/mdio_bus/devices/

# PHY ID (PHYIDR1:PHYIDR2)
cat /sys/bus/mdio_bus/devices/0000:00/phy_id

# PHY sürücüsü
cat /sys/bus/mdio_bus/devices/0000:00/modalias

# Bağlantı parametreleri
cat /sys/bus/mdio_bus/devices/0000:00/link

# phylink durum makinesi (debugfs)
cat /sys/kernel/debug/phylink/eth0

phylink durum makinesi izleme

bash
# Kernel log — phylink durum geçişleri
dmesg | grep -E "phylink|PHY|eth0"

# Dinamik debug etkinleştir
echo "module phylink +p" > /sys/kernel/debug/dynamic_debug/control
echo "module phy_device +p" > /sys/kernel/debug/dynamic_debug/control

# MDIO register dump (mdio-tools paketi)
mdio-tool read 0 BMSR
mdio-tool read 0 PHYIDR1
mdio-tool read 0 PHYIDR2

Yaygın sorunlar ve çözümleri

BelirtiOlası NedenÇözüm
Link yok, PHY bulunamıyorReset GPIO eksik veya hatalıDT'de reset-gpios ve zamanlamaları kontrol et
Link var, paket kaybı/hataRGMII gecikme yanlışphy-mode ve vendor delay register'larını kontrol et
Hız 10M'a düşüyorKablo hasarı veya auto-neg uyumsuzluğuethtool -s speed 100 duplex full autoneg off ile test et
PHY ID 0xFFFFMDIO bağlantı sorunu veya yanlış adresMDC/MDIO pinlerini ve DT reg değerini doğrula
SFP modül algılanmıyorMOD-DEF0 GPIO polaritesi yanlışDT'de ACTIVE_HIGH/LOW flag'ini kontrol et

Bu bölümde

  • ethtool -d eth0 ham MII register dump'ı döküm alır
  • /sys/bus/mdio_bus/devices/ tüm MDIO cihazlarını sysfs'ten gösterir
  • dynamic_debug ile phylink ve phy_device modüllerinde verbose log etkinleştirilebilir
  • PHY ID 0xFFFF → MDIO veri yolu bağlantı sorunu (MDC/MDIO pinleri veya güç)