18d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/*
28d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * Faraday FTMAC100 10/100 Ethernet
38d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *
48d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * (C) Copyright 2009-2011 Faraday Technology
58d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * Po-Yu Chuang <ratbert@faraday-tech.com>
68d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *
78d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * This program is free software; you can redistribute it and/or modify
88d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * it under the terms of the GNU General Public License as published by
98d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * the Free Software Foundation; either version 2 of the License, or
108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * (at your option) any later version.
118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *
128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * This program is distributed in the hope that it will be useful,
138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * but WITHOUT ANY WARRANTY; without even the implied warranty of
148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * GNU General Public License for more details.
168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *
178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * You should have received a copy of the GNU General Public License
188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * along with this program; if not, write to the Free Software
198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang */
218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/dma-mapping.h>
258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/etherdevice.h>
268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/ethtool.h>
278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/init.h>
2817f1bbca1baf2f652fa9c102ec239d6abded94c1Thomas Faber#include <linux/interrupt.h>
298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/io.h>
308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/mii.h>
318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/module.h>
328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/netdevice.h>
338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include <linux/platform_device.h>
348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#include "ftmac100.h"
368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define DRV_NAME	"ftmac100"
388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define DRV_VERSION	"0.2"
398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define RX_QUEUE_ENTRIES	128	/* must be power of 2 */
418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define TX_QUEUE_ENTRIES	16	/* must be power of 2 */
428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define MAX_PKT_SIZE		1518
448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define RX_BUF_SIZE		2044	/* must be smaller than 0x7ff */
458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#if MAX_PKT_SIZE > 0x7ff
478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#error invalid MAX_PKT_SIZE
488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#endif
498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#if RX_BUF_SIZE > 0x7ff || RX_BUF_SIZE > PAGE_SIZE
518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#error invalid RX_BUF_SIZE
528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#endif
538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * private data
568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstruct ftmac100_descs {
588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_txdes txdes[TX_QUEUE_ENTRIES];
608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang};
618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstruct ftmac100 {
638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct resource *res;
648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	void __iomem *base;
658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int irq;
668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_descs *descs;
688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_addr_t descs_dma_addr;
698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int rx_pointer;
718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int tx_clean_pointer;
728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int tx_pointer;
738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int tx_pending;
748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	spinlock_t tx_lock;
768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev;
788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct device *dev;
798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct napi_struct napi;
808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct mii_if_info mii;
828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang};
838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
84c05e7ac99c32d4e5d8be272c0ba95b0fdcab431bEric Dumazetstatic int ftmac100_alloc_rx_page(struct ftmac100 *priv,
85c05e7ac99c32d4e5d8be272c0ba95b0fdcab431bEric Dumazet				  struct ftmac100_rxdes *rxdes, gfp_t gfp);
868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * internal functions (hardware register access)
898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define INT_MASK_ALL_ENABLED	(FTMAC100_INT_RPKT_FINISH	| \
918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_INT_NORXBUF		| \
928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_INT_XPKT_OK		| \
938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_INT_XPKT_LOST		| \
948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_INT_RPKT_LOST		| \
958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_INT_AHB_ERR		| \
968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_INT_PHYSTS_CHG)
978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define INT_MASK_ALL_DISABLED	0
998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_enable_all_int(struct ftmac100 *priv)
1018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTMAC100_OFFSET_IMR);
1038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_disable_all_int(struct ftmac100 *priv)
1068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(INT_MASK_ALL_DISABLED, priv->base + FTMAC100_OFFSET_IMR);
1088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_set_rx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
1118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(addr, priv->base + FTMAC100_OFFSET_RXR_BADR);
1138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_set_tx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
1168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(addr, priv->base + FTMAC100_OFFSET_TXR_BADR);
1188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdma_start_polling(struct ftmac100 *priv)
1218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(1, priv->base + FTMAC100_OFFSET_TXPD);
1238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_reset(struct ftmac100 *priv)
1268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
1288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int i;
1298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* NOTE: reset clears all registers */
1318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(FTMAC100_MACCR_SW_RST, priv->base + FTMAC100_OFFSET_MACCR);
1328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	for (i = 0; i < 5; i++) {
1348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		unsigned int maccr;
1358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
1378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (!(maccr & FTMAC100_MACCR_SW_RST)) {
1388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			/*
1398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			 * FTMAC100_MACCR_SW_RST cleared does not indicate
1408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			 * that hardware reset completed (what the f*ck).
1418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			 * We still need to wait for a while.
1428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			 */
143eee9700c5dd8fbac517c8c1e85c60b688bc311a9Adam Jaremko			udelay(500);
1448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			return 0;
1458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		}
1468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
147eee9700c5dd8fbac517c8c1e85c60b688bc311a9Adam Jaremko		udelay(1000);
1488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
1498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev_err(netdev, "software reset failed\n");
1518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return -EIO;
1528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac)
1558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int maddr = mac[0] << 8 | mac[1];
1578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
1588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(maddr, priv->base + FTMAC100_OFFSET_MAC_MADR);
1608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR);
1618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang#define MACCR_ENABLE_ALL	(FTMAC100_MACCR_XMT_EN	| \
1648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_MACCR_RCV_EN	| \
1658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_MACCR_XDMA_EN	| \
1668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_MACCR_RDMA_EN	| \
1678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_MACCR_CRC_APD	| \
1688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_MACCR_FULLDUP	| \
1698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_MACCR_RX_RUNT	| \
1708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 FTMAC100_MACCR_RX_BROADPKT)
1718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_start_hw(struct ftmac100 *priv)
1738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
1758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (ftmac100_reset(priv))
1778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return -EIO;
1788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* setup ring buffer base registers */
1808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_set_rx_ring_base(priv,
1818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				  priv->descs_dma_addr +
1828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				  offsetof(struct ftmac100_descs, rxdes));
1838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_set_tx_ring_base(priv,
1848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				  priv->descs_dma_addr +
1858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				  offsetof(struct ftmac100_descs, txdes));
1868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(FTMAC100_APTC_RXPOLL_CNT(1), priv->base + FTMAC100_OFFSET_APTC);
1888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_set_mac(priv, netdev->dev_addr);
1908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(MACCR_ENABLE_ALL, priv->base + FTMAC100_OFFSET_MACCR);
1928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
1938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
1958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_stop_hw(struct ftmac100 *priv)
1968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
1978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(0, priv->base + FTMAC100_OFFSET_MACCR);
1988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
1998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
2018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * internal functions (receive descriptor)
2028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
2038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_first_segment(struct ftmac100_rxdes *rxdes)
2048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FRS);
2068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_last_segment(struct ftmac100_rxdes *rxdes)
2098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_LRS);
2118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes *rxdes)
2148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
2168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes *rxdes)
2198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* clear status bits */
2218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	rxdes->rxdes0 = cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
2228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_rx_error(struct ftmac100_rxdes *rxdes)
2258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ERR);
2278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes)
2308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR);
2328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_frame_too_long(struct ftmac100_rxdes *rxdes)
2358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FTL);
2378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes)
2408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT);
2428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes *rxdes)
2458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ODD_NB);
2478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic unsigned int ftmac100_rxdes_frame_length(struct ftmac100_rxdes *rxdes)
2508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return le32_to_cpu(rxdes->rxdes0) & FTMAC100_RXDES0_RFL;
2528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rxdes_multicast(struct ftmac100_rxdes *rxdes)
2558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_MULTICAST);
2578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes *rxdes,
2608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang					   unsigned int size)
2618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	rxdes->rxdes1 &= cpu_to_le32(FTMAC100_RXDES1_EDORR);
2638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_RXBUF_SIZE(size));
2648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes *rxdes)
2678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_EDORR);
2698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes *rxdes,
2728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang					dma_addr_t addr)
2738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	rxdes->rxdes2 = cpu_to_le32(addr);
2758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic dma_addr_t ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes *rxdes)
2788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return le32_to_cpu(rxdes->rxdes2);
2808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/*
2838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * rxdes3 is not used by hardware. We use it to keep track of page.
2848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
2858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang */
2868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_rxdes_set_page(struct ftmac100_rxdes *rxdes, struct page *page)
2878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	rxdes->rxdes3 = (unsigned int)page;
2898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic struct page *ftmac100_rxdes_get_page(struct ftmac100_rxdes *rxdes)
2928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
2938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return (struct page *)rxdes->rxdes3;
2948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
2958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
2968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
2978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * internal functions (receive)
2988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
2998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_next_rx_pointer(int pointer)
3008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
3018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
3028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
3038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_rx_pointer_advance(struct ftmac100 *priv)
3058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
3068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->rx_pointer = ftmac100_next_rx_pointer(priv->rx_pointer);
3078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
3088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic struct ftmac100_rxdes *ftmac100_current_rxdes(struct ftmac100 *priv)
3108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
3118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return &priv->descs->rxdes[priv->rx_pointer];
3128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
3138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic struct ftmac100_rxdes *
3158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangftmac100_rx_locate_first_segment(struct ftmac100 *priv)
3168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
3178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
3188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	while (!ftmac100_rxdes_owned_by_dma(rxdes)) {
3208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (ftmac100_rxdes_first_segment(rxdes))
3218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			return rxdes;
3228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_rxdes_set_dma_own(rxdes);
3248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_rx_pointer_advance(priv);
3258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		rxdes = ftmac100_current_rxdes(priv);
3268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
3278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return NULL;
3298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
3308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rx_packet_error(struct ftmac100 *priv,
3328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				     struct ftmac100_rxdes *rxdes)
3338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
3348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
3358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	bool error = false;
3368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(ftmac100_rxdes_rx_error(rxdes))) {
3388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
3398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_info(netdev, "rx err\n");
3408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.rx_errors++;
3428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		error = true;
3438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
3448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(ftmac100_rxdes_crc_error(rxdes))) {
3468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
3478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_info(netdev, "rx crc err\n");
3488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.rx_crc_errors++;
3508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		error = true;
3518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
3528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(ftmac100_rxdes_frame_too_long(rxdes))) {
3548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
3558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_info(netdev, "rx frame too long\n");
3568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.rx_length_errors++;
3588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		error = true;
3598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	} else if (unlikely(ftmac100_rxdes_runt(rxdes))) {
3608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
3618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_info(netdev, "rx runt\n");
3628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.rx_length_errors++;
3648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		error = true;
3658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	} else if (unlikely(ftmac100_rxdes_odd_nibble(rxdes))) {
3668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
3678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_info(netdev, "rx odd nibble\n");
3688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.rx_length_errors++;
3708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		error = true;
3718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
3728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return error;
3748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
3758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_rx_drop_packet(struct ftmac100 *priv)
3778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
3788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
3798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
3808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	bool done = false;
3818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (net_ratelimit())
3838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev_dbg(netdev, "drop packet %p\n", rxdes);
3848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	do {
3868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (ftmac100_rxdes_last_segment(rxdes))
3878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			done = true;
3888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_rxdes_set_dma_own(rxdes);
3908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_rx_pointer_advance(priv);
3918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		rxdes = ftmac100_current_rxdes(priv);
3928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	} while (!done && !ftmac100_rxdes_owned_by_dma(rxdes));
3938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev->stats.rx_dropped++;
3958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
3968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
3978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed)
3988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
3998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
4008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_rxdes *rxdes;
4018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct sk_buff *skb;
4028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct page *page;
4038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_addr_t map;
4048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int length;
4058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	rxdes = ftmac100_rx_locate_first_segment(priv);
4078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!rxdes)
4088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return false;
4098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(ftmac100_rx_packet_error(priv, rxdes))) {
4118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_rx_drop_packet(priv);
4128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return true;
4138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
4148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/*
4168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	 * It is impossible to get multi-segment packets
4178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	 * because we always provide big enough receive buffers.
4188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	 */
4198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(!ftmac100_rxdes_last_segment(rxdes)))
4208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		BUG();
4218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* start processing */
4238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	skb = netdev_alloc_skb_ip_align(netdev, 128);
4248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(!skb)) {
4258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
4268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_err(netdev, "rx skb alloc failed\n");
4278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_rx_drop_packet(priv);
4298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return true;
4308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
4318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(ftmac100_rxdes_multicast(rxdes)))
4338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.multicast++;
4348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	map = ftmac100_rxdes_get_dma_addr(rxdes);
4368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
4378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	length = ftmac100_rxdes_frame_length(rxdes);
4398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	page = ftmac100_rxdes_get_page(rxdes);
4408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	skb_fill_page_desc(skb, 0, page, 0, length);
4418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	skb->len += length;
4428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	skb->data_len += length;
44396cd8951684adaa5fd72952adef532d0b42f70e1Eric Dumazet
44496cd8951684adaa5fd72952adef532d0b42f70e1Eric Dumazet	/* page might be freed in __pskb_pull_tail() */
44596cd8951684adaa5fd72952adef532d0b42f70e1Eric Dumazet	if (length > 64)
44696cd8951684adaa5fd72952adef532d0b42f70e1Eric Dumazet		skb->truesize += PAGE_SIZE;
4478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	__pskb_pull_tail(skb, min(length, 64));
4488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
449c05e7ac99c32d4e5d8be272c0ba95b0fdcab431bEric Dumazet	ftmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
4508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_rx_pointer_advance(priv);
4528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	skb->protocol = eth_type_trans(skb, netdev);
4548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev->stats.rx_packets++;
4568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev->stats.rx_bytes += skb->len;
4578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* push packet to protocol stack */
4598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netif_receive_skb(skb);
4608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	(*processed)++;
4628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return true;
4638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
4648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
4668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * internal functions (transmit descriptor)
4678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
4688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_reset(struct ftmac100_txdes *txdes)
4698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
4708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* clear all except end of ring bit */
4718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes0 = 0;
4728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes1 &= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
4738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes2 = 0;
4748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes3 = 0;
4758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
4768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_txdes_owned_by_dma(struct ftmac100_txdes *txdes)
4788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
4798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
4808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
4818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_dma_own(struct ftmac100_txdes *txdes)
4838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
4848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/*
4858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	 * Make sure dma own bit will not be set before any other
4868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	 * descriptor fields.
4878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	 */
4888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	wmb();
4898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes0 |= cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
4908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
4918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_txdes_excessive_collision(struct ftmac100_txdes *txdes)
4938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
4948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_EXSCOL);
4958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
4968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
4978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_txdes_late_collision(struct ftmac100_txdes *txdes)
4988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
4998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_LATECOL);
5008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes *txdes)
5038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
5058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_first_segment(struct ftmac100_txdes *txdes)
5088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_FTS);
5108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_last_segment(struct ftmac100_txdes *txdes)
5138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_LTS);
5158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_txint(struct ftmac100_txdes *txdes)
5188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXIC);
5208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_buffer_size(struct ftmac100_txdes *txdes,
5238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang					   unsigned int len)
5248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXBUF_SIZE(len));
5268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_dma_addr(struct ftmac100_txdes *txdes,
5298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang					dma_addr_t addr)
5308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes2 = cpu_to_le32(addr);
5328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic dma_addr_t ftmac100_txdes_get_dma_addr(struct ftmac100_txdes *txdes)
5358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return le32_to_cpu(txdes->txdes2);
5378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/*
5408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * txdes3 is not used by hardware. We use it to keep track of socket buffer.
5418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
5428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang */
5438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_txdes_set_skb(struct ftmac100_txdes *txdes, struct sk_buff *skb)
5448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes->txdes3 = (unsigned int)skb;
5468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic struct sk_buff *ftmac100_txdes_get_skb(struct ftmac100_txdes *txdes)
5498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return (struct sk_buff *)txdes->txdes3;
5518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
5548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * internal functions (transmit)
5558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
5568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_next_tx_pointer(int pointer)
5578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
5598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_tx_pointer_advance(struct ftmac100 *priv)
5628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->tx_pointer = ftmac100_next_tx_pointer(priv->tx_pointer);
5648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_tx_clean_pointer_advance(struct ftmac100 *priv)
5678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->tx_clean_pointer = ftmac100_next_tx_pointer(priv->tx_clean_pointer);
5698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic struct ftmac100_txdes *ftmac100_current_txdes(struct ftmac100 *priv)
5728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return &priv->descs->txdes[priv->tx_pointer];
5748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic struct ftmac100_txdes *ftmac100_current_clean_txdes(struct ftmac100 *priv)
5778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return &priv->descs->txdes[priv->tx_clean_pointer];
5798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
5808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic bool ftmac100_tx_complete_packet(struct ftmac100 *priv)
5828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
5838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
5848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_txdes *txdes;
5858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct sk_buff *skb;
5868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_addr_t map;
5878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (priv->tx_pending == 0)
5898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return false;
5908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes = ftmac100_current_clean_txdes(priv);
5928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (ftmac100_txdes_owned_by_dma(txdes))
5948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return false;
5958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	skb = ftmac100_txdes_get_skb(txdes);
5978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	map = ftmac100_txdes_get_dma_addr(txdes);
5988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
5998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(ftmac100_txdes_excessive_collision(txdes) ||
6008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		     ftmac100_txdes_late_collision(txdes))) {
6018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		/*
6028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 * packet transmitted to ethernet lost due to late collision
6038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 * or excessive collision
6048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 */
6058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.tx_aborted_errors++;
6068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	} else {
6078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.tx_packets++;
6088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.tx_bytes += skb->len;
6098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
6108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
6128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dev_kfree_skb(skb);
6138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_reset(txdes);
6158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_tx_clean_pointer_advance(priv);
6178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	spin_lock(&priv->tx_lock);
6198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->tx_pending--;
6208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	spin_unlock(&priv->tx_lock);
6218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netif_wake_queue(netdev);
6228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return true;
6248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
6258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_tx_complete(struct ftmac100 *priv)
6278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
6288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	while (ftmac100_tx_complete_packet(priv))
6298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		;
6308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
6318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb,
6338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			 dma_addr_t map)
6348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
6358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
6368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100_txdes *txdes;
6378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
6388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	txdes = ftmac100_current_txdes(priv);
6408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_tx_pointer_advance(priv);
6418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* setup TX descriptor */
6438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_skb(txdes, skb);
6448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_dma_addr(txdes, map);
6458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_first_segment(txdes);
6478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_last_segment(txdes);
6488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_txint(txdes);
6498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_buffer_size(txdes, len);
6508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	spin_lock(&priv->tx_lock);
6528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->tx_pending++;
6538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (priv->tx_pending == TX_QUEUE_ENTRIES)
6548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netif_stop_queue(netdev);
6558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* start transmit */
6578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_dma_own(txdes);
6588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	spin_unlock(&priv->tx_lock);
6598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdma_start_polling(priv);
6618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return NETDEV_TX_OK;
6628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
6638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
6658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * internal functions (buffer)
6668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
667c05e7ac99c32d4e5d8be272c0ba95b0fdcab431bEric Dumazetstatic int ftmac100_alloc_rx_page(struct ftmac100 *priv,
668c05e7ac99c32d4e5d8be272c0ba95b0fdcab431bEric Dumazet				  struct ftmac100_rxdes *rxdes, gfp_t gfp)
6698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
6708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
6718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct page *page;
6728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_addr_t map;
6738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
674c05e7ac99c32d4e5d8be272c0ba95b0fdcab431bEric Dumazet	page = alloc_page(gfp);
6758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!page) {
6768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
6778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_err(netdev, "failed to allocate rx page\n");
6788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return -ENOMEM;
6798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
6808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
6828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(dma_mapping_error(priv->dev, map))) {
6838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
6848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_err(netdev, "failed to map rx page\n");
6858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		__free_page(page);
6868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return -ENOMEM;
6878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
6888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_rxdes_set_page(rxdes, page);
6908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_rxdes_set_dma_addr(rxdes, map);
6918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE);
6928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_rxdes_set_dma_own(rxdes);
6938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
6948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
6958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
6968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_free_buffers(struct ftmac100 *priv)
6978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
6988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int i;
6998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
7018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
7028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		struct page *page = ftmac100_rxdes_get_page(rxdes);
7038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dma_addr_t map = ftmac100_rxdes_get_dma_addr(rxdes);
7048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (!page)
7068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			continue;
7078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
7098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		__free_page(page);
7108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
7118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
7138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		struct ftmac100_txdes *txdes = &priv->descs->txdes[i];
7148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		struct sk_buff *skb = ftmac100_txdes_get_skb(txdes);
7158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dma_addr_t map = ftmac100_txdes_get_dma_addr(txdes);
7168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (!skb)
7188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			continue;
7198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
7218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dev_kfree_skb(skb);
7228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
7238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_free_coherent(priv->dev, sizeof(struct ftmac100_descs),
7258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			  priv->descs, priv->descs_dma_addr);
7268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
7278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_alloc_buffers(struct ftmac100 *priv)
7298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
7308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int i;
7318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->descs = dma_alloc_coherent(priv->dev, sizeof(struct ftmac100_descs),
7338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang					 &priv->descs_dma_addr, GFP_KERNEL);
7348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!priv->descs)
7358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return -ENOMEM;
7368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	memset(priv->descs, 0, sizeof(struct ftmac100_descs));
7388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* initialize RX ring */
7408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
7418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
7438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
7448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
745c05e7ac99c32d4e5d8be272c0ba95b0fdcab431bEric Dumazet		if (ftmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL))
7468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			goto err;
7478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
7488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* initialize TX ring */
7508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
7518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
7528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr:
7548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_free_buffers(priv);
7558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return -ENOMEM;
7568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
7578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
7598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * struct mii_if_info functions
7608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
7618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg)
7628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
7638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
7648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int phycr;
7658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int i;
7668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
7688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		FTMAC100_PHYCR_REGAD(reg) |
7698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		FTMAC100_PHYCR_MIIRD;
7708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
7728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	for (i = 0; i < 10; i++) {
7748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
7758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if ((phycr & FTMAC100_PHYCR_MIIRD) == 0)
7778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			return phycr & FTMAC100_PHYCR_MIIRDATA;
7788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
779eee9700c5dd8fbac517c8c1e85c60b688bc311a9Adam Jaremko		udelay(100);
7808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
7818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev_err(netdev, "mdio read timed out\n");
7838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
7848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
7858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
7878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				int data)
7888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
7898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
7908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int phycr;
7918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int i;
7928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
7948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		FTMAC100_PHYCR_REGAD(reg) |
7958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		FTMAC100_PHYCR_MIIWR;
7968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	data = FTMAC100_PHYWDATA_MIIWDATA(data);
7988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
7998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(data, priv->base + FTMAC100_OFFSET_PHYWDATA);
8008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
8018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	for (i = 0; i < 10; i++) {
8038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
8048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if ((phycr & FTMAC100_PHYCR_MIIWR) == 0)
8068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			return;
8078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
808eee9700c5dd8fbac517c8c1e85c60b688bc311a9Adam Jaremko		udelay(100);
8098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
8108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev_err(netdev, "mdio write timed out\n");
8128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
8138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
8158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * struct ethtool_ops functions
8168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
8178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void ftmac100_get_drvinfo(struct net_device *netdev,
8188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				 struct ethtool_drvinfo *info)
8198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
8208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	strcpy(info->driver, DRV_NAME);
8218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	strcpy(info->version, DRV_VERSION);
8228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	strcpy(info->bus_info, dev_name(&netdev->dev));
8238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
8248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
8268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
8278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
8288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return mii_ethtool_gset(&priv->mii, cmd);
8298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
8308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
8328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
8338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
8348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return mii_ethtool_sset(&priv->mii, cmd);
8358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
8368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_nway_reset(struct net_device *netdev)
8388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
8398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
8408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return mii_nway_restart(&priv->mii);
8418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
8428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic u32 ftmac100_get_link(struct net_device *netdev)
8448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
8458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
8468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return mii_link_ok(&priv->mii);
8478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
8488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic const struct ethtool_ops ftmac100_ethtool_ops = {
8508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.set_settings		= ftmac100_set_settings,
8518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.get_settings		= ftmac100_get_settings,
8528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.get_drvinfo		= ftmac100_get_drvinfo,
8538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.nway_reset		= ftmac100_nway_reset,
8548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.get_link		= ftmac100_get_link,
8558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang};
8568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
8588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * interrupt handler
8598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
8608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic irqreturn_t ftmac100_interrupt(int irq, void *dev_id)
8618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
8628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = dev_id;
8638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
8648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (likely(netif_running(netdev))) {
8668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		/* Disable interrupts for polling */
8678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_disable_all_int(priv);
8688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		napi_schedule(&priv->napi);
8698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
8708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return IRQ_HANDLED;
8728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
8738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
8758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * struct napi_struct functions
8768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
8778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_poll(struct napi_struct *napi, int budget)
8788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
8798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = container_of(napi, struct ftmac100, napi);
8808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev = priv->netdev;
8818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unsigned int status;
8828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	bool completed = true;
8838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int rx = 0;
8848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	status = ioread32(priv->base + FTMAC100_OFFSET_ISR);
8868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF)) {
8888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		/*
8898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 * FTMAC100_INT_RPKT_FINISH:
8908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 *	RX DMA has received packets into RX buffer successfully
8918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 *
8928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 * FTMAC100_INT_NORXBUF:
8938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 *	RX buffer unavailable
8948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 */
8958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		bool retry;
8968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
8978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		do {
8988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			retry = ftmac100_rx_packet(priv, &rx);
8998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		} while (retry && rx < budget);
9008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (retry && rx == budget)
9028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			completed = false;
9038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
9048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (status & (FTMAC100_INT_XPKT_OK | FTMAC100_INT_XPKT_LOST)) {
9068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		/*
9078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 * FTMAC100_INT_XPKT_OK:
9088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 *	packet transmitted to ethernet successfully
9098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 *
9108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 * FTMAC100_INT_XPKT_LOST:
9118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 *	packet transmitted to ethernet lost due to late
9128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 *	collision or excessive collision
9138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		 */
9148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_tx_complete(priv);
9158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
9168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (status & (FTMAC100_INT_NORXBUF | FTMAC100_INT_RPKT_LOST |
9188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		      FTMAC100_INT_AHB_ERR | FTMAC100_INT_PHYSTS_CHG)) {
9198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
9208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
9218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				    status & FTMAC100_INT_NORXBUF ? "NORXBUF " : "",
9228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				    status & FTMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
9238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				    status & FTMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
9248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				    status & FTMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
9258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (status & FTMAC100_INT_NORXBUF) {
9278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			/* RX buffer unavailable */
9288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev->stats.rx_over_errors++;
9298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		}
9308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (status & FTMAC100_INT_RPKT_LOST) {
9328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			/* received packet lost due to RX FIFO full */
9338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev->stats.rx_fifo_errors++;
9348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		}
9358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (status & FTMAC100_INT_PHYSTS_CHG) {
9378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			/* PHY link status change */
9388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			mii_check_link(&priv->mii);
9398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		}
9408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
9418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (completed) {
9438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		/* stop polling */
9448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		napi_complete(napi);
9458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		ftmac100_enable_all_int(priv);
9468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
9478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return rx;
9498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
9508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
9528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * struct net_device_ops functions
9538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
9548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_open(struct net_device *netdev)
9558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
9568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
9578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int err;
9588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	err = ftmac100_alloc_buffers(priv);
9608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (err) {
9618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev_err(netdev, "failed to allocate buffers\n");
9628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		goto err_alloc;
9638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
9648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	err = request_irq(priv->irq, ftmac100_interrupt, 0, netdev->name, netdev);
9668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (err) {
9678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev_err(netdev, "failed to request irq %d\n", priv->irq);
9688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		goto err_irq;
9698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
9708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->rx_pointer = 0;
9728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->tx_clean_pointer = 0;
9738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->tx_pointer = 0;
9748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->tx_pending = 0;
9758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	err = ftmac100_start_hw(priv);
9778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (err)
9788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		goto err_hw;
9798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	napi_enable(&priv->napi);
9818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netif_start_queue(netdev);
9828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_enable_all_int(priv);
9848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
9868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr_hw:
9888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	free_irq(priv->irq, netdev);
9898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr_irq:
9908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_free_buffers(priv);
9918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr_alloc:
9928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return err;
9938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
9948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_stop(struct net_device *netdev)
9968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
9978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
9988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
9998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_disable_all_int(priv);
10008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netif_stop_queue(netdev);
10018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	napi_disable(&priv->napi);
10028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_stop_hw(priv);
10038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	free_irq(priv->irq, netdev);
10048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	ftmac100_free_buffers(priv);
10058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
10078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
10088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10098d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
10108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
10118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
10128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	dma_addr_t map;
10138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(skb->len > MAX_PKT_SIZE)) {
10158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
10168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_dbg(netdev, "tx packet too big\n");
10178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.tx_dropped++;
10198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dev_kfree_skb(skb);
10208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return NETDEV_TX_OK;
10218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
10228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
10248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (unlikely(dma_mapping_error(priv->dev, map))) {
10258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		/* drop packet */
10268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		if (net_ratelimit())
10278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			netdev_err(netdev, "map socket buffer failed\n");
10288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev->stats.tx_dropped++;
10308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dev_kfree_skb(skb);
10318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return NETDEV_TX_OK;
10328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
10338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return ftmac100_xmit(priv, skb, map);
10358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
10368d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/* optional */
10388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
10398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
10408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv = netdev_priv(netdev);
10418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct mii_ioctl_data *data = if_mii(ifr);
10428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return generic_mii_ioctl(&priv->mii, data, cmd, NULL);
10448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
10458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic const struct net_device_ops ftmac100_netdev_ops = {
10478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.ndo_open		= ftmac100_open,
10488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.ndo_stop		= ftmac100_stop,
10498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.ndo_start_xmit		= ftmac100_hard_start_xmit,
10508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.ndo_set_mac_address	= eth_mac_addr,
10518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.ndo_validate_addr	= eth_validate_addr,
10528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.ndo_do_ioctl		= ftmac100_do_ioctl,
10538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang};
10548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
10568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * struct platform_driver functions
10578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
10588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int ftmac100_probe(struct platform_device *pdev)
10598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
10608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct resource *res;
10618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int irq;
10628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev;
10638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv;
10648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	int err;
10658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!pdev)
10678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return -ENODEV;
10688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
10708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!res)
10718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return -ENXIO;
10728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	irq = platform_get_irq(pdev, 0);
10748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (irq < 0)
10758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		return irq;
10768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* setup net_device */
10788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev = alloc_etherdev(sizeof(*priv));
10798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!netdev) {
10808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		err = -ENOMEM;
10818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		goto err_alloc_etherdev;
10828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
10838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	SET_NETDEV_DEV(netdev, &pdev->dev);
10858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	SET_ETHTOOL_OPS(netdev, &ftmac100_ethtool_ops);
10868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev->netdev_ops = &ftmac100_netdev_ops;
10878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	platform_set_drvdata(pdev, netdev);
10898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* setup private data */
10918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv = netdev_priv(netdev);
10928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->netdev = netdev;
10938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->dev = &pdev->dev;
10948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	spin_lock_init(&priv->tx_lock);
10968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
10978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* initialize NAPI */
10988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netif_napi_add(netdev, &priv->napi, ftmac100_poll, 64);
10998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* map io memory */
11018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->res = request_mem_region(res->start, resource_size(res),
11028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang				       dev_name(&pdev->dev));
11038d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!priv->res) {
11048d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dev_err(&pdev->dev, "Could not reserve memory region\n");
11058d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		err = -ENOMEM;
11068d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		goto err_req_mem;
11078d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
11088d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
110993d03203d5a165d7a757546245dd1543dfe0ff80Dan Carpenter	priv->base = ioremap(res->start, resource_size(res));
11108d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!priv->base) {
11118d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
11128d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		err = -EIO;
11138d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		goto err_ioremap;
11148d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
11158d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11168d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->irq = irq;
11178d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11188d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* initialize struct mii_if_info */
11198d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->mii.phy_id	= 0;
11208d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->mii.phy_id_mask	= 0x1f;
11218d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->mii.reg_num_mask	= 0x1f;
11228d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->mii.dev		= netdev;
11238d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->mii.mdio_read	= ftmac100_mdio_read;
11248d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv->mii.mdio_write	= ftmac100_mdio_write;
11258d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11268d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	/* register network device */
11278d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	err = register_netdev(netdev);
11288d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (err) {
11298d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		dev_err(&pdev->dev, "Failed to register netdev\n");
11308d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		goto err_register_netdev;
11318d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
11328d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11338d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
11348d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11358d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	if (!is_valid_ether_addr(netdev->dev_addr)) {
1136f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka		eth_hw_addr_random(netdev);
11378d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		netdev_info(netdev, "generated random MAC address %pM\n",
11388d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang			    netdev->dev_addr);
11398d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	}
11408d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11418d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
11428d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11438d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr_register_netdev:
11448d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iounmap(priv->base);
11458d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr_ioremap:
11468d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	release_resource(priv->res);
11478d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr_req_mem:
11488d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netif_napi_del(&priv->napi);
11498d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	platform_set_drvdata(pdev, NULL);
11508d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	free_netdev(netdev);
11518d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangerr_alloc_etherdev:
11528d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return err;
11538d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
11548d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11558d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int __exit ftmac100_remove(struct platform_device *pdev)
11568d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
11578d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct net_device *netdev;
11588d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	struct ftmac100 *priv;
11598d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11608d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netdev = platform_get_drvdata(pdev);
11618d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	priv = netdev_priv(netdev);
11628d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11638d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	unregister_netdev(netdev);
11648d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11658d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	iounmap(priv->base);
11668d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	release_resource(priv->res);
11678d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11688d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	netif_napi_del(&priv->napi);
11698d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	platform_set_drvdata(pdev, NULL);
11708d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	free_netdev(netdev);
11718d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return 0;
11728d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
11738d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11748d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic struct platform_driver ftmac100_driver = {
11758d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.probe		= ftmac100_probe,
11768d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.remove		= __exit_p(ftmac100_remove),
11778d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	.driver		= {
11788d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		.name	= DRV_NAME,
11798d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang		.owner	= THIS_MODULE,
11808d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	},
11818d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang};
11828d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11838d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang/******************************************************************************
11848d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang * initialization / finalization
11858d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang *****************************************************************************/
11868d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic int __init ftmac100_init(void)
11878d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
11888d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	pr_info("Loading version " DRV_VERSION " ...\n");
11898d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	return platform_driver_register(&ftmac100_driver);
11908d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
11918d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11928d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangstatic void __exit ftmac100_exit(void)
11938d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang{
11948d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang	platform_driver_unregister(&ftmac100_driver);
11958d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang}
11968d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
11978d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangmodule_init(ftmac100_init);
11988d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuangmodule_exit(ftmac100_exit);
11998d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu Chuang
12008d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu ChuangMODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
12018d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu ChuangMODULE_DESCRIPTION("FTMAC100 driver");
12028d77c036b57cf813d838f859e11b6a188acdb1fbPo-Yu ChuangMODULE_LICENSE("GPL");
1203