int hieth_mdio_read(struct hieth_mdio_local *ld, int phy_addr, int regnum) { int val = 0; hieth_assert((!(phy_addr & (~0x1F))) && (!(regnum & (~0x1F)))); local_lock(ld); if (!wait_mdio_ready(ld)) { hieth_error("mdio busy"); goto error_exit; } mdio_start_phyread(ld, phy_addr, regnum); if (wait_mdio_ready(ld)) val = mdio_get_phyread_val(ld); else hieth_error("read timeout"); error_exit: local_unlock(ld); hieth_trace(4, "phy_addr = %d, regnum = %d, val = 0x%04x", phy_addr, regnum, val); return val; }
static int hieth_init(void) { int ret = 0; ret = platform_device_register(&hieth_platform_device); if (ret) { hieth_error("register platform device failed!"); goto _error_register_device; } ret = platform_driver_register(&hieth_platform_driver); if (ret) { hieth_error("register platform driver failed!"); goto _error_register_driver; } return ret; _error_register_driver: platform_device_unregister(&hieth_platform_device); _error_register_device: return -1; }
int hieth_mdio_write( struct hieth_mdio_local *ld, int phy_addr, int regnum, int val) { int ret = 0; hieth_assert((!(phy_addr & (~0x1F))) && (!(regnum & (~0x1F)))); hieth_trace(4, "phy_addr = %d, regnum = %d", phy_addr, regnum); local_lock(ld); if (!wait_mdio_ready(ld)) { hieth_error("mdio busy"); ret = -1; goto error_exit; } mdio_phywrite(ld, phy_addr, regnum, val); error_exit: local_unlock(ld); return val; }
static int hieth_init_skb_buffers(struct hieth_netdev_local *ld) { int i; struct sk_buff *skb; for (i = 0; i < CONFIG_HIETH_MAX_RX_POOLS; i++) { skb = dev_alloc_skb(SKB_SIZE); if (!skb) break; ld->rx_pool.sk_pool[i] = skb; } if (i < CONFIG_HIETH_MAX_RX_POOLS) { hieth_error("no mem"); for (i--; i > 0; i--) dev_kfree_skb_any(ld->rx_pool.sk_pool[i]); return -ENOMEM; } ld->rx_pool.next_free_skb = 0; ld->stat.rx_pool_dry_times = 0; return 0; }
static void hieth_bfproc_recv(unsigned long data) { int ret = 0; struct net_device *dev = (void *)data; struct hieth_netdev_local *ld = netdev_priv(dev); struct sk_buff *skb; hieth_hw_recv_tryup(ld); while ((skb = skb_dequeue(&ld->rx_head)) != NULL) { skb->protocol = eth_type_trans(skb, dev); if (HIETH_INVALID_RXPKG_LEN(skb->len)) { hieth_error("pkg len error"); ld->stats.rx_errors++; ld->stats.rx_length_errors++; dev_kfree_skb_any(skb); continue; } ld->stats.rx_packets++; ld->stats.rx_bytes += skb->len; dev->last_rx = jiffies; skb->dev = dev; ret = netif_rx(skb); if (ret) ld->stats.rx_dropped++; } return; }
static int __init hieth_parse_tag(const struct tag *tag) { if (tag->hdr.size != 4) { hieth_error("tag error."); goto err_out; } memcpy(macaddr.sa_data, &tag->u, 6); err_out: return 0; }
static int hieth_net_hard_start_xmit( struct sk_buff *skb, struct net_device *dev) { int ret; struct hieth_netdev_local *ld = netdev_priv(dev); int tx_lpi_assert = 0x2; unsigned int data; data = readl(ld->iobase + 0x488); data &= ~tx_lpi_assert; writel(data, ld->iobase + 0x488); hieth_xmit_release_skb(ld); dma_map_single(ld->dev, skb->data, skb->len, DMA_TO_DEVICE); ret = hieth_xmit_real_send(ld, skb); if (ret < 0) { ld->stats.tx_dropped++; hieth_error("tx bug, drop packet"); BUG(); return NETDEV_TX_BUSY; } dev->trans_start = jiffies; ld->stats.tx_packets++; ld->stats.tx_bytes += skb->len; hieth_clear_irqstatus(ld, UD_BIT_NAME(HIETH_INT_TXQUE_RDY)); if (!hieth_hw_xmitq_ready(ld)) { netif_stop_queue(dev); hieth_irq_enable(ld, UD_BIT_NAME(HIETH_INT_TXQUE_RDY)); } return NETDEV_TX_OK; }
static int hieth_plat_driver_probe(struct platform_device *pdev) { int ret = -1; struct net_device *ndev = NULL; memset(hieth_devs_save, 0, sizeof(hieth_devs_save)); hieth_sys_init(); if (hieth_mdiobus_driver_init(pdev)) { hieth_error("mdio bus init error!\n"); ret = -ENODEV; goto _error_mdiobus_driver_init; } hieth_platdev_probe_port(pdev, UP_PORT); #ifdef CONFIG_HIETH_DOWNPORT_EN hieth_platdev_probe_port(pdev, DOWN_PORT); #endif phy_quirk(&hieth_mdio_local_device, CONFIG_HIETH_PHYID_U); phy_quirk(&hieth_mdio_local_device, CONFIG_HIETH_PHYID_D); if (hieth_devs_save[UP_PORT]) ndev = hieth_devs_save[UP_PORT]; else if (hieth_devs_save[DOWN_PORT]) ndev = hieth_devs_save[DOWN_PORT]; if (!ndev) { hieth_error("no dev probed!\n"); ret = -ENODEV; goto _error_nodev_exit; } if (!is_valid_ether_addr(macaddr.sa_data)) { print_mac_address(KERN_WARNING "Invalid HW-MAC Address: ", \ macaddr.sa_data, "\n"); random_ether_addr(macaddr.sa_data); print_mac_address(KERN_WARNING "Set Random MAC address: ", \ macaddr.sa_data, "\n"); } hieth_net_set_mac_address(ndev, (void *)&macaddr); ret = request_irq(CONFIG_HIETH_IRQNUM, hieth_net_isr, IRQF_SHARED, \ "hieth", hieth_devs_save); if (ret) { hieth_error("request_irq %d failed!", CONFIG_HIETH_IRQNUM); goto _error_request_irq; } return ret; _error_request_irq: hieth_platdev_remove_port(pdev, UP_PORT); hieth_platdev_remove_port(pdev, DOWN_PORT); _error_nodev_exit: hieth_mdiobus_driver_exit(); _error_mdiobus_driver_init: hieth_sys_exit(); return ret; }
static int hieth_platdev_probe_port(struct platform_device *pdev, int port) { int ret = -1; struct net_device *netdev = NULL; struct hieth_netdev_local *ld; if ((UP_PORT != port) && (DOWN_PORT != port)) { hieth_error("port error!"); ret = -ENODEV; goto _error_exit; } netdev = alloc_etherdev(sizeof(*ld)); if (netdev == NULL) { hieth_error("alloc_etherdev fail!"); ret = -ENOMEM; goto _error_alloc_etherdev; } SET_NETDEV_DEV(netdev, &pdev->dev); netdev->irq = CONFIG_HIETH_IRQNUM; netdev->watchdog_timeo = 3*HZ; netdev->netdev_ops = &hieth_netdev_ops; netdev->ethtool_ops = &hieth_ethtools_ops; /* init hieth_global somethings... */ hieth_devs_save[port] = netdev; /* init hieth_local_driver */ ld = netdev_priv(netdev); memset(ld, 0, sizeof(*ld)); local_lock_init(ld); ld->iobase = (unsigned long)ioremap_nocache(CONFIG_HIETH_IOBASE, \ CONFIG_HIETH_IOSIZE); if (!ld->iobase) { hieth_error("ioremap_nocache err, base=0x%.8x, size=0x%.8x\n", CONFIG_HIETH_IOBASE, CONFIG_HIETH_IOSIZE); ret = -EFAULT; goto _error_ioremap_nocache; } ld->iobase_phys = CONFIG_HIETH_IOBASE; ld->port = port; ld->dev = &(pdev->dev); /* reset and init port */ hieth_port_reset(ld, ld->port); hieth_port_init(ld, ld->port); ld->depth.hw_xmitq = CONFIG_HIETH_HWQ_XMIT_DEPTH; memset(ld->phy_name, 0, sizeof(ld->phy_name)); snprintf(ld->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, \ HIETH_MIIBUS_NAME, UD_PHY_NAME(CONFIG_HIETH_PHYID)); ld->phy = phy_connect(netdev, ld->phy_name, hieth_adjust_link, 0, \ UD_BIT_NAME(CONFIG_HIETH_MII_RMII_MODE) ? \ PHY_INTERFACE_MODE_MII : PHY_INTERFACE_MODE_MII); if (IS_ERR(ld->phy)) { hieth_error("connect to phy_device %s failed!", ld->phy_name); ld->phy = NULL; goto _error_phy_connect; } skb_queue_head_init(&ld->rx_head); skb_queue_head_init(&ld->rx_hw); skb_queue_head_init(&ld->tx_hw); ld->tx_hw_cnt = 0; ret = hieth_init_skb_buffers(ld); if (ret) { hieth_error("hieth_init_skb_buffers failed!"); goto _error_init_skb_buffers; } ret = register_netdev(netdev); if (ret) { hieth_error("register_netdev %s failed!", netdev->name); goto _error_register_netdev; } return ret; _error_register_netdev: hieth_destroy_skb_buffers(ld); _error_init_skb_buffers: phy_disconnect(ld->phy); ld->phy = NULL; _error_phy_connect: iounmap((void *)ld->iobase); _error_ioremap_nocache: local_lock_exit(); hieth_devs_save[port] = NULL; free_netdev(netdev); _error_alloc_etherdev: _error_exit: return ret; }
static void hieth_net_timeout(struct net_device *dev) { hieth_error("tx timeout"); }
static irqreturn_t hieth_net_isr(int irq, void *dev_id) { int ints; struct hieth_netdev_local *ld; if (hieth_devs_save[UP_PORT]) ld = netdev_priv(hieth_devs_save[UP_PORT]); else if (hieth_devs_save[DOWN_PORT]) ld = netdev_priv(hieth_devs_save[DOWN_PORT]); else { BUG(); return IRQ_NONE; } /*mask the all interrupt*/ hieth_writel_bits(ld, 0, GLB_RW_IRQ_ENA, BITS_IRQS_ENA_ALLPORT); #ifdef CONFIG_EEE_SUPPORT if (eee_available == MAC_EEE) { /* what eee intr we get? */ eee_ints = readl(ld->iobase + 0x480); /* get ready for LPI */ if (eee_ints & TX_LPI_COND) { /* clear eee_intr status */ writel(0x10, ld->iobase + 0x480); data = readl(ld->iobase + 0x488); /* tx_lpi_assert enable */ data |= 0x2; writel(data, ld->iobase + 0x488); /*LPI entry*/ } if (eee_ints & TX_ENTRY_LPI) { /* clear eee_intr status */ writel(0x1, ld->iobase + 0x480); } if (eee_ints & TX_LEAVE_LPI) { /* clear eee_intr status */ writel(0x2, ld->iobase + 0x480); } } #endif ints = hieth_read_irqstatus(ld); if (likely(ints & BITS_IRQS_MASK_U) && hieth_devs_save[UP_PORT]) { hieth_net_isr_proc(netdev_priv(hieth_devs_save[UP_PORT]), (ints & BITS_IRQS_MASK_U)); hieth_clear_irqstatus(ld, (ints & BITS_IRQS_MASK_U)); ints &= ~BITS_IRQS_MASK_U; } if (likely(ints & BITS_IRQS_MASK_D) && hieth_devs_save[DOWN_PORT]) { hieth_net_isr_proc( netdev_priv(hieth_devs_save[DOWN_PORT]), (ints & BITS_IRQS_MASK_D)); hieth_clear_irqstatus(ld, (ints & BITS_IRQS_MASK_D)); ints &= ~BITS_IRQS_MASK_D; } if (unlikely(ints)) { hieth_error("unknown ints=0x%.8x\n", ints); hieth_clear_irqstatus(ld, ints); } /*unmask the all interrupt*/ hieth_writel_bits(ld, 1, GLB_RW_IRQ_ENA, BITS_IRQS_ENA_ALLPORT); return IRQ_HANDLED; }