X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fnet%2Frtl8169.c;h=7b6e20f30fbfe3ee4f0413be7dce4f4f645be219;hb=fe0596cac3079a74eeee93e2940010a7a158c58d;hp=d71323f7f41858942b5373bfa04641c96e57d415;hpb=92915741fc7c77175680e036965fb88d7552d743;p=u-boot diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index d71323f7f4..7b6e20f30f 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -11,19 +11,7 @@ * r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit * Written 2003 by Timothy Legge * -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * SPDX-License-Identifier: GPL-2.0+ * * Portions of this code based on: * r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver @@ -53,14 +41,16 @@ * Modified to use le32_to_cpu and cpu_to_le32 properly */ #include +#include +#include #include #include +#ifndef CONFIG_DM_ETH +#include +#endif #include #include -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ - defined(CONFIG_RTL8169) - #undef DEBUG_RTL8169 #undef DEBUG_RTL8169_TX #undef DEBUG_RTL8169_RX @@ -68,7 +58,7 @@ #define drv_version "v1.5" #define drv_date "01-17-2004" -static u32 ioaddr; +static unsigned long ioaddr; /* Condensed operations for readability. */ #define currticks() get_timer(0) @@ -93,7 +83,11 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ #define NUM_TX_DESC 1 /* Number of Tx descriptor registers */ -#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */ +#ifdef CONFIG_SYS_RX_ETH_BUFFER + #define NUM_RX_DESC CONFIG_SYS_RX_ETH_BUFFER +#else + #define NUM_RX_DESC 4 /* Number of Rx descriptor registers */ +#endif #define RX_BUF_SIZE 1536 /* Rx Buffer size */ #define RX_BUF_LEN 8192 @@ -101,22 +95,29 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #define TX_TIMEOUT (6*HZ) /* write/read MMIO register. Notice: {read,write}[wl] do the necessary swapping */ -#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) -#define RTL_R8(reg) readb (ioaddr + (reg)) -#define RTL_R16(reg) readw (ioaddr + (reg)) -#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) +#define RTL_W8(reg, val8) writeb((val8), ioaddr + (reg)) +#define RTL_W16(reg, val16) writew((val16), ioaddr + (reg)) +#define RTL_W32(reg, val32) writel((val32), ioaddr + (reg)) +#define RTL_R8(reg) readb(ioaddr + (reg)) +#define RTL_R16(reg) readw(ioaddr + (reg)) +#define RTL_R32(reg) readl(ioaddr + (reg)) #define ETH_FRAME_LEN MAX_ETH_FRAME_SIZE #define ETH_ALEN MAC_ADDR_LEN #define ETH_ZLEN 60 +#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)(unsigned long)dev->priv, \ + (pci_addr_t)(unsigned long)a) +#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)(unsigned long)dev->priv, \ + (phys_addr_t)a) + enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ - TxDescStartAddr = 0x20, - TxHDescStartAddr = 0x28, + TxDescStartAddrLow = 0x20, + TxDescStartAddrHigh = 0x24, + TxHDescStartAddrLow = 0x28, + TxHDescStartAddrHigh = 0x2c, FLASH = 0x30, ERSR = 0x36, ChipCmd = 0x37, @@ -141,7 +142,8 @@ enum RTL8169_registers { PHYstatus = 0x6C, RxMaxSize = 0xDA, CPlusCmd = 0xE0, - RxDescStartAddr = 0xE4, + RxDescStartAddrLow = 0xE4, + RxDescStartAddrHigh = 0xE8, EarlyTxThres = 0xEC, FuncEvent = 0xF0, FuncEventMask = 0xF4, @@ -247,6 +249,18 @@ static struct { } rtl_chip_info[] = { {"RTL-8169", 0x00, 0xff7e1880,}, {"RTL-8169", 0x04, 0xff7e1880,}, + {"RTL-8169", 0x00, 0xff7e1880,}, + {"RTL-8169s/8110s", 0x02, 0xff7e1880,}, + {"RTL-8169s/8110s", 0x04, 0xff7e1880,}, + {"RTL-8169sb/8110sb", 0x10, 0xff7e1880,}, + {"RTL-8169sc/8110sc", 0x18, 0xff7e1880,}, + {"RTL-8168b/8111sb", 0x30, 0xff7e1880,}, + {"RTL-8168b/8111sb", 0x38, 0xff7e1880,}, + {"RTL-8168d/8111d", 0x28, 0xff7e1880,}, + {"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,}, + {"RTL-8168/8111g", 0x4c, 0xff7e1880,}, + {"RTL-8101e", 0x34, 0xff7e1880,}, + {"RTL-8100e", 0x32, 0xff7e1880,}, }; enum _DescStatusBit { @@ -270,32 +284,51 @@ struct RxDesc { u32 buf_Haddr; }; -/* Define the TX Descriptor */ -static u8 tx_ring[NUM_TX_DESC * sizeof(struct TxDesc) + 256]; -/* __attribute__ ((aligned(256))); */ +static unsigned char rxdata[RX_BUF_LEN]; -/* Create a static buffer of size RX_BUF_SZ for each -TX Descriptor. All descriptors point to a -part of this buffer */ -static unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE]; +#define RTL8169_DESC_SIZE 16 -/* Define the RX Descriptor */ -static u8 rx_ring[NUM_RX_DESC * sizeof(struct TxDesc) + 256]; - /* __attribute__ ((aligned(256))); */ +#if ARCH_DMA_MINALIGN > 256 +# define RTL8169_ALIGN ARCH_DMA_MINALIGN +#else +# define RTL8169_ALIGN 256 +#endif -/* Create a static buffer of size RX_BUF_SZ for each -RX Descriptor All descriptors point to a -part of this buffer */ -static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]; +/* + * Warn if the cache-line size is larger than the descriptor size. In such + * cases the driver will likely fail because the CPU needs to flush the cache + * when requeuing RX buffers, therefore descriptors written by the hardware + * may be discarded. + * + * This can be fixed by defining CONFIG_SYS_NONCACHED_MEMORY which will cause + * the driver to allocate descriptors from a pool of non-cached memory. + */ +#if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN +#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ + !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) +#warning cache-line size is larger than descriptor size +#endif +#endif + +/* + * Create a static buffer of size RX_BUF_SZ for each TX Descriptor. All + * descriptors point to a part of this buffer. + */ +DEFINE_ALIGN_BUFFER(u8, txb, NUM_TX_DESC * RX_BUF_SIZE, RTL8169_ALIGN); + +/* + * Create a static buffer of size RX_BUF_SZ for each RX Descriptor. All + * descriptors point to a part of this buffer. + */ +DEFINE_ALIGN_BUFFER(u8, rxb, NUM_RX_DESC * RX_BUF_SIZE, RTL8169_ALIGN); struct rtl8169_private { + ulong iobase; void *mmio_addr; /* memory map physical address */ int chipset; unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ unsigned long dirty_tx; - unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */ - unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */ struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ unsigned char *RxBufferRings; /* Index of Rx Buffer */ @@ -312,7 +345,9 @@ static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); static struct pci_device_id supported[] = { - {PCI_VENDOR_ID_REALTEK, 0x8169}, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169) }, {} }; @@ -352,7 +387,7 @@ int mdio_read(int RegAddr) return value; } -static int rtl8169_init_board(struct eth_device *dev) +static int rtl8169_init_board(unsigned long dev_iobase, const char *name) { int i; u32 tmp; @@ -360,7 +395,7 @@ static int rtl8169_init_board(struct eth_device *dev) #ifdef DEBUG_RTL8169 printf ("%s\n", __FUNCTION__); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; /* Soft reset the chip. */ RTL_W8(ChipCmd, CmdReset); @@ -384,18 +419,101 @@ static int rtl8169_init_board(struct eth_device *dev) } /* if unknown chip, assume array element #0, original RTL-8169 in this case */ - printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name); - printf("PCI device: TxConfig = 0x%hX\n", (unsigned long) RTL_R32(TxConfig)); + printf("PCI device %s: unknown chip version, assuming RTL-8169\n", + name); + printf("PCI device: TxConfig = 0x%lX\n", (unsigned long) RTL_R32(TxConfig)); tpc->chipset = 0; match: return 0; } +/* + * TX and RX descriptors are 16 bytes. This causes problems with the cache + * maintenance on CPUs where the cache-line size exceeds the size of these + * descriptors. What will happen is that when the driver receives a packet + * it will be immediately requeued for the hardware to reuse. The CPU will + * therefore need to flush the cache-line containing the descriptor, which + * will cause all other descriptors in the same cache-line to be flushed + * along with it. If one of those descriptors had been written to by the + * device those changes (and the associated packet) will be lost. + * + * To work around this, we make use of non-cached memory if available. If + * descriptors are mapped uncached there's no need to manually flush them + * or invalidate them. + * + * Note that this only applies to descriptors. The packet data buffers do + * not have the same constraints since they are 1536 bytes large, so they + * are unlikely to share cache-lines. + */ +static void *rtl_alloc_descs(unsigned int num) +{ + size_t size = num * RTL8169_DESC_SIZE; + +#ifdef CONFIG_SYS_NONCACHED_MEMORY + return (void *)noncached_alloc(size, RTL8169_ALIGN); +#else + return memalign(RTL8169_ALIGN, size); +#endif +} + +/* + * Cache maintenance functions. These are simple wrappers around the more + * general purpose flush_cache() and invalidate_dcache_range() functions. + */ + +static void rtl_inval_rx_desc(struct RxDesc *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +#endif +} + +static void rtl_flush_rx_desc(struct RxDesc *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + flush_cache((unsigned long)desc, sizeof(*desc)); +#endif +} + +static void rtl_inval_tx_desc(struct TxDesc *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +#endif +} + +static void rtl_flush_tx_desc(struct TxDesc *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + flush_cache((unsigned long)desc, sizeof(*desc)); +#endif +} + +static void rtl_inval_buffer(void *buf, size_t size) +{ + unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void rtl_flush_buffer(void *buf, size_t size) +{ + flush_cache((unsigned long)buf, size); +} + /************************************************************************** RECV - Receive a frame ***************************************************************************/ -static int rtl_recv(struct eth_device *dev) +static int rtl_recv_common(pci_dev_t bdf, unsigned long dev_iobase, + uchar **packetp) { /* return true if there's an ethernet packet ready to read */ /* nic->packet should contain data on return */ @@ -406,17 +524,19 @@ static int rtl_recv(struct eth_device *dev) #ifdef DEBUG_RTL8169_RX printf ("%s\n", __FUNCTION__); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; cur_rx = tpc->cur_rx; + + rtl_inval_rx_desc(&tpc->RxDescArray[cur_rx]); + if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) { if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) { - unsigned char rxdata[RX_BUF_LEN]; length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx]. status) & 0x00001FFF) - 4; + rtl_inval_buffer(tpc->RxBufferRing[cur_rx], length); memcpy(rxdata, tpc->RxBufferRing[cur_rx], length); - NetReceive(rxdata, length); if (cur_rx == NUM_RX_DESC - 1) tpc->RxDescArray[cur_rx].status = @@ -424,25 +544,52 @@ static int rtl_recv(struct eth_device *dev) else tpc->RxDescArray[cur_rx].status = cpu_to_le32(OWNbit + RX_BUF_SIZE); - tpc->RxDescArray[cur_rx].buf_addr = - cpu_to_le32(tpc->RxBufferRing[cur_rx]); + tpc->RxDescArray[cur_rx].buf_addr = cpu_to_le32( + pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long) + tpc->RxBufferRing[cur_rx])); + rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]); +#ifdef CONFIG_DM_ETH + *packetp = rxdata; +#else + net_process_received_packet(rxdata, length); +#endif } else { puts("Error Rx"); + length = -EIO; } cur_rx = (cur_rx + 1) % NUM_RX_DESC; tpc->cur_rx = cur_rx; - return 1; + return length; + } else { + ushort sts = RTL_R8(IntrStatus); + RTL_W8(IntrStatus, sts & ~(TxErr | RxErr | SYSErr)); + udelay(100); /* wait */ } tpc->cur_rx = cur_rx; return (0); /* initially as this is called to flush the input */ } +#ifdef CONFIG_DM_ETH +int rtl8169_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct rtl8169_private *priv = dev_get_priv(dev); + + return rtl_recv_common(pci_get_bdf(dev), priv->iobase, packetp); +} +#else +static int rtl_recv(struct eth_device *dev) +{ + return rtl_recv_common((pci_dev_t)dev->priv, dev->iobase, NULL); +} +#endif /* nCONFIG_DM_ETH */ + #define HZ 1000 /************************************************************************** SEND - Transmit a frame ***************************************************************************/ -static int rtl_send(struct eth_device *dev, volatile void *packet, int length) +static int rtl_send_common(pci_dev_t bdf, unsigned long dev_iobase, + void *packet, int length) { /* send the packet to destination */ @@ -458,16 +605,19 @@ static int rtl_send(struct eth_device *dev, volatile void *packet, int length) printf("sending %d bytes\n", len); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; /* point to the current txb incase multiple tx_rings are used */ ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE]; memcpy(ptxb, (char *)packet, (int)length); + rtl_flush_buffer(ptxb, length); while (len < ETH_ZLEN) ptxb[len++] = '\0'; - tpc->TxDescArray[entry].buf_addr = cpu_to_le32(ptxb); + tpc->TxDescArray[entry].buf_Haddr = 0; + tpc->TxDescArray[entry].buf_addr = cpu_to_le32( + pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)ptxb)); if (entry != (NUM_TX_DESC - 1)) { tpc->TxDescArray[entry].status = cpu_to_le32((OWNbit | FSbit | LSbit) | @@ -477,17 +627,20 @@ static int rtl_send(struct eth_device *dev, volatile void *packet, int length) cpu_to_le32((OWNbit | EORbit | FSbit | LSbit) | ((len > ETH_ZLEN) ? len : ETH_ZLEN)); } + rtl_flush_tx_desc(&tpc->TxDescArray[entry]); RTL_W8(TxPoll, 0x40); /* set polling bit */ tpc->cur_tx++; to = currticks() + TX_TIMEOUT; - while ((le32_to_cpu(tpc->TxDescArray[entry].status) & OWNbit) + do { + rtl_inval_tx_desc(&tpc->TxDescArray[entry]); + } while ((le32_to_cpu(tpc->TxDescArray[entry].status) & OWNbit) && (currticks() < to)); /* wait */ if (currticks() >= to) { #ifdef DEBUG_RTL8169_TX - puts ("tx timeout/error\n"); - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + puts("tx timeout/error\n"); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif ret = 0; } else { @@ -501,7 +654,23 @@ static int rtl_send(struct eth_device *dev, volatile void *packet, int length) return ret; } -static void rtl8169_set_rx_mode(struct eth_device *dev) +#ifdef CONFIG_DM_ETH +int rtl8169_eth_send(struct udevice *dev, void *packet, int length) +{ + struct rtl8169_private *priv = dev_get_priv(dev); + + return rtl_send_common(pci_get_bdf(dev), priv->iobase, packet, length); +} + +#else +static int rtl_send(struct eth_device *dev, void *packet, int length) +{ + return rtl_send_common((pci_dev_t)dev->priv, dev->iobase, packet, + length); +} +#endif + +static void rtl8169_set_rx_mode(void) { u32 mc_filter[2]; /* Multicast hash filter */ int rx_mode; @@ -524,7 +693,7 @@ static void rtl8169_set_rx_mode(struct eth_device *dev) RTL_W32(MAR0 + 4, mc_filter[1]); } -static void rtl8169_hw_start(struct eth_device *dev) +static void rtl8169_hw_start(pci_dev_t bdf) { u32 i; @@ -547,7 +716,11 @@ static void rtl8169_hw_start(struct eth_device *dev) #endif RTL_W8(Cfg9346, Cfg9346_Unlock); - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + /* RTL-8169sb/8110sb or previous version */ + if (tpc->chipset <= 5) + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + RTL_W8(EarlyTxThres, EarlyTxThld); /* For gigabit rtl8169 */ @@ -565,24 +738,33 @@ static void rtl8169_hw_start(struct eth_device *dev) tpc->cur_rx = 0; - RTL_W32(TxDescStartAddr, tpc->TxDescArray); - RTL_W32(RxDescStartAddr, tpc->RxDescArray); + RTL_W32(TxDescStartAddrLow, pci_mem_to_phys(bdf, + (pci_addr_t)(unsigned long)tpc->TxDescArray)); + RTL_W32(TxDescStartAddrHigh, (unsigned long)0); + RTL_W32(RxDescStartAddrLow, pci_mem_to_phys( + bdf, (pci_addr_t)(unsigned long)tpc->RxDescArray)); + RTL_W32(RxDescStartAddrHigh, (unsigned long)0); + + /* RTL-8169sc/8110sc or later version */ + if (tpc->chipset > 5) + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + RTL_W8(Cfg9346, Cfg9346_Lock); udelay(10); RTL_W32(RxMissed, 0); - rtl8169_set_rx_mode(dev); + rtl8169_set_rx_mode(); /* no early-rx interrupts */ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); #ifdef DEBUG_RTL8169 - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif } -static void rtl8169_init_ring(struct eth_device *dev) +static void rtl8169_init_ring(pci_dev_t bdf) { int i; @@ -610,19 +792,17 @@ static void rtl8169_init_ring(struct eth_device *dev) cpu_to_le32(OWNbit + RX_BUF_SIZE); tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; - tpc->RxDescArray[i].buf_addr = - cpu_to_le32(tpc->RxBufferRing[i]); + tpc->RxDescArray[i].buf_addr = cpu_to_le32(pci_mem_to_phys( + bdf, (pci_addr_t)(unsigned long)tpc->RxBufferRing[i])); + rtl_flush_rx_desc(&tpc->RxDescArray[i]); } #ifdef DEBUG_RTL8169 - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif } -/************************************************************************** -RESET - Finish setting up the ethernet interface -***************************************************************************/ -static int rtl_reset(struct eth_device *dev, bd_t *bis) +static void rtl8169_common_start(pci_dev_t bdf, unsigned char *enetaddr) { int i; @@ -631,40 +811,47 @@ static int rtl_reset(struct eth_device *dev, bd_t *bis) printf ("%s\n", __FUNCTION__); #endif - tpc->TxDescArrays = tx_ring; - /* Tx Desscriptor needs 256 bytes alignment; */ - tpc->TxDescArray = (struct TxDesc *) ((unsigned long)(tpc->TxDescArrays + - 255) & ~255); - - tpc->RxDescArrays = rx_ring; - /* Rx Desscriptor needs 256 bytes alignment; */ - tpc->RxDescArray = (struct RxDesc *) ((unsigned long)(tpc->RxDescArrays + - 255) & ~255); - - rtl8169_init_ring(dev); - rtl8169_hw_start(dev); + rtl8169_init_ring(bdf); + rtl8169_hw_start(bdf); /* Construct a perfect filter frame with the mac address as first match * and broadcast for all others */ for (i = 0; i < 192; i++) txb[i] = 0xFF; - txb[0] = dev->enetaddr[0]; - txb[1] = dev->enetaddr[1]; - txb[2] = dev->enetaddr[2]; - txb[3] = dev->enetaddr[3]; - txb[4] = dev->enetaddr[4]; - txb[5] = dev->enetaddr[5]; + txb[0] = enetaddr[0]; + txb[1] = enetaddr[1]; + txb[2] = enetaddr[2]; + txb[3] = enetaddr[3]; + txb[4] = enetaddr[4]; + txb[5] = enetaddr[5]; #ifdef DEBUG_RTL8169 - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif - return 0; } +#ifdef CONFIG_DM_ETH +static int rtl8169_eth_start(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + + rtl8169_common_start(pci_get_bdf(dev), plat->enetaddr); + + return 0; +} +#else /************************************************************************** -HALT - Turn off ethernet interface +RESET - Finish setting up the ethernet interface ***************************************************************************/ -static void rtl_halt(struct eth_device *dev) +static int rtl_reset(struct eth_device *dev, bd_t *bis) +{ + rtl8169_common_start((pci_dev_t)dev->priv, dev->enetaddr); + + return 0; +} +#endif /* nCONFIG_DM_ETH */ + +static void rtl_halt_common(unsigned long dev_iobase) { int i; @@ -672,7 +859,7 @@ static void rtl_halt(struct eth_device *dev) printf ("%s\n", __FUNCTION__); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; /* Stop the chip's Tx and Rx DMA processes. */ RTL_W8(ChipCmd, 0x00); @@ -682,59 +869,70 @@ static void rtl_halt(struct eth_device *dev) RTL_W32(RxMissed, 0); - tpc->TxDescArrays = NULL; - tpc->RxDescArrays = NULL; - tpc->TxDescArray = NULL; - tpc->RxDescArray = NULL; for (i = 0; i < NUM_RX_DESC; i++) { tpc->RxBufferRing[i] = NULL; } } +#ifdef CONFIG_DM_ETH +void rtl8169_eth_stop(struct udevice *dev) +{ + struct rtl8169_private *priv = dev_get_priv(dev); + + rtl_halt_common(priv->iobase); +} +#else +/************************************************************************** +HALT - Turn off ethernet interface +***************************************************************************/ +static void rtl_halt(struct eth_device *dev) +{ + rtl_halt_common(dev->iobase); +} +#endif + /************************************************************************** INIT - Look for an adapter, this routine's visible to the outside ***************************************************************************/ #define board_found 1 #define valid_link 0 -static int rtl_init(struct eth_device *dev, bd_t *bis) +static int rtl_init(unsigned long dev_ioaddr, const char *name, + unsigned char *enetaddr) { static int board_idx = -1; - static int printed_version = 0; int i, rc; int option = -1, Cap10_100 = 0, Cap1000 = 0; #ifdef DEBUG_RTL8169 printf ("%s\n", __FUNCTION__); #endif - - ioaddr = dev->iobase; + ioaddr = dev_ioaddr; board_idx++; - printed_version = 1; - /* point to private storage */ tpc = &tpx; - rc = rtl8169_init_board(dev); + rc = rtl8169_init_board(ioaddr, name); if (rc) return rc; /* Get MAC address. FIXME: read EEPROM */ for (i = 0; i < MAC_ADDR_LEN; i++) - bis->bi_enetaddr[i] = dev->enetaddr[i] = RTL_R8(MAC0 + i); + enetaddr[i] = RTL_R8(MAC0 + i); #ifdef DEBUG_RTL8169 + printf("chipset = %d\n", tpc->chipset); printf("MAC Address"); for (i = 0; i < MAC_ADDR_LEN; i++) - printf(":%02x", dev->enetaddr[i]); + printf(":%02x", enetaddr[i]); putc('\n'); #endif #ifdef DEBUG_RTL8169 /* Print out some hardware info */ - printf("%s: at ioaddr 0x%x\n", dev->name, ioaddr); + printf("%s: at ioaddr 0x%lx\n", name, ioaddr); #endif /* if TBI is not endbled */ @@ -832,9 +1030,19 @@ static int rtl_init(struct eth_device *dev, bd_t *bis) #endif } - return 1; + + tpc->RxDescArray = rtl_alloc_descs(NUM_RX_DESC); + if (!tpc->RxDescArray) + return -ENOMEM; + + tpc->TxDescArray = rtl_alloc_descs(NUM_TX_DESC); + if (!tpc->TxDescArray) + return -ENOMEM; + + return 0; } +#ifndef CONFIG_DM_ETH int rtl8169_initialize(bd_t *bis) { pci_dev_t devno; @@ -844,20 +1052,40 @@ int rtl8169_initialize(bd_t *bis) int idx=0; while(1){ + unsigned int region; + u16 device; + int err; + /* Find RTL8169 */ if ((devno = pci_find_devices(supported, idx++)) < 0) break; - pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase); + pci_read_config_word(devno, PCI_DEVICE_ID, &device); + switch (device) { + case 0x8168: + region = 2; + break; + + default: + region = 1; + break; + } + + pci_read_config_dword(devno, PCI_BASE_ADDRESS_0 + (region * 4), &iobase); iobase &= ~0xf; debug ("rtl8169: REALTEK RTL8169 @0x%x\n", iobase); dev = (struct eth_device *)malloc(sizeof *dev); + if (!dev) { + printf("Can not allocate memory of rtl8169\n"); + break; + } + memset(dev, 0, sizeof(*dev)); sprintf (dev->name, "RTL8169#%d", card_number); - dev->priv = (void *) devno; + dev->priv = (void *)(unsigned long)devno; dev->iobase = (int)pci_mem_to_phys(devno, iobase); dev->init = rtl_reset; @@ -865,13 +1093,75 @@ int rtl8169_initialize(bd_t *bis) dev->send = rtl_send; dev->recv = rtl_recv; - eth_register (dev); + err = rtl_init(dev->iobase, dev->name, dev->enetaddr); + if (err < 0) { + printf(pr_fmt("failed to initialize card: %d\n"), err); + free(dev); + continue; + } - rtl_init(dev, bis); + eth_register (dev); card_number++; } return card_number; } +#endif + +#ifdef CONFIG_DM_ETH +static int rtl8169_eth_probe(struct udevice *dev) +{ + struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); + struct rtl8169_private *priv = dev_get_priv(dev); + struct eth_pdata *plat = dev_get_platdata(dev); + u32 iobase; + int region; + int ret; + + debug("rtl8169: REALTEK RTL8169 @0x%x\n", iobase); + switch (pplat->device) { + case 0x8168: + region = 2; + break; + default: + region = 1; + break; + } + pci_read_config32(pci_get_bdf(dev), PCI_BASE_ADDRESS_0 + region * 4, + &iobase); + iobase &= ~0xf; + priv->iobase = (int)pci_mem_to_phys(pci_get_bdf(dev), iobase); + + ret = rtl_init(priv->iobase, dev->name, plat->enetaddr); + if (ret < 0) { + printf(pr_fmt("failed to initialize card: %d\n"), ret); + return ret; + } + + return 0; +} + +static const struct eth_ops rtl8169_eth_ops = { + .start = rtl8169_eth_start, + .send = rtl8169_eth_send, + .recv = rtl8169_eth_recv, + .stop = rtl8169_eth_stop, +}; + +static const struct udevice_id rtl8169_eth_ids[] = { + { .compatible = "realtek,rtl8169" }, + { } +}; + +U_BOOT_DRIVER(eth_rtl8169) = { + .name = "eth_rtl8169", + .id = UCLASS_ETH, + .of_match = rtl8169_eth_ids, + .probe = rtl8169_eth_probe, + .ops = &rtl8169_eth_ops, + .priv_auto_alloc_size = sizeof(struct rtl8169_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; +U_BOOT_PCI_DEVICE(eth_rtl8169, supported); #endif