[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