This paper takes the Stmmac drive registration process of HiSilicon 3535 as an example to introduce the network-driven detection and network equipment detection process. Original Address http://blog.csdn.net/linchuanzhi_886/article/details/44458713
1. Because we are using Ethernet, we return a struct Net_device address Ndev directly with the Alloc_etherdev () function.
In the process of Alloc_ether, Ndev->dev->name will be assigned to "eth%"
2. After the first step succeeds, obtains the STMMAC resources, including memory, interrupts.
3. Initialize MAC information. It is mainly based on the ability of MAC controller to assign value to Mac_device_info result body member. such as full/Half-duplex mode, 10/100/1000mbps, and read MAC address, if the MAC address is invalid, automatically assign a MAC address. There is a DMA operation function inside.
4. ' Static int stmmac_mac_device_setup (struct net_device *dev)
{
struct Stmmac_priv *priv = Netdev_priv (dev);
struct Mac_device_info *device;
if (PRIV->PLAT->HAS_GMAC)
device = Dwmac1000_setup (PRIV->IOADDR);
else
device = Dwmac100_setup (PRIV->IOADDR);
if (!device)
Return-enomem;
if (priv->plat->enh_desc) {
Device->desc = &enh_desc_ops;
Pr_info ("\tenhanced descriptor structure\n");
} else
Device->desc = &ndesc_ops;
PRIV->HW = device;**** return
0;
}
`
struct mac_device_info *dwmac1000_setup (void __iomem *ioaddr) {struct mac_device_info;
U32 uid = READL (ioaddr + gmac_version); PRINTK ("\tdwmac1000-user id:0x%x, Synopsys id:0x%x\n", ((UID & 0x0000ff00) >> 8), (UID & 0x00000
0FF));
Mac = Kzalloc (sizeof (const struct mac_device_info), gfp_kernel);
if (!MAC) return NULL;
Mac->mac = &dwmac1000_ops;
MAC->DMA = &dwmac1000_dma_ops;
Mac->link.port = Gmac_control_ps;
Mac->link.duplex = GMAC_CONTROL_DM;
Mac->link.speed = Gmac_control_fes;
MAC->MII.ADDR = gmac_mii_addr;
Mac->mii.data = Gmac_mii_data;
return mac; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 1 2 3 4-5--6 7---8 9--10 11 12 13 14 15 16-17 18 19 20
const struct Stmmac_dma_ops dwmac1000_dma_ops = {. init = Dwmac1000_dma_init,. Dump_regs = Dwmac1000_dump_dma_regs ,. Dma_mode = Dwmac1000_dma_operation_mode,. enable_dma_transmission = Dwmac_enable_dma_transmission,. Enable_ DMA_IRQ = Dwmac_enable_dma_irq,. Disable_dma_irq = Dwmac_disable_dma_irq,. Start_tx = Dwmac_dma_start_tx,. Sto P_tx = Dwmac_dma_stop_tx,. Start_rx = Dwmac_dma_start_rx,. Stop_rx = Dwmac_dma_stop_rx,. Dma_interrupt = Dwmac
_dma_interrupt,. get_hw_feature = Dwmac1000_get_hw_feature,}; static const struct Stmmac_ops dwmac1000_ops = {. Core_init = Dwmac1000_core_init,. Rx_coe = Dwmac1000_rx_coe_supp orted,. Dump_regs = Dwmac1000_dump_regs,. host_irq_status = Dwmac1000_irq_status,. Set_filter = dwmac1000_set_
Filter,. Flow_ctrl = Dwmac1000_flow_ctrl,. PMT = Dwmac1000_pmt,. set_umac_addr = Dwmac1000_set_umac_addr,
. get_umac_addr = Dwmac1000_get_umac_addr,};
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18-------------19 20 21 22 23 24 25 26 1-2 3 4 5, 6 22 23 24 25 26
4.ether_setup (dev); set Ndev header information:
void Ether_setup (struct net_device *dev)
{
Dev->header_ops = ð_header_ops;
Dev->type = arphrd_ether;//1
Dev->hard_header_len = ETH_HLEN;//14
dev->mtu = ETH_ data_len;//1500
Dev->addr_len = ETH_ALEN;//6
Dev->tx_queue_len = 1000;/* Ethernet wants Good queues * *
dev->flags = iff_broadcast| Iff_multicast;
Dev->priv_flags |= iff_tx_skb_sharing;
memset (Dev->broadcast, 0xFF, Eth_alen);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Fill in the Ndev netdev_ops, realize the network device open, occur, stop, timeout processing functions, IOCTL call.
' Static const struct Net_device_ops Stmmac_netdev_ops = {
. Ndo_open = Stmmac_open,
. Ndo_start_xmit = Stmmac_xmit,
. Ndo_stop = Stmmac_release,
. NDO_CHANGE_MTU = Stmmac_change_mtu,
. Ndo_set_rx_mode = Stmmac_multicast_list,
. ndo_tx_timeout = Stmmac_tx_timeout,
. Ndo_do_ioctl = Stmmac_ioctl,
. Ndo_set_config = Stmmac_config, ifdef stmmac_vlan_tag_used
. Ndo_vlan_rx_register = Stmmac_vlan_rx_register,
endif
ifdef Config_net_poll_controller
. Ndo_poll_controller = Stmmac_poll_controller,
endif
. ndo_set_mac_address = Stmmac_eth_mac_addr,
' Now the kernel basically supports ethtool, filling the Ndev ethtooll_ops.
((Netdev)->ethtool_ops = (OPS)
static struct Ethtool_ops Stmmac_ethtool_ops = {. Begin = stmmac_check_if_running,. Get_drvinfo = Stmmac_ethtool_g Etdrvinfo,. get_settings = Stmmac_ethtool_getsettings,. set_settings = Stmmac_ethtool_setsettings,. Get_msglev
El = Stmmac_ethtool_getmsglevel,. set_msglevel = Stmmac_ethtool_setmsglevel,. Get_regs = Stmmac_ethtool_gregs, . Get_regs_len = Stmmac_ethtool_get_regs_len,. Get_link = Ethtool_op_get_link,. Get_pauseparam = Stmmac_get_pausep Aram,. Set_pauseparam = Stmmac_set_pauseparam,. get_ethtool_stats = Stmmac_get_ethtool_stats,. get_strings = S Tmmac_get_strings,. Get_wol = Stmmac_get_wol,. Set_wol = Stmmac_set_wol,. Get_sset_count = Stmmac_get_sset_cou
NT,}; 6. Set Watchdog_timeo time in the first 5 steps, can also initialize Mac_device_info, and realize its Mdio_bus bus degree yoke 7.register_netdev (ndev) register to the kernel.
Generates ETH0/1/2 nodes. 8. Initialize the Mdiobus read-write function and register the Bus->dev, then detect the PHY on the Mii bus.
After discovering a valid PHY, perform phy_device_create, Phydev_register.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18-------------19 20 21 22 23 24 25 1 2-3 4 5 6, 7 23 24 25
static struct Mii_bus *stmmac_mii_bus;
int Stmmac_mdio_register (struct net_device *ndev)
{
.......
Stmmac_mii_bus->name = "Stmmac mii bus";
Stmmac_mii_bus->read = &stmmac_mdio_read;
Stmmac_mii_bus->write = &stmmac_mdio_write;
Stmmac_mii_bus->reset = &stmmac_mdio_reset;
snprintf (Stmmac_mii_bus->id, Mii_bus_id_size, "%x"),
PRIV->PLAT->BUS_ID);
Stmmac_mii_bus->priv = Ndev;
STMMAC_MII_BUS->IRQ = irqlist;
Stmmac_mii_bus->phy_mask = priv->phy_mask;
Stmmac_mii_bus->parent = priv->device;
Err = Mdiobus_register (Stmmac_mii_bus);
......
}
int Mdiobus_register (struct Mii_bus *bus)
{
int I, err;
if (NULL = = Bus | |
NULL = = Bus->name | |
NULL = = Bus->read | |
NULL = = bus->write) return-einval;
bug_on (bus->state!= mdiobus_allocated && bus->state!=);
Bus->dev.parent = bus->parent;
Bus->dev.class = &mdio_bus_class;
Bus->dev.groups = NULL;
Dev_set_name (&bus->dev, "%s", Bus->id);
Err = Device_register (&bus->dev);
if (err) {PRINTK (kern_err "Mii_bus%s failed to register\n", bus->id);
Return-einval;
} mutex_init (&bus->mdio_lock);
if (bus->reset) Bus->reset (bus); for (i = 0; i < phy_max_addr i++) {if (Bus->phy_mask & (1 << i)) = = 0) {struct Phy_device
*phydev;
Phydev = Mdiobus_scan (bus, i);
if (Is_err (Phydev)) {ERR = Ptr_err (Phydev);
Goto error;
}} bus->state = mdiobus_registered;
Pr_info ("%s:probed\n", bus->name);
return 0;
Error
while (– I >= 0) {
if (Bus->phy_map[i])
Device_unregister (&bus->phy_map[i]->dev);
}
Device_del (&bus->dev);
return err;
}
1 1
struct Phy_device *mdiobus_scan (struct mii_bus *bus, int addr)
{
struct Phy_device *phydev;
int err;
Phydev = Get_phy_device (bus, addr);
if (Is_err (phydev) | | | | phydev = NULL) return
Phydev;
Err = Phy_device_register (Phydev);
if (err) {
phy_device_free (phydev);
return NULL;
}
return Phydev;
}
struct Phy_device * get_phy_device (struct mii_bus *bus, int addr)
{
struct Phy_device *dev = NULL;
U32 phy_id;
int R;
r = get_phy_id (bus, addr, &phy_id);
if (r) return
Err_ptr (r);
/* If the phy_id is mostly Fs, there is no device there
/if ((phy_id & 0x1fffffff) = = 0x1FFFFFFF) return
NUL L;
dev = phy_device_create (bus, addr, phy_id);
return dev;
}
int get_phy_id (struct mii_bus *bus, int addr, u32 *phy_id)
{
int Phy_reg;
/* Grab the bits from PHYIR1, and put them * in the
upper half
/Phy_reg = Mdiobus_read (bus, addr, mii_physid1); C2/>PRINTK (kern_info "ID1 = 0x%x at%s \ n", phy_reg,bus->name);
if (Phy_reg < 0)
Return-eio;
*phy_id = (Phy_reg & 0xffff) <<;
/* Grab the bits from PHYIR2, and put them in the lower half
/phy_reg = Mdiobus_read (bus, addr, mii_physid2);
PRINTK (kern_info "ID2 = 0x%x at%s \ n", phy_reg,bus->name);
if (Phy_reg < 0)
Return-eio;
*phy_id |= (Phy_reg & 0xFFFF);
return 0;
}
9. Initialize Sk_buff queue header, Skb_queue_head_init. Then the application is interrupted and the interrupt is turned on.