if (unlikely(comm->tx_desc_full == 1)) { /* No TX descriptors left. Wait for tx interrupt. */
netdev_dbg(ndev, "TX descriptor queue full when xmit!\n"); return NETDEV_TX_BUSY;
}
/* If skb size is shorter than ETH_ZLEN (60), pad it with 0. */ if (unlikely(skb->len < ETH_ZLEN)) { if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK;
for (i = 0; i < MAX_NETDEV_NUM; i++) if (comm->ndev[i])
netif_stop_queue(comm->ndev[i]);
spl2sw_mac_soft_reset(comm);
/* Accept TX packets again. */ for (i = 0; i < MAX_NETDEV_NUM; i++) if (comm->ndev[i]) {
netif_trans_update(comm->ndev[i]);
netif_wake_queue(comm->ndev[i]);
}
staticvoid spl2sw_check_mac_vendor_id_and_convert(u8 *mac_addr)
{ /* Byte order of MAC address of some samples are reversed. * Check vendor id and convert byte order if it is wrong. * OUI of Sunplus: fc:4b:bc
*/ if (mac_addr[5] == 0xfc && mac_addr[4] == 0x4b && mac_addr[3] == 0xbc &&
(mac_addr[0] != 0xfc || mac_addr[1] != 0x4b || mac_addr[2] != 0xbc)) {
/* Get nvmem cell of mac-address from dts. */
cell = of_nvmem_cell_get(np, "mac-address"); if (IS_ERR(cell)) return PTR_ERR(cell);
/* Read mac address from nvmem cell. */
mac = nvmem_cell_read(cell, &len);
nvmem_cell_put(cell); if (IS_ERR(mac)) return PTR_ERR(mac);
if (len != ETH_ALEN) {
kfree(mac);
dev_info(dev, "Invalid length of mac address in nvmem!\n"); return -EINVAL;
}
/* Byte order of some samples are reversed. * Convert byte order here.
*/
spl2sw_check_mac_vendor_id_and_convert(mac);
/* Check if mac address is valid */ if (!is_valid_ether_addr(mac)) {
dev_info(dev, "Invalid mac address in nvmem (%pM)!\n", mac);
kfree(mac); return -EINVAL;
}
/* Allocate the devices, and also allocate spl2sw_mac, * we can get it by netdev_priv().
*/
ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*mac)); if (!ndev) {
*r_ndev = NULL; return -ENOMEM;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->netdev_ops = &netdev_ops;
mac = netdev_priv(ndev);
mac->ndev = ndev;
ether_addr_copy(mac->mac_addr, mac_addr);
/* Get memory resource 0 from dts. */
comm->l2sw_reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(comm->l2sw_reg_base)) return PTR_ERR(comm->l2sw_reg_base);
/* Get irq resource from dts. */
ret = platform_get_irq(pdev, 0); if (ret < 0) return ret;
irq = ret;
/* Get clock controller. */
comm->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(comm->clk)) {
dev_err_probe(&pdev->dev, PTR_ERR(comm->clk), "Failed to retrieve clock controller!\n"); return PTR_ERR(comm->clk);
}
/* Get reset controller. */
comm->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(comm->rstc)) {
dev_err_probe(&pdev->dev, PTR_ERR(comm->rstc), "Failed to retrieve reset controller!\n"); return PTR_ERR(comm->rstc);
}
/* Enable clock. */
ret = clk_prepare_enable(comm->clk); if (ret) return ret;
udelay(1);
/* Reset MAC */
reset_control_assert(comm->rstc);
udelay(1);
reset_control_deassert(comm->rstc);
usleep_range(1000, 2000);
/* Request irq. */
ret = devm_request_irq(&pdev->dev, irq, spl2sw_ethernet_interrupt, 0,
dev_name(&pdev->dev), comm); if (ret) {
dev_err(&pdev->dev, "Failed to request irq #%d!\n", irq); goto out_clk_disable;
}
/* Initialize TX and RX descriptors. */
ret = spl2sw_descs_init(comm); if (ret) {
dev_err(&pdev->dev, "Fail to initialize mac descriptors!\n");
spl2sw_descs_free(comm); goto out_clk_disable;
}
/* Initialize MAC. */
spl2sw_mac_init(comm);
/* Initialize mdio bus */
ret = spl2sw_mdio_init(comm); if (ret) {
dev_err(&pdev->dev, "Failed to initialize mdio bus!\n"); goto out_clk_disable;
}
/* Get child node ethernet-ports. */
eth_ports_np = of_get_child_by_name(pdev->dev.of_node, "ethernet-ports"); if (!eth_ports_np) {
dev_err(&pdev->dev, "No ethernet-ports child node found!\n");
ret = -ENODEV; goto out_free_mdio;
}
for (i = 0; i < MAX_NETDEV_NUM; i++) { /* Get port@i of node ethernet-ports. */
port_np = spl2sw_get_eth_child_node(eth_ports_np, i); if (!port_np) continue;
/* Get phy-mode. */ if (of_get_phy_mode(port_np, &phy_mode)) {
dev_err(&pdev->dev, "Failed to get phy-mode property of port@%d!\n",
i); continue;
}
/* Get phy-handle. */
phy_np = of_parse_phandle(port_np, "phy-handle", 0); if (!phy_np) {
dev_err(&pdev->dev, "Failed to get phy-handle property of port@%d!\n",
i); continue;
}
/* Get mac-address from nvmem. */
ret = spl2sw_nvmem_get_mac_address(&pdev->dev, port_np, mac_addr); if (ret == -EPROBE_DEFER) { goto out_unregister_dev;
} elseif (ret) {
dev_info(&pdev->dev, "Generate a random mac address!\n");
eth_random_addr(mac_addr);
}
/* Initialize the net device. */
ret = spl2sw_init_netdev(pdev, mac_addr, &ndev); if (ret) goto out_unregister_dev;
mac->lan_port = 0x1 << i; /* forward to port i */
mac->to_vlan = 0x1 << i; /* vlan group: i */
mac->vlan_id = i; /* vlan group: i */
/* Set MAC address */
ret = spl2sw_mac_addr_add(mac); if (ret) goto out_unregister_dev;
spl2sw_mac_rx_mode_set(mac);
}
/* Find first valid net device. */ for (i = 0; i < MAX_NETDEV_NUM; i++) { if (comm->ndev[i]) break;
} if (i >= MAX_NETDEV_NUM) {
dev_err(&pdev->dev, "No valid ethernet port!\n");
ret = -ENODEV; goto out_free_mdio;
}
/* Save first valid net device */
ndev = comm->ndev[i];
ret = spl2sw_phy_connect(comm); if (ret) {
netdev_err(ndev, "Failed to connect phy!\n"); goto out_unregister_dev;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.