linux DSA 开发上手笔记(一)
与 DSA 相关的代码
./net/dsa/*
./drivers/net/dsa/*
./net/dsa/Kconfig
# net/dsa/Kconfig 里面主要定义了以下CONFIG选项
NET_DSA
NET_DSA_TAG_8021Q
NET_DSA_TAG_xxx
./net/dsa/Makefile
# SPDX-License-Identifier: GPL-2.0
# the core
obj-$(CONFIG_NET_DSA) += dsa_core.o
dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o
# tagging formats
obj-$(CONFIG_NET_DSA_TAG_8021Q) += tag_8021q.o
obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
由此可见核心代码是:
obj-$(CONFIG_NET_DSA) += dsa_core.o
dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o
./drivers/net/dsa/Makefile
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm-sf2.o
bcm-sf2-objs := bcm_sf2.o bcm_sf2_cfp.o
obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o
ifdef CONFIG_NET_DSA_LOOP
obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o
endif
obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
obj-y += b53/
obj-y += microchip/
obj-y += mv88e6xxx/
obj-y += sja1105/
# 这里是不同厂家switch 驱动
以 mt7530.c 为例,学习 dsa switch 驱动的写法
static struct mdio_driver mt7530_mdio_driver = {
.probe = mt7530_probe,
.remove = mt7530_remove,
.mdiodrv.driver = {
.name = "mt7530",
.of_match_table = mt7530_of_match,
},
};
mdio_module_driver(mt7530_mdio_driver);
要点:是用 mdio_module_driver
/**
* mdio_module_driver() - Helper macro for registering mdio drivers
*
* Helper macro for MDIO drivers which do not do anything special in module
* init/exit. Each module may only use this macro once, and calling it
* replaces module_init() and module_exit().
*/
#define mdio_module_driver(_mdio_driver) \
static int __init mdio_module_init(void) \
{ \
return mdio_driver_register(&_mdio_driver); \
} \
module_init(mdio_module_init); \
static void __exit mdio_module_exit(void) \
{ \
mdio_driver_unregister(&_mdio_driver); \
} \
module_exit(mdio_module_exit)
mt7530_probe
static int
mt7530_probe(struct mdio_device *mdiodev)
{
//...
priv->bus = mdiodev->bus;
priv->dev = &mdiodev->dev;
priv->ds->priv = priv;
priv->ds->ops = &mt7530_switch_ops; //关键代码
mutex_init(&priv->reg_mutex);
dev_set_drvdata(&mdiodev->dev, priv);
return dsa_register_switch(priv->ds); //关键代码
}
关键在于 mt7530_switch_ops 和 dsa_register_switch
mt7530_switch_ops
static const struct dsa_switch_ops mt7530_switch_ops = {
.get_tag_protocol = mtk_get_tag_protocol,
.setup = mt7530_setup,
.get_strings = mt7530_get_strings,
.phy_read = mt7530_phy_read,
.phy_write = mt7530_phy_write,
.get_ethtool_stats = mt7530_get_ethtool_stats,
.get_sset_count = mt7530_get_sset_count,
.port_enable = mt7530_port_enable,
.port_disable = mt7530_port_disable,
.port_stp_state_set = mt7530_stp_state_set,
.port_bridge_join = mt7530_port_bridge_join,
.port_bridge_leave = mt7530_port_bridge_leave,
.port_fdb_add = mt7530_port_fdb_add,
.port_fdb_del = mt7530_port_fdb_del,
.port_fdb_dump = mt7530_port_fdb_dump,
.port_vlan_filtering = mt7530_port_vlan_filtering,
.port_vlan_prepare = mt7530_port_vlan_prepare,
.port_vlan_add = mt7530_port_vlan_add,
.port_vlan_del = mt7530_port_vlan_del,
.phylink_validate = mt7530_phylink_validate,
.phylink_mac_link_state = mt7530_phylink_mac_link_state,
.phylink_mac_config = mt7530_phylink_mac_config,
.phylink_mac_link_down = mt7530_phylink_mac_link_down,
.phylink_mac_link_up = mt7530_phylink_mac_link_up,
};
定义了一些关键函数。
小结 :
- dsa switch 驱动本身是 mdio 设备驱动
- dsa switch 驱动的核心是实现 struct dsa_switch_ops 结构体
dts 写法
ð {
status = "okay";
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
reg = <0>;
phy-mode = "trgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
mdio: mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
switch@0 {
compatible = "mediatek,mt7530";
reg = <0>;
reset-gpios = <&pio 33 0>;
core-supply = <&mt6323_vpa_reg>;
io-supply = <&mt6323_vemc3v3_reg>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "wan";
};
port@1 {
reg = <1>;
label = "lan0";
};
port@2 {
reg = <2>;
label = "lan1";
};
port@3 {
reg = <3>;
label = "lan2";
};
port@4 {
reg = <4>;
label = "lan3";
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&gmac0>;
phy-mode = "trgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
};
};
};
};
详见:Documentation/devicetree/bindings/net/dsa/dsa.txt
dsa switch 驱动的骨架
static const struct dsa_switch_ops mt7530_switch_ops = {
};
static const struct of_device_id mt7530_of_match[] = {
{ .compatible = "mediatek,mt7621", .data = (void *)ID_MT7621, },
{ .compatible = "mediatek,mt7530", .data = (void *)ID_MT7530, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mt7530_of_match);
static int
mt7530_probe(struct mdio_device *mdiodev)
{
}
static void
mt7530_remove(struct mdio_device *mdiodev)
{
}
static struct mdio_driver mt7530_mdio_driver = {
.probe = mt7530_probe,
.remove = mt7530_remove,
.mdiodrv.driver = {
.name = "mt7530",
.of_match_table = mt7530_of_match,
},
};
mdio_module_driver(mt7530_mdio_driver);
MODULE_LICENSE("GPL");