[RFC v4 4/6] net: add RealTek RTL-8139 PCI Ethernet driver

Sascha Hauer s.hauer at pengutronix.de
Tue Jul 1 23:18:30 PDT 2014


On Mon, Jun 30, 2014 at 11:59:47PM +0400, Antony Pavlov wrote:
> This driver is based on Linux 2.6.39 8139too driver.
> 
> Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
> ---
>  drivers/net/Kconfig     |   8 +
>  drivers/net/Makefile    |   1 +
>  drivers/net/rtl8139.c   | 616 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci_ids.h |   5 +
>  4 files changed, 630 insertions(+)
> 
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 7a0d5e1..975c927 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -130,6 +130,14 @@ config DRIVER_NET_ORION
>  	select PHYLIB
>  	select MDIO_MVEBU
>  
> +config DRIVER_NET_RTL8139
> +	bool "RealTek RTL-8139 PCI Ethernet driver"
> +	depends on PCI
> +	select PHYLIB
> +	help
> +	  This is a driver for the Fast Ethernet PCI network cards based on
> +	  the RTL 8139 chips.
> +
>  config DRIVER_NET_SMC911X
>  	bool "smc911x ethernet driver"
>  	select PHYLIB
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 65f0d8b..d907061 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_NET_MICREL)		+= ksz8864rmn.o
>  obj-$(CONFIG_DRIVER_NET_MPC5200)	+= fec_mpc5200.o
>  obj-$(CONFIG_DRIVER_NET_NETX)		+= netx_eth.o
>  obj-$(CONFIG_DRIVER_NET_ORION)		+= orion-gbe.o
> +obj-$(CONFIG_DRIVER_NET_RTL8139)	+= rtl8139.o
>  obj-$(CONFIG_DRIVER_NET_SMC911X)	+= smc911x.o
>  obj-$(CONFIG_DRIVER_NET_SMC91111)	+= smc91111.o
>  obj-$(CONFIG_DRIVER_NET_TAP)		+= tap.o
> diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
> new file mode 100644
> index 0000000..82c3585
> --- /dev/null
> +++ b/drivers/net/rtl8139.c
> @@ -0,0 +1,616 @@
> +#include <common.h>
> +#include <net.h>
> +#include <malloc.h>
> +#include <init.h>
> +#include <xfuncs.h>
> +#include <errno.h>
> +#include <io.h>
> +#include <linux/phy.h>
> +#include <linux/pci.h>
> +
> +#include <asm/dma-mapping.h>
> +
> +#define RTL8139_DEBUG
> +#undef RTL8139_DEBUG
> +
> +/*
> + * Receive ring size
> + * Warning: 64K ring has hardware issues and may lock up.
> + */
> +#define RX_BUF_IDX	0	/* 8K ring */
> +#define RX_BUF_LEN	(8192 << RX_BUF_IDX)
> +#define RX_BUF_PAD	16
> +#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
> +
> +#if RX_BUF_LEN == 65536
> +#define RX_BUF_TOT_LEN	RX_BUF_LEN
> +#else
> +#define RX_BUF_TOT_LEN	(RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
> +#endif
> +
> +/* Number of Tx descriptor registers. */
> +#define NUM_TX_DESC	4
> +
> +/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
> +#define MAX_ETH_FRAME_SIZE	1536
> +
> +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
> +#define TX_BUF_SIZE	MAX_ETH_FRAME_SIZE
> +#define TX_BUF_TOT_LEN	(TX_BUF_SIZE * NUM_TX_DESC)
> +
> +/* PCI Tuning Parameters
> +   Threshold is bytes transferred to chip before transmission starts. */
> +#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
> +
> +/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
> +#define RX_FIFO_THRESH	7	/* Rx buffer level before first PCI xfer.  */
> +#define RX_DMA_BURST	7	/* Maximum PCI burst, '6' is 1024 */
> +#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
> +#define TX_RETRY	8	/* 0-15.  retries = 16 + (TX_RETRY * 16) */
> +
> +struct rtl8139_priv {
> +	struct eth_device	edev;
> +	void __iomem		*base;
> +	struct pci_dev		*pci_dev;
> +	unsigned char		*rx_ring;
> +	unsigned int		cur_rx; /* RX buf index of next pkt */
> +	dma_addr_t		rx_ring_dma;
> +
> +	u32			rx_config;
> +	unsigned int		tx_flag;
> +	unsigned long		cur_tx;
> +	unsigned long		dirty_tx;
> +	unsigned char		*tx_buf[NUM_TX_DESC];   /* Tx bounce buffers */
> +	unsigned char		*tx_bufs;       /* Tx bounce buffer region. */
> +	dma_addr_t		tx_bufs_dma;
> +
> +	struct mii_bus miibus;
> +};
> +
> +#define ETH_ZLEN        60              /* Min. octets in frame sans FCS */
> +
> +/* Registers */
> +#define MAC0		0x00
> +#define MAR0		0x08
> +#define TxStatus0	0x10
> +
> +enum TxStatusBits {
> +	TxHostOwns	= 0x2000,
> +	TxUnderrun	= 0x4000,
> +	TxStatOK	= 0x8000,
> +	TxOutOfWindow	= 0x20000000,
> +	TxAborted	= 0x40000000,
> +	TxCarrierLost	= 0x80000000,
> +};
> +
> +#define TxAddr0		0x20
> +#define RxBuf		0x30
> +#define ChipCmd		0x37
> +#define  CmdReset	0x10
> +#define  CmdRxEnb	0x08
> +#define  CmdTxEnb	0x04
> +#define  RxBufEmpty	0x01
> +#define RxBufPtr	0x38
> +#define RxBufAddr	0x3A
> +#define IntrMask	0x3C
> +#define IntrStatus	0x3E
> +#define  PCIErr		0x8000
> +#define  PCSTimeout	0x4000
> +#define  RxFIFOOver	0x0040
> +#define  RxUnderrun	0x0020
> +#define  RxOverflow	0x0010
> +#define  TxErr		0x0008
> +#define  TxOK		0x0004
> +#define  RxErr		0x0002
> +#define  RxOK		0x0001
> +#define    RxAckBits	(RxFIFOOver | RxOverflow | RxOK)
> +
> +#define TxConfig	0x40
> +/* Bits in TxConfig. */
> +enum tx_config_bits {
> +	/* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
> +	TxIFGShift	= 24,
> +	TxIFG84		= (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
> +	TxIFG88		= (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
> +	TxIFG92		= (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
> +	TxIFG96		= (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
> +
> +	TxLoopBack	= (1 << 18) | (1 << 17), /* enable loopback test mode */
> +	TxCRC		= (1 << 16),	/* DISABLE Tx pkt CRC append */
> +	TxClearAbt	= (1 << 0),	/* Clear abort (WO) */
> +	TxDMAShift	= 8, /* DMA burst value (0-7) is shifted X many bits */
> +	TxRetryShift	= 4, /* TXRR value (0-15) is shifted X many bits */
> +
> +	TxVersionMask	= 0x7C800000, /* mask out version bits 30-26, 23 */
> +};
> +
> +#define RxConfig	0x44
> +	/* rx fifo threshold */
> +#define  RxCfgFIFOShift	13
> +#define	 RxCfgFIFONone	(7 << RxCfgFIFOShift)
> +	/* Max DMA burst */
> +#define	 RxCfgDMAShift	8
> +#define	 RxCfgDMAUnlimited (7 << RxCfgDMAShift)
> +	/* rx ring buffer length */
> +#define	 RxCfgRcv8K	0
> +#define	 RxCfgRcv16K	(1 << 11)
> +#define	 RxCfgRcv32K	(1 << 12)
> +#define	 RxCfgRcv64K	((1 << 11) | (1 << 12))
> +	/* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
> +#define	 RxNoWrap	(1 << 7)
> +#define	 AcceptErr		0x20
> +#define	 AcceptRunt		0x10
> +#define	 AcceptBroadcast	0x08
> +#define	 AcceptMulticast	0x04
> +#define	 AcceptMyPhys		0x02
> +#define	 AcceptAllPhys		0x01
> +
> +#define RxMissed	0x4C
> +#define Cfg9346		0x50
> +#define  Cfg9346_Lock	0x00
> +#define  Cfg9346_Unlock	0xC0
> +#define BasicModeCtrl	0x62
> +#define BasicModeStatus	0x64
> +#define NWayAdvert	0x66
> +#define NWayLPAR	0x68
> +#define NWayExpansion	0x6a
> +
> +static const char mii_2_8139_map[8] = {
> +	BasicModeCtrl,
> +	BasicModeStatus,
> +	0,
> +	0,
> +	NWayAdvert,
> +	NWayLPAR,
> +	NWayExpansion,
> +	0
> +};
> +
> +/* write MMIO register */
> +#define RTL_W8(priv, reg, val)	writeb(val, ((char *)(priv->base) + reg))
> +#define RTL_W16(priv, reg, val)	writew(val, ((char *)(priv->base) + reg))
> +#define RTL_W32(priv, reg, val)	writel(val, ((char *)(priv->base) + reg))
> +
> +/* read MMIO register */
> +#define RTL_R8(priv, reg)	readb(((char *)(priv->base) + reg))
> +#define RTL_R16(priv, reg)	readw(((char *)(priv->base) + reg))
> +#define RTL_R32(priv, reg)	readl(((char *)(priv->base) + reg))
> +
> +/* write MMIO register, with flush */
> +/* Flush avoids rtl8139 bug w/ posted MMIO writes */
> +static inline void RTL_W8_F(struct rtl8139_priv *priv, int reg, int val)
> +{
> +	RTL_W8(priv, reg, val);
> +	RTL_R8(priv, reg);
> +}
> +
> +static inline void RTL_W16_F(struct rtl8139_priv *priv, int reg, int val)
> +{
> +	RTL_W16(priv, reg, val);
> +	RTL_R16(priv, reg);
> +}
> +
> +static inline void RTL_W32_F(struct rtl8139_priv *priv, int reg, int val)
> +{
> +	RTL_W32(priv, reg, val);
> +	RTL_R32(priv, reg);
> +}
> +
> +static const unsigned int rtl8139_rx_config =
> +	RxCfgRcv8K | RxNoWrap |
> +	(RX_FIFO_THRESH << RxCfgFIFOShift) |
> +	(RX_DMA_BURST << RxCfgDMAShift);
> +
> +static const unsigned int rtl8139_tx_config =
> +	TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
> +
> +static void rtl8139_chip_reset(struct rtl8139_priv *priv)
> +{
> +	int i;
> +
> +	/* Soft reset the chip. */
> +	RTL_W8(priv, ChipCmd, CmdReset);
> +
> +	/* Check that the chip has finished the reset. */
> +	for (i = 1000; i > 0; i--) {
> +		if ((RTL_R8(priv, ChipCmd) & CmdReset) == 0)
> +			break;
> +		udelay(10);
> +	}
> +}
> +
> +static void __set_rx_mode(struct rtl8139_priv *priv)
> +{
> +	u32 mc_filter[2];	/* Multicast hash filter */
> +	int rx_mode;
> +	u32 tmp;
> +
> +	rx_mode =
> +	    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
> +	    AcceptAllPhys;
> +	mc_filter[1] = mc_filter[0] = 0xffffffff;
> +
> +	/* We can safely update without stopping the chip. */
> +	tmp = rtl8139_rx_config | rx_mode;
> +	if (priv->rx_config != tmp) {
> +		RTL_W32_F(priv, RxConfig, tmp);
> +		priv->rx_config = tmp;
> +	}
> +
> +	RTL_W32_F(priv, MAR0 + 0, mc_filter[0]);
> +	RTL_W32_F(priv, MAR0 + 4, mc_filter[1]);
> +}
> +
> +/* Start the hardware at open or resume. */
> +static void rtl8139_hw_start(struct rtl8139_priv *priv)
> +{
> +	u32 i;
> +	u8 tmp;
> +
> +	rtl8139_chip_reset(priv);
> +
> +	/* unlock Config[01234] and BMCR register writes */
> +	RTL_W8_F(priv, Cfg9346, Cfg9346_Unlock);
> +
> +	/* FIXME */
> +#if 0
> +	/* Restore our idea of the MAC address. */
> +	RTL_W32_F(priv, MAC0 + 0, *(__le32 *) (dev->dev_addr + 0));
> +	RTL_W32_F(priv, MAC0 + 4, *(__le16 *) (dev->dev_addr + 4));
> +#endif

Is this something that needs fixing? The MAC Address should be
configured correctly without this code, right?

> +	priv->miibus.read = rtl8139_phy_read;
> +	priv->miibus.write = rtl8139_phy_write;
> +	priv->miibus.priv = priv;
> +	priv->miibus.parent = &edev->dev;
> +
> +	/* FIXME: pci_resource_start() */
> +	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &bar);
> +
> +	/* FIXME: use pci_iomap() */
> +	priv->base = (void *)bus->ops->res_start(bus, bar);

barebox has resources. Can't we use them here? What's missing?

> +
> +	printk("found rtl8139 (rev %02x) at %02x: %04x (base=%p)\n",
> +			pdev->revision,
> +			pdev->devfn,
> +			(pdev->class >> 8) & 0xffff,
> +			priv->base);

dev_info

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the barebox mailing list