Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
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;
}
Beispiel #6
0
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;
}
Beispiel #7
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
static void hieth_net_timeout(struct net_device *dev)
{
	hieth_error("tx timeout");
}
Beispiel #11
0
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;
}