18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Alchemy Au1x00 ethernet driver 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2001-2003, 2006 MontaVista Software Inc. 78c2ecf20Sopenharmony_ci * Copyright 2002 TimeSys Corp. 88c2ecf20Sopenharmony_ci * Added ethtool/mii-tool support, 98c2ecf20Sopenharmony_ci * Copyright 2004 Matt Porter <mporter@kernel.crashing.org> 108c2ecf20Sopenharmony_ci * Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de 118c2ecf20Sopenharmony_ci * or riemer@riemer-nt.de: fixed the link beat detection with 128c2ecf20Sopenharmony_ci * ioctls (SIOCGMIIPHY) 138c2ecf20Sopenharmony_ci * Copyright 2006 Herbert Valerio Riedel <hvr@gnu.org> 148c2ecf20Sopenharmony_ci * converted to use linux-2.6.x's PHY framework 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Author: MontaVista Software, Inc. 178c2ecf20Sopenharmony_ci * ppopov@mvista.com or source@mvista.com 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/capability.h> 228c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/kernel.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include <linux/timer.h> 278c2ecf20Sopenharmony_ci#include <linux/errno.h> 288c2ecf20Sopenharmony_ci#include <linux/in.h> 298c2ecf20Sopenharmony_ci#include <linux/ioport.h> 308c2ecf20Sopenharmony_ci#include <linux/bitops.h> 318c2ecf20Sopenharmony_ci#include <linux/slab.h> 328c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 338c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 348c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 358c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 368c2ecf20Sopenharmony_ci#include <linux/mii.h> 378c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 388c2ecf20Sopenharmony_ci#include <linux/delay.h> 398c2ecf20Sopenharmony_ci#include <linux/crc32.h> 408c2ecf20Sopenharmony_ci#include <linux/phy.h> 418c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 428c2ecf20Sopenharmony_ci#include <linux/cpu.h> 438c2ecf20Sopenharmony_ci#include <linux/io.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include <asm/mipsregs.h> 468c2ecf20Sopenharmony_ci#include <asm/irq.h> 478c2ecf20Sopenharmony_ci#include <asm/processor.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <au1000.h> 508c2ecf20Sopenharmony_ci#include <au1xxx_eth.h> 518c2ecf20Sopenharmony_ci#include <prom.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include "au1000_eth.h" 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#ifdef AU1000_ETH_DEBUG 568c2ecf20Sopenharmony_cistatic int au1000_debug = 5; 578c2ecf20Sopenharmony_ci#else 588c2ecf20Sopenharmony_cistatic int au1000_debug = 3; 598c2ecf20Sopenharmony_ci#endif 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define AU1000_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ 628c2ecf20Sopenharmony_ci NETIF_MSG_PROBE | \ 638c2ecf20Sopenharmony_ci NETIF_MSG_LINK) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define DRV_NAME "au1000_eth" 668c2ecf20Sopenharmony_ci#define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>" 678c2ecf20Sopenharmony_ci#define DRV_DESC "Au1xxx on-chip Ethernet driver" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_AUTHOR); 708c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC); 718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* AU1000 MAC registers and bits */ 748c2ecf20Sopenharmony_ci#define MAC_CONTROL 0x0 758c2ecf20Sopenharmony_ci# define MAC_RX_ENABLE (1 << 2) 768c2ecf20Sopenharmony_ci# define MAC_TX_ENABLE (1 << 3) 778c2ecf20Sopenharmony_ci# define MAC_DEF_CHECK (1 << 5) 788c2ecf20Sopenharmony_ci# define MAC_SET_BL(X) (((X) & 0x3) << 6) 798c2ecf20Sopenharmony_ci# define MAC_AUTO_PAD (1 << 8) 808c2ecf20Sopenharmony_ci# define MAC_DISABLE_RETRY (1 << 10) 818c2ecf20Sopenharmony_ci# define MAC_DISABLE_BCAST (1 << 11) 828c2ecf20Sopenharmony_ci# define MAC_LATE_COL (1 << 12) 838c2ecf20Sopenharmony_ci# define MAC_HASH_MODE (1 << 13) 848c2ecf20Sopenharmony_ci# define MAC_HASH_ONLY (1 << 15) 858c2ecf20Sopenharmony_ci# define MAC_PASS_ALL (1 << 16) 868c2ecf20Sopenharmony_ci# define MAC_INVERSE_FILTER (1 << 17) 878c2ecf20Sopenharmony_ci# define MAC_PROMISCUOUS (1 << 18) 888c2ecf20Sopenharmony_ci# define MAC_PASS_ALL_MULTI (1 << 19) 898c2ecf20Sopenharmony_ci# define MAC_FULL_DUPLEX (1 << 20) 908c2ecf20Sopenharmony_ci# define MAC_NORMAL_MODE 0 918c2ecf20Sopenharmony_ci# define MAC_INT_LOOPBACK (1 << 21) 928c2ecf20Sopenharmony_ci# define MAC_EXT_LOOPBACK (1 << 22) 938c2ecf20Sopenharmony_ci# define MAC_DISABLE_RX_OWN (1 << 23) 948c2ecf20Sopenharmony_ci# define MAC_BIG_ENDIAN (1 << 30) 958c2ecf20Sopenharmony_ci# define MAC_RX_ALL (1 << 31) 968c2ecf20Sopenharmony_ci#define MAC_ADDRESS_HIGH 0x4 978c2ecf20Sopenharmony_ci#define MAC_ADDRESS_LOW 0x8 988c2ecf20Sopenharmony_ci#define MAC_MCAST_HIGH 0xC 998c2ecf20Sopenharmony_ci#define MAC_MCAST_LOW 0x10 1008c2ecf20Sopenharmony_ci#define MAC_MII_CNTRL 0x14 1018c2ecf20Sopenharmony_ci# define MAC_MII_BUSY (1 << 0) 1028c2ecf20Sopenharmony_ci# define MAC_MII_READ 0 1038c2ecf20Sopenharmony_ci# define MAC_MII_WRITE (1 << 1) 1048c2ecf20Sopenharmony_ci# define MAC_SET_MII_SELECT_REG(X) (((X) & 0x1f) << 6) 1058c2ecf20Sopenharmony_ci# define MAC_SET_MII_SELECT_PHY(X) (((X) & 0x1f) << 11) 1068c2ecf20Sopenharmony_ci#define MAC_MII_DATA 0x18 1078c2ecf20Sopenharmony_ci#define MAC_FLOW_CNTRL 0x1C 1088c2ecf20Sopenharmony_ci# define MAC_FLOW_CNTRL_BUSY (1 << 0) 1098c2ecf20Sopenharmony_ci# define MAC_FLOW_CNTRL_ENABLE (1 << 1) 1108c2ecf20Sopenharmony_ci# define MAC_PASS_CONTROL (1 << 2) 1118c2ecf20Sopenharmony_ci# define MAC_SET_PAUSE(X) (((X) & 0xffff) << 16) 1128c2ecf20Sopenharmony_ci#define MAC_VLAN1_TAG 0x20 1138c2ecf20Sopenharmony_ci#define MAC_VLAN2_TAG 0x24 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Ethernet Controller Enable */ 1168c2ecf20Sopenharmony_ci# define MAC_EN_CLOCK_ENABLE (1 << 0) 1178c2ecf20Sopenharmony_ci# define MAC_EN_RESET0 (1 << 1) 1188c2ecf20Sopenharmony_ci# define MAC_EN_TOSS (0 << 2) 1198c2ecf20Sopenharmony_ci# define MAC_EN_CACHEABLE (1 << 3) 1208c2ecf20Sopenharmony_ci# define MAC_EN_RESET1 (1 << 4) 1218c2ecf20Sopenharmony_ci# define MAC_EN_RESET2 (1 << 5) 1228c2ecf20Sopenharmony_ci# define MAC_DMA_RESET (1 << 6) 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Ethernet Controller DMA Channels */ 1258c2ecf20Sopenharmony_ci/* offsets from MAC_TX_RING_ADDR address */ 1268c2ecf20Sopenharmony_ci#define MAC_TX_BUFF0_STATUS 0x0 1278c2ecf20Sopenharmony_ci# define TX_FRAME_ABORTED (1 << 0) 1288c2ecf20Sopenharmony_ci# define TX_JAB_TIMEOUT (1 << 1) 1298c2ecf20Sopenharmony_ci# define TX_NO_CARRIER (1 << 2) 1308c2ecf20Sopenharmony_ci# define TX_LOSS_CARRIER (1 << 3) 1318c2ecf20Sopenharmony_ci# define TX_EXC_DEF (1 << 4) 1328c2ecf20Sopenharmony_ci# define TX_LATE_COLL_ABORT (1 << 5) 1338c2ecf20Sopenharmony_ci# define TX_EXC_COLL (1 << 6) 1348c2ecf20Sopenharmony_ci# define TX_UNDERRUN (1 << 7) 1358c2ecf20Sopenharmony_ci# define TX_DEFERRED (1 << 8) 1368c2ecf20Sopenharmony_ci# define TX_LATE_COLL (1 << 9) 1378c2ecf20Sopenharmony_ci# define TX_COLL_CNT_MASK (0xF << 10) 1388c2ecf20Sopenharmony_ci# define TX_PKT_RETRY (1 << 31) 1398c2ecf20Sopenharmony_ci#define MAC_TX_BUFF0_ADDR 0x4 1408c2ecf20Sopenharmony_ci# define TX_DMA_ENABLE (1 << 0) 1418c2ecf20Sopenharmony_ci# define TX_T_DONE (1 << 1) 1428c2ecf20Sopenharmony_ci# define TX_GET_DMA_BUFFER(X) (((X) >> 2) & 0x3) 1438c2ecf20Sopenharmony_ci#define MAC_TX_BUFF0_LEN 0x8 1448c2ecf20Sopenharmony_ci#define MAC_TX_BUFF1_STATUS 0x10 1458c2ecf20Sopenharmony_ci#define MAC_TX_BUFF1_ADDR 0x14 1468c2ecf20Sopenharmony_ci#define MAC_TX_BUFF1_LEN 0x18 1478c2ecf20Sopenharmony_ci#define MAC_TX_BUFF2_STATUS 0x20 1488c2ecf20Sopenharmony_ci#define MAC_TX_BUFF2_ADDR 0x24 1498c2ecf20Sopenharmony_ci#define MAC_TX_BUFF2_LEN 0x28 1508c2ecf20Sopenharmony_ci#define MAC_TX_BUFF3_STATUS 0x30 1518c2ecf20Sopenharmony_ci#define MAC_TX_BUFF3_ADDR 0x34 1528c2ecf20Sopenharmony_ci#define MAC_TX_BUFF3_LEN 0x38 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* offsets from MAC_RX_RING_ADDR */ 1558c2ecf20Sopenharmony_ci#define MAC_RX_BUFF0_STATUS 0x0 1568c2ecf20Sopenharmony_ci# define RX_FRAME_LEN_MASK 0x3fff 1578c2ecf20Sopenharmony_ci# define RX_WDOG_TIMER (1 << 14) 1588c2ecf20Sopenharmony_ci# define RX_RUNT (1 << 15) 1598c2ecf20Sopenharmony_ci# define RX_OVERLEN (1 << 16) 1608c2ecf20Sopenharmony_ci# define RX_COLL (1 << 17) 1618c2ecf20Sopenharmony_ci# define RX_ETHER (1 << 18) 1628c2ecf20Sopenharmony_ci# define RX_MII_ERROR (1 << 19) 1638c2ecf20Sopenharmony_ci# define RX_DRIBBLING (1 << 20) 1648c2ecf20Sopenharmony_ci# define RX_CRC_ERROR (1 << 21) 1658c2ecf20Sopenharmony_ci# define RX_VLAN1 (1 << 22) 1668c2ecf20Sopenharmony_ci# define RX_VLAN2 (1 << 23) 1678c2ecf20Sopenharmony_ci# define RX_LEN_ERROR (1 << 24) 1688c2ecf20Sopenharmony_ci# define RX_CNTRL_FRAME (1 << 25) 1698c2ecf20Sopenharmony_ci# define RX_U_CNTRL_FRAME (1 << 26) 1708c2ecf20Sopenharmony_ci# define RX_MCAST_FRAME (1 << 27) 1718c2ecf20Sopenharmony_ci# define RX_BCAST_FRAME (1 << 28) 1728c2ecf20Sopenharmony_ci# define RX_FILTER_FAIL (1 << 29) 1738c2ecf20Sopenharmony_ci# define RX_PACKET_FILTER (1 << 30) 1748c2ecf20Sopenharmony_ci# define RX_MISSED_FRAME (1 << 31) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci# define RX_ERROR (RX_WDOG_TIMER | RX_RUNT | RX_OVERLEN | \ 1778c2ecf20Sopenharmony_ci RX_COLL | RX_MII_ERROR | RX_CRC_ERROR | \ 1788c2ecf20Sopenharmony_ci RX_LEN_ERROR | RX_U_CNTRL_FRAME | RX_MISSED_FRAME) 1798c2ecf20Sopenharmony_ci#define MAC_RX_BUFF0_ADDR 0x4 1808c2ecf20Sopenharmony_ci# define RX_DMA_ENABLE (1 << 0) 1818c2ecf20Sopenharmony_ci# define RX_T_DONE (1 << 1) 1828c2ecf20Sopenharmony_ci# define RX_GET_DMA_BUFFER(X) (((X) >> 2) & 0x3) 1838c2ecf20Sopenharmony_ci# define RX_SET_BUFF_ADDR(X) ((X) & 0xffffffc0) 1848c2ecf20Sopenharmony_ci#define MAC_RX_BUFF1_STATUS 0x10 1858c2ecf20Sopenharmony_ci#define MAC_RX_BUFF1_ADDR 0x14 1868c2ecf20Sopenharmony_ci#define MAC_RX_BUFF2_STATUS 0x20 1878c2ecf20Sopenharmony_ci#define MAC_RX_BUFF2_ADDR 0x24 1888c2ecf20Sopenharmony_ci#define MAC_RX_BUFF3_STATUS 0x30 1898c2ecf20Sopenharmony_ci#define MAC_RX_BUFF3_ADDR 0x34 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* 1928c2ecf20Sopenharmony_ci * Theory of operation 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * The Au1000 MACs use a simple rx and tx descriptor ring scheme. 1958c2ecf20Sopenharmony_ci * There are four receive and four transmit descriptors. These 1968c2ecf20Sopenharmony_ci * descriptors are not in memory; rather, they are just a set of 1978c2ecf20Sopenharmony_ci * hardware registers. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * Since the Au1000 has a coherent data cache, the receive and 2008c2ecf20Sopenharmony_ci * transmit buffers are allocated from the KSEG0 segment. The 2018c2ecf20Sopenharmony_ci * hardware registers, however, are still mapped at KSEG1 to 2028c2ecf20Sopenharmony_ci * make sure there's no out-of-order writes, and that all writes 2038c2ecf20Sopenharmony_ci * complete immediately. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* 2078c2ecf20Sopenharmony_ci * board-specific configurations 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * PHY detection algorithm 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * If phy_static_config is undefined, the PHY setup is 2128c2ecf20Sopenharmony_ci * autodetected: 2138c2ecf20Sopenharmony_ci * 2148c2ecf20Sopenharmony_ci * mii_probe() first searches the current MAC's MII bus for a PHY, 2158c2ecf20Sopenharmony_ci * selecting the first (or last, if phy_search_highest_addr is 2168c2ecf20Sopenharmony_ci * defined) PHY address not already claimed by another netdev. 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * If nothing was found that way when searching for the 2nd ethernet 2198c2ecf20Sopenharmony_ci * controller's PHY and phy1_search_mac0 is defined, then 2208c2ecf20Sopenharmony_ci * the first MII bus is searched as well for an unclaimed PHY; this is 2218c2ecf20Sopenharmony_ci * needed in case of a dual-PHY accessible only through the MAC0's MII 2228c2ecf20Sopenharmony_ci * bus. 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * Finally, if no PHY is found, then the corresponding ethernet 2258c2ecf20Sopenharmony_ci * controller is not registered to the network subsystem. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* autodetection defaults: phy1_search_mac0 */ 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* static PHY setup 2318c2ecf20Sopenharmony_ci * 2328c2ecf20Sopenharmony_ci * most boards PHY setup should be detectable properly with the 2338c2ecf20Sopenharmony_ci * autodetection algorithm in mii_probe(), but in some cases (e.g. if 2348c2ecf20Sopenharmony_ci * you have a switch attached, or want to use the PHY's interrupt 2358c2ecf20Sopenharmony_ci * notification capabilities) you can provide a static PHY 2368c2ecf20Sopenharmony_ci * configuration here 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * IRQs may only be set, if a PHY address was configured 2398c2ecf20Sopenharmony_ci * If a PHY address is given, also a bus id is required to be set 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * ps: make sure the used irqs are configured properly in the board 2428c2ecf20Sopenharmony_ci * specific irq-map 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic void au1000_enable_mac(struct net_device *dev, int force_reset) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci unsigned long flags; 2478c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci spin_lock_irqsave(&aup->lock, flags); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (force_reset || (!aup->mac_enabled)) { 2528c2ecf20Sopenharmony_ci writel(MAC_EN_CLOCK_ENABLE, aup->enable); 2538c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 2548c2ecf20Sopenharmony_ci mdelay(2); 2558c2ecf20Sopenharmony_ci writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 2568c2ecf20Sopenharmony_ci | MAC_EN_CLOCK_ENABLE), aup->enable); 2578c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 2588c2ecf20Sopenharmony_ci mdelay(2); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci aup->mac_enabled = 1; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&aup->lock, flags); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* 2678c2ecf20Sopenharmony_ci * MII operations 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_cistatic int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 2728c2ecf20Sopenharmony_ci u32 *const mii_control_reg = &aup->mac->mii_control; 2738c2ecf20Sopenharmony_ci u32 *const mii_data_reg = &aup->mac->mii_data; 2748c2ecf20Sopenharmony_ci u32 timedout = 20; 2758c2ecf20Sopenharmony_ci u32 mii_control; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci while (readl(mii_control_reg) & MAC_MII_BUSY) { 2788c2ecf20Sopenharmony_ci mdelay(1); 2798c2ecf20Sopenharmony_ci if (--timedout == 0) { 2808c2ecf20Sopenharmony_ci netdev_err(dev, "read_MII busy timeout!!\n"); 2818c2ecf20Sopenharmony_ci return -1; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci mii_control = MAC_SET_MII_SELECT_REG(reg) | 2868c2ecf20Sopenharmony_ci MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci writel(mii_control, mii_control_reg); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci timedout = 20; 2918c2ecf20Sopenharmony_ci while (readl(mii_control_reg) & MAC_MII_BUSY) { 2928c2ecf20Sopenharmony_ci mdelay(1); 2938c2ecf20Sopenharmony_ci if (--timedout == 0) { 2948c2ecf20Sopenharmony_ci netdev_err(dev, "mdio_read busy timeout!!\n"); 2958c2ecf20Sopenharmony_ci return -1; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci return readl(mii_data_reg); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void au1000_mdio_write(struct net_device *dev, int phy_addr, 3028c2ecf20Sopenharmony_ci int reg, u16 value) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 3058c2ecf20Sopenharmony_ci u32 *const mii_control_reg = &aup->mac->mii_control; 3068c2ecf20Sopenharmony_ci u32 *const mii_data_reg = &aup->mac->mii_data; 3078c2ecf20Sopenharmony_ci u32 timedout = 20; 3088c2ecf20Sopenharmony_ci u32 mii_control; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci while (readl(mii_control_reg) & MAC_MII_BUSY) { 3118c2ecf20Sopenharmony_ci mdelay(1); 3128c2ecf20Sopenharmony_ci if (--timedout == 0) { 3138c2ecf20Sopenharmony_ci netdev_err(dev, "mdio_write busy timeout!!\n"); 3148c2ecf20Sopenharmony_ci return; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci mii_control = MAC_SET_MII_SELECT_REG(reg) | 3198c2ecf20Sopenharmony_ci MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci writel(value, mii_data_reg); 3228c2ecf20Sopenharmony_ci writel(mii_control, mii_control_reg); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct net_device *const dev = bus->priv; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* make sure the MAC associated with this 3308c2ecf20Sopenharmony_ci * mii_bus is enabled 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci au1000_enable_mac(dev, 0); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return au1000_mdio_read(dev, phy_addr, regnum); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, 3388c2ecf20Sopenharmony_ci u16 value) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct net_device *const dev = bus->priv; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* make sure the MAC associated with this 3438c2ecf20Sopenharmony_ci * mii_bus is enabled 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci au1000_enable_mac(dev, 0); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci au1000_mdio_write(dev, phy_addr, regnum, value); 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int au1000_mdiobus_reset(struct mii_bus *bus) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct net_device *const dev = bus->priv; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* make sure the MAC associated with this 3568c2ecf20Sopenharmony_ci * mii_bus is enabled 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci au1000_enable_mac(dev, 0); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void au1000_hard_stop(struct net_device *dev) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 3668c2ecf20Sopenharmony_ci u32 reg; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci netif_dbg(aup, drv, dev, "hard stop\n"); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci reg = readl(&aup->mac->control); 3718c2ecf20Sopenharmony_ci reg &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE); 3728c2ecf20Sopenharmony_ci writel(reg, &aup->mac->control); 3738c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 3748c2ecf20Sopenharmony_ci mdelay(10); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void au1000_enable_rx_tx(struct net_device *dev) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 3808c2ecf20Sopenharmony_ci u32 reg; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci netif_dbg(aup, hw, dev, "enable_rx_tx\n"); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci reg = readl(&aup->mac->control); 3858c2ecf20Sopenharmony_ci reg |= (MAC_RX_ENABLE | MAC_TX_ENABLE); 3868c2ecf20Sopenharmony_ci writel(reg, &aup->mac->control); 3878c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 3888c2ecf20Sopenharmony_ci mdelay(10); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic void 3928c2ecf20Sopenharmony_ciau1000_adjust_link(struct net_device *dev) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 3958c2ecf20Sopenharmony_ci struct phy_device *phydev = dev->phydev; 3968c2ecf20Sopenharmony_ci unsigned long flags; 3978c2ecf20Sopenharmony_ci u32 reg; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci int status_change = 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci BUG_ON(!phydev); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci spin_lock_irqsave(&aup->lock, flags); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (phydev->link && (aup->old_speed != phydev->speed)) { 4068c2ecf20Sopenharmony_ci /* speed changed */ 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci switch (phydev->speed) { 4098c2ecf20Sopenharmony_ci case SPEED_10: 4108c2ecf20Sopenharmony_ci case SPEED_100: 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci default: 4138c2ecf20Sopenharmony_ci netdev_warn(dev, "Speed (%d) is not 10/100 ???\n", 4148c2ecf20Sopenharmony_ci phydev->speed); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci aup->old_speed = phydev->speed; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci status_change = 1; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (phydev->link && (aup->old_duplex != phydev->duplex)) { 4248c2ecf20Sopenharmony_ci /* duplex mode changed */ 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* switching duplex mode requires to disable rx and tx! */ 4278c2ecf20Sopenharmony_ci au1000_hard_stop(dev); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci reg = readl(&aup->mac->control); 4308c2ecf20Sopenharmony_ci if (DUPLEX_FULL == phydev->duplex) { 4318c2ecf20Sopenharmony_ci reg |= MAC_FULL_DUPLEX; 4328c2ecf20Sopenharmony_ci reg &= ~MAC_DISABLE_RX_OWN; 4338c2ecf20Sopenharmony_ci } else { 4348c2ecf20Sopenharmony_ci reg &= ~MAC_FULL_DUPLEX; 4358c2ecf20Sopenharmony_ci reg |= MAC_DISABLE_RX_OWN; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci writel(reg, &aup->mac->control); 4388c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 4398c2ecf20Sopenharmony_ci mdelay(1); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci au1000_enable_rx_tx(dev); 4428c2ecf20Sopenharmony_ci aup->old_duplex = phydev->duplex; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci status_change = 1; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (phydev->link != aup->old_link) { 4488c2ecf20Sopenharmony_ci /* link state changed */ 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!phydev->link) { 4518c2ecf20Sopenharmony_ci /* link went down */ 4528c2ecf20Sopenharmony_ci aup->old_speed = 0; 4538c2ecf20Sopenharmony_ci aup->old_duplex = -1; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci aup->old_link = phydev->link; 4578c2ecf20Sopenharmony_ci status_change = 1; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&aup->lock, flags); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (status_change) { 4638c2ecf20Sopenharmony_ci if (phydev->link) 4648c2ecf20Sopenharmony_ci netdev_info(dev, "link up (%d/%s)\n", 4658c2ecf20Sopenharmony_ci phydev->speed, 4668c2ecf20Sopenharmony_ci DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); 4678c2ecf20Sopenharmony_ci else 4688c2ecf20Sopenharmony_ci netdev_info(dev, "link down\n"); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int au1000_mii_probe(struct net_device *dev) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct au1000_private *const aup = netdev_priv(dev); 4758c2ecf20Sopenharmony_ci struct phy_device *phydev = NULL; 4768c2ecf20Sopenharmony_ci int phy_addr; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (aup->phy_static_config) { 4798c2ecf20Sopenharmony_ci BUG_ON(aup->mac_id < 0 || aup->mac_id > 1); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (aup->phy_addr) 4828c2ecf20Sopenharmony_ci phydev = mdiobus_get_phy(aup->mii_bus, aup->phy_addr); 4838c2ecf20Sopenharmony_ci else 4848c2ecf20Sopenharmony_ci netdev_info(dev, "using PHY-less setup\n"); 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* find the first (lowest address) PHY 4898c2ecf20Sopenharmony_ci * on the current MAC's MII bus 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ci for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) 4928c2ecf20Sopenharmony_ci if (mdiobus_get_phy(aup->mii_bus, phy_addr)) { 4938c2ecf20Sopenharmony_ci phydev = mdiobus_get_phy(aup->mii_bus, phy_addr); 4948c2ecf20Sopenharmony_ci if (!aup->phy_search_highest_addr) 4958c2ecf20Sopenharmony_ci /* break out with first one found */ 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (aup->phy1_search_mac0) { 5008c2ecf20Sopenharmony_ci /* try harder to find a PHY */ 5018c2ecf20Sopenharmony_ci if (!phydev && (aup->mac_id == 1)) { 5028c2ecf20Sopenharmony_ci /* no PHY found, maybe we have a dual PHY? */ 5038c2ecf20Sopenharmony_ci dev_info(&dev->dev, ": no PHY found on MAC1, " 5048c2ecf20Sopenharmony_ci "let's see if it's attached to MAC0...\n"); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* find the first (lowest address) non-attached 5078c2ecf20Sopenharmony_ci * PHY on the MAC0 MII bus 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ci for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { 5108c2ecf20Sopenharmony_ci struct phy_device *const tmp_phydev = 5118c2ecf20Sopenharmony_ci mdiobus_get_phy(aup->mii_bus, 5128c2ecf20Sopenharmony_ci phy_addr); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (aup->mac_id == 1) 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* no PHY here... */ 5188c2ecf20Sopenharmony_ci if (!tmp_phydev) 5198c2ecf20Sopenharmony_ci continue; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* already claimed by MAC0 */ 5228c2ecf20Sopenharmony_ci if (tmp_phydev->attached_dev) 5238c2ecf20Sopenharmony_ci continue; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci phydev = tmp_phydev; 5268c2ecf20Sopenharmony_ci break; /* found it */ 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (!phydev) { 5328c2ecf20Sopenharmony_ci netdev_err(dev, "no PHY found\n"); 5338c2ecf20Sopenharmony_ci return -1; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* now we are supposed to have a proper phydev, to attach to... */ 5378c2ecf20Sopenharmony_ci BUG_ON(phydev->attached_dev); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci phydev = phy_connect(dev, phydev_name(phydev), 5408c2ecf20Sopenharmony_ci &au1000_adjust_link, PHY_INTERFACE_MODE_MII); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (IS_ERR(phydev)) { 5438c2ecf20Sopenharmony_ci netdev_err(dev, "Could not attach to PHY\n"); 5448c2ecf20Sopenharmony_ci return PTR_ERR(phydev); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci phy_set_max_speed(phydev, SPEED_100); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci aup->old_link = 0; 5508c2ecf20Sopenharmony_ci aup->old_speed = 0; 5518c2ecf20Sopenharmony_ci aup->old_duplex = -1; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci phy_attached_info(phydev); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return 0; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci/* 5598c2ecf20Sopenharmony_ci * Buffer allocation/deallocation routines. The buffer descriptor returned 5608c2ecf20Sopenharmony_ci * has the virtual and dma address of a buffer suitable for 5618c2ecf20Sopenharmony_ci * both, receive and transmit operations. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_cistatic struct db_dest *au1000_GetFreeDB(struct au1000_private *aup) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci struct db_dest *pDB; 5668c2ecf20Sopenharmony_ci pDB = aup->pDBfree; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (pDB) 5698c2ecf20Sopenharmony_ci aup->pDBfree = pDB->pnext; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return pDB; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_civoid au1000_ReleaseDB(struct au1000_private *aup, struct db_dest *pDB) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct db_dest *pDBfree = aup->pDBfree; 5778c2ecf20Sopenharmony_ci if (pDBfree) 5788c2ecf20Sopenharmony_ci pDBfree->pnext = pDB; 5798c2ecf20Sopenharmony_ci aup->pDBfree = pDB; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void au1000_reset_mac_unlocked(struct net_device *dev) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct au1000_private *const aup = netdev_priv(dev); 5858c2ecf20Sopenharmony_ci int i; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci au1000_hard_stop(dev); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci writel(MAC_EN_CLOCK_ENABLE, aup->enable); 5908c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 5918c2ecf20Sopenharmony_ci mdelay(2); 5928c2ecf20Sopenharmony_ci writel(0, aup->enable); 5938c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 5948c2ecf20Sopenharmony_ci mdelay(2); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci aup->tx_full = 0; 5978c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DMA; i++) { 5988c2ecf20Sopenharmony_ci /* reset control bits */ 5998c2ecf20Sopenharmony_ci aup->rx_dma_ring[i]->buff_stat &= ~0xf; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TX_DMA; i++) { 6028c2ecf20Sopenharmony_ci /* reset control bits */ 6038c2ecf20Sopenharmony_ci aup->tx_dma_ring[i]->buff_stat &= ~0xf; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci aup->mac_enabled = 0; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic void au1000_reset_mac(struct net_device *dev) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct au1000_private *const aup = netdev_priv(dev); 6138c2ecf20Sopenharmony_ci unsigned long flags; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci netif_dbg(aup, hw, dev, "reset mac, aup %x\n", 6168c2ecf20Sopenharmony_ci (unsigned)aup); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci spin_lock_irqsave(&aup->lock, flags); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci au1000_reset_mac_unlocked(dev); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&aup->lock, flags); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci/* 6268c2ecf20Sopenharmony_ci * Setup the receive and transmit "rings". These pointers are the addresses 6278c2ecf20Sopenharmony_ci * of the rx and tx MAC DMA registers so they are fixed by the hardware -- 6288c2ecf20Sopenharmony_ci * these are not descriptors sitting in memory. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_cistatic void 6318c2ecf20Sopenharmony_ciau1000_setup_hw_rings(struct au1000_private *aup, void __iomem *tx_base) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci int i; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DMA; i++) { 6368c2ecf20Sopenharmony_ci aup->rx_dma_ring[i] = (struct rx_dma *) 6378c2ecf20Sopenharmony_ci (tx_base + 0x100 + sizeof(struct rx_dma) * i); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TX_DMA; i++) { 6408c2ecf20Sopenharmony_ci aup->tx_dma_ring[i] = (struct tx_dma *) 6418c2ecf20Sopenharmony_ci (tx_base + sizeof(struct tx_dma) * i); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci/* 6468c2ecf20Sopenharmony_ci * ethtool operations 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_cistatic void 6498c2ecf20Sopenharmony_ciau1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 6548c2ecf20Sopenharmony_ci snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME, 6558c2ecf20Sopenharmony_ci aup->mac_id); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic void au1000_set_msglevel(struct net_device *dev, u32 value) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 6618c2ecf20Sopenharmony_ci aup->msg_enable = value; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic u32 au1000_get_msglevel(struct net_device *dev) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 6678c2ecf20Sopenharmony_ci return aup->msg_enable; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic const struct ethtool_ops au1000_ethtool_ops = { 6718c2ecf20Sopenharmony_ci .get_drvinfo = au1000_get_drvinfo, 6728c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 6738c2ecf20Sopenharmony_ci .get_msglevel = au1000_get_msglevel, 6748c2ecf20Sopenharmony_ci .set_msglevel = au1000_set_msglevel, 6758c2ecf20Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 6768c2ecf20Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 6778c2ecf20Sopenharmony_ci}; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci/* 6808c2ecf20Sopenharmony_ci * Initialize the interface. 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * When the device powers up, the clocks are disabled and the 6838c2ecf20Sopenharmony_ci * mac is in reset state. When the interface is closed, we 6848c2ecf20Sopenharmony_ci * do the same -- reset the device and disable the clocks to 6858c2ecf20Sopenharmony_ci * conserve power. Thus, whenever au1000_init() is called, 6868c2ecf20Sopenharmony_ci * the device should already be in reset state. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_cistatic int au1000_init(struct net_device *dev) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 6918c2ecf20Sopenharmony_ci unsigned long flags; 6928c2ecf20Sopenharmony_ci int i; 6938c2ecf20Sopenharmony_ci u32 control; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci netif_dbg(aup, hw, dev, "au1000_init\n"); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* bring the device out of reset */ 6988c2ecf20Sopenharmony_ci au1000_enable_mac(dev, 1); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci spin_lock_irqsave(&aup->lock, flags); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci writel(0, &aup->mac->control); 7038c2ecf20Sopenharmony_ci aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2; 7048c2ecf20Sopenharmony_ci aup->tx_tail = aup->tx_head; 7058c2ecf20Sopenharmony_ci aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci writel(dev->dev_addr[5]<<8 | dev->dev_addr[4], 7088c2ecf20Sopenharmony_ci &aup->mac->mac_addr_high); 7098c2ecf20Sopenharmony_ci writel(dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 | 7108c2ecf20Sopenharmony_ci dev->dev_addr[1]<<8 | dev->dev_addr[0], 7118c2ecf20Sopenharmony_ci &aup->mac->mac_addr_low); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DMA; i++) 7158c2ecf20Sopenharmony_ci aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci control = MAC_RX_ENABLE | MAC_TX_ENABLE; 7208c2ecf20Sopenharmony_ci#ifndef CONFIG_CPU_LITTLE_ENDIAN 7218c2ecf20Sopenharmony_ci control |= MAC_BIG_ENDIAN; 7228c2ecf20Sopenharmony_ci#endif 7238c2ecf20Sopenharmony_ci if (dev->phydev) { 7248c2ecf20Sopenharmony_ci if (dev->phydev->link && (DUPLEX_FULL == dev->phydev->duplex)) 7258c2ecf20Sopenharmony_ci control |= MAC_FULL_DUPLEX; 7268c2ecf20Sopenharmony_ci else 7278c2ecf20Sopenharmony_ci control |= MAC_DISABLE_RX_OWN; 7288c2ecf20Sopenharmony_ci } else { /* PHY-less op, assume full-duplex */ 7298c2ecf20Sopenharmony_ci control |= MAC_FULL_DUPLEX; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci writel(control, &aup->mac->control); 7338c2ecf20Sopenharmony_ci writel(0x8100, &aup->mac->vlan1_tag); /* activate vlan support */ 7348c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&aup->lock, flags); 7378c2ecf20Sopenharmony_ci return 0; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic inline void au1000_update_rx_stats(struct net_device *dev, u32 status) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct net_device_stats *ps = &dev->stats; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci ps->rx_packets++; 7458c2ecf20Sopenharmony_ci if (status & RX_MCAST_FRAME) 7468c2ecf20Sopenharmony_ci ps->multicast++; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (status & RX_ERROR) { 7498c2ecf20Sopenharmony_ci ps->rx_errors++; 7508c2ecf20Sopenharmony_ci if (status & RX_MISSED_FRAME) 7518c2ecf20Sopenharmony_ci ps->rx_missed_errors++; 7528c2ecf20Sopenharmony_ci if (status & (RX_OVERLEN | RX_RUNT | RX_LEN_ERROR)) 7538c2ecf20Sopenharmony_ci ps->rx_length_errors++; 7548c2ecf20Sopenharmony_ci if (status & RX_CRC_ERROR) 7558c2ecf20Sopenharmony_ci ps->rx_crc_errors++; 7568c2ecf20Sopenharmony_ci if (status & RX_COLL) 7578c2ecf20Sopenharmony_ci ps->collisions++; 7588c2ecf20Sopenharmony_ci } else 7598c2ecf20Sopenharmony_ci ps->rx_bytes += status & RX_FRAME_LEN_MASK; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci/* 7648c2ecf20Sopenharmony_ci * Au1000 receive routine. 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_cistatic int au1000_rx(struct net_device *dev) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 7698c2ecf20Sopenharmony_ci struct sk_buff *skb; 7708c2ecf20Sopenharmony_ci struct rx_dma *prxd; 7718c2ecf20Sopenharmony_ci u32 buff_stat, status; 7728c2ecf20Sopenharmony_ci struct db_dest *pDB; 7738c2ecf20Sopenharmony_ci u32 frmlen; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci netif_dbg(aup, rx_status, dev, "au1000_rx head %d\n", aup->rx_head); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci prxd = aup->rx_dma_ring[aup->rx_head]; 7788c2ecf20Sopenharmony_ci buff_stat = prxd->buff_stat; 7798c2ecf20Sopenharmony_ci while (buff_stat & RX_T_DONE) { 7808c2ecf20Sopenharmony_ci status = prxd->status; 7818c2ecf20Sopenharmony_ci pDB = aup->rx_db_inuse[aup->rx_head]; 7828c2ecf20Sopenharmony_ci au1000_update_rx_stats(dev, status); 7838c2ecf20Sopenharmony_ci if (!(status & RX_ERROR)) { 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* good frame */ 7868c2ecf20Sopenharmony_ci frmlen = (status & RX_FRAME_LEN_MASK); 7878c2ecf20Sopenharmony_ci frmlen -= 4; /* Remove FCS */ 7888c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, frmlen + 2); 7898c2ecf20Sopenharmony_ci if (skb == NULL) { 7908c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 7918c2ecf20Sopenharmony_ci continue; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte IP header align */ 7948c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, 7958c2ecf20Sopenharmony_ci (unsigned char *)pDB->vaddr, frmlen); 7968c2ecf20Sopenharmony_ci skb_put(skb, frmlen); 7978c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 7988c2ecf20Sopenharmony_ci netif_rx(skb); /* pass the packet to upper layers */ 7998c2ecf20Sopenharmony_ci } else { 8008c2ecf20Sopenharmony_ci if (au1000_debug > 4) { 8018c2ecf20Sopenharmony_ci pr_err("rx_error(s):"); 8028c2ecf20Sopenharmony_ci if (status & RX_MISSED_FRAME) 8038c2ecf20Sopenharmony_ci pr_cont(" miss"); 8048c2ecf20Sopenharmony_ci if (status & RX_WDOG_TIMER) 8058c2ecf20Sopenharmony_ci pr_cont(" wdog"); 8068c2ecf20Sopenharmony_ci if (status & RX_RUNT) 8078c2ecf20Sopenharmony_ci pr_cont(" runt"); 8088c2ecf20Sopenharmony_ci if (status & RX_OVERLEN) 8098c2ecf20Sopenharmony_ci pr_cont(" overlen"); 8108c2ecf20Sopenharmony_ci if (status & RX_COLL) 8118c2ecf20Sopenharmony_ci pr_cont(" coll"); 8128c2ecf20Sopenharmony_ci if (status & RX_MII_ERROR) 8138c2ecf20Sopenharmony_ci pr_cont(" mii error"); 8148c2ecf20Sopenharmony_ci if (status & RX_CRC_ERROR) 8158c2ecf20Sopenharmony_ci pr_cont(" crc error"); 8168c2ecf20Sopenharmony_ci if (status & RX_LEN_ERROR) 8178c2ecf20Sopenharmony_ci pr_cont(" len error"); 8188c2ecf20Sopenharmony_ci if (status & RX_U_CNTRL_FRAME) 8198c2ecf20Sopenharmony_ci pr_cont(" u control frame"); 8208c2ecf20Sopenharmony_ci pr_cont("\n"); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE); 8248c2ecf20Sopenharmony_ci aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1); 8258c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci /* next descriptor */ 8288c2ecf20Sopenharmony_ci prxd = aup->rx_dma_ring[aup->rx_head]; 8298c2ecf20Sopenharmony_ci buff_stat = prxd->buff_stat; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic void au1000_update_tx_stats(struct net_device *dev, u32 status) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct net_device_stats *ps = &dev->stats; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (status & TX_FRAME_ABORTED) { 8398c2ecf20Sopenharmony_ci if (!dev->phydev || (DUPLEX_FULL == dev->phydev->duplex)) { 8408c2ecf20Sopenharmony_ci if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) { 8418c2ecf20Sopenharmony_ci /* any other tx errors are only valid 8428c2ecf20Sopenharmony_ci * in half duplex mode 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci ps->tx_errors++; 8458c2ecf20Sopenharmony_ci ps->tx_aborted_errors++; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci } else { 8488c2ecf20Sopenharmony_ci ps->tx_errors++; 8498c2ecf20Sopenharmony_ci ps->tx_aborted_errors++; 8508c2ecf20Sopenharmony_ci if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER)) 8518c2ecf20Sopenharmony_ci ps->tx_carrier_errors++; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/* 8578c2ecf20Sopenharmony_ci * Called from the interrupt service routine to acknowledge 8588c2ecf20Sopenharmony_ci * the TX DONE bits. This is a must if the irq is setup as 8598c2ecf20Sopenharmony_ci * edge triggered. 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_cistatic void au1000_tx_ack(struct net_device *dev) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 8648c2ecf20Sopenharmony_ci struct tx_dma *ptxd; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci ptxd = aup->tx_dma_ring[aup->tx_tail]; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci while (ptxd->buff_stat & TX_T_DONE) { 8698c2ecf20Sopenharmony_ci au1000_update_tx_stats(dev, ptxd->status); 8708c2ecf20Sopenharmony_ci ptxd->buff_stat &= ~TX_T_DONE; 8718c2ecf20Sopenharmony_ci ptxd->len = 0; 8728c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1); 8758c2ecf20Sopenharmony_ci ptxd = aup->tx_dma_ring[aup->tx_tail]; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (aup->tx_full) { 8788c2ecf20Sopenharmony_ci aup->tx_full = 0; 8798c2ecf20Sopenharmony_ci netif_wake_queue(dev); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci/* 8858c2ecf20Sopenharmony_ci * Au1000 interrupt service routine. 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_cistatic irqreturn_t au1000_interrupt(int irq, void *dev_id) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* Handle RX interrupts first to minimize chance of overrun */ 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci au1000_rx(dev); 8948c2ecf20Sopenharmony_ci au1000_tx_ack(dev); 8958c2ecf20Sopenharmony_ci return IRQ_RETVAL(1); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic int au1000_open(struct net_device *dev) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci int retval; 9018c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci netif_dbg(aup, drv, dev, "open: dev=%p\n", dev); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci retval = request_irq(dev->irq, au1000_interrupt, 0, 9068c2ecf20Sopenharmony_ci dev->name, dev); 9078c2ecf20Sopenharmony_ci if (retval) { 9088c2ecf20Sopenharmony_ci netdev_err(dev, "unable to get IRQ %d\n", dev->irq); 9098c2ecf20Sopenharmony_ci return retval; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci retval = au1000_init(dev); 9138c2ecf20Sopenharmony_ci if (retval) { 9148c2ecf20Sopenharmony_ci netdev_err(dev, "error in au1000_init\n"); 9158c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 9168c2ecf20Sopenharmony_ci return retval; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (dev->phydev) 9208c2ecf20Sopenharmony_ci phy_start(dev->phydev); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci netif_start_queue(dev); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci netif_dbg(aup, drv, dev, "open: Initialization done.\n"); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci return 0; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int au1000_close(struct net_device *dev) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci unsigned long flags; 9328c2ecf20Sopenharmony_ci struct au1000_private *const aup = netdev_priv(dev); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci netif_dbg(aup, drv, dev, "close: dev=%p\n", dev); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (dev->phydev) 9378c2ecf20Sopenharmony_ci phy_stop(dev->phydev); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci spin_lock_irqsave(&aup->lock, flags); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci au1000_reset_mac_unlocked(dev); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* stop the device */ 9448c2ecf20Sopenharmony_ci netif_stop_queue(dev); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* disable the interrupt */ 9478c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 9488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&aup->lock, flags); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci return 0; 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci/* 9548c2ecf20Sopenharmony_ci * Au1000 transmit routine. 9558c2ecf20Sopenharmony_ci */ 9568c2ecf20Sopenharmony_cistatic netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 9598c2ecf20Sopenharmony_ci struct net_device_stats *ps = &dev->stats; 9608c2ecf20Sopenharmony_ci struct tx_dma *ptxd; 9618c2ecf20Sopenharmony_ci u32 buff_stat; 9628c2ecf20Sopenharmony_ci struct db_dest *pDB; 9638c2ecf20Sopenharmony_ci int i; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci netif_dbg(aup, tx_queued, dev, "tx: aup %x len=%d, data=%p, head %d\n", 9668c2ecf20Sopenharmony_ci (unsigned)aup, skb->len, 9678c2ecf20Sopenharmony_ci skb->data, aup->tx_head); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci ptxd = aup->tx_dma_ring[aup->tx_head]; 9708c2ecf20Sopenharmony_ci buff_stat = ptxd->buff_stat; 9718c2ecf20Sopenharmony_ci if (buff_stat & TX_DMA_ENABLE) { 9728c2ecf20Sopenharmony_ci /* We've wrapped around and the transmitter is still busy */ 9738c2ecf20Sopenharmony_ci netif_stop_queue(dev); 9748c2ecf20Sopenharmony_ci aup->tx_full = 1; 9758c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 9768c2ecf20Sopenharmony_ci } else if (buff_stat & TX_T_DONE) { 9778c2ecf20Sopenharmony_ci au1000_update_tx_stats(dev, ptxd->status); 9788c2ecf20Sopenharmony_ci ptxd->len = 0; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (aup->tx_full) { 9828c2ecf20Sopenharmony_ci aup->tx_full = 0; 9838c2ecf20Sopenharmony_ci netif_wake_queue(dev); 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci pDB = aup->tx_db_inuse[aup->tx_head]; 9878c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len); 9888c2ecf20Sopenharmony_ci if (skb->len < ETH_ZLEN) { 9898c2ecf20Sopenharmony_ci for (i = skb->len; i < ETH_ZLEN; i++) 9908c2ecf20Sopenharmony_ci ((char *)pDB->vaddr)[i] = 0; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci ptxd->len = ETH_ZLEN; 9938c2ecf20Sopenharmony_ci } else 9948c2ecf20Sopenharmony_ci ptxd->len = skb->len; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci ps->tx_packets++; 9978c2ecf20Sopenharmony_ci ps->tx_bytes += ptxd->len; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE; 10008c2ecf20Sopenharmony_ci wmb(); /* drain writebuffer */ 10018c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 10028c2ecf20Sopenharmony_ci aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1); 10038c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci/* 10078c2ecf20Sopenharmony_ci * The Tx ring has been full longer than the watchdog timeout 10088c2ecf20Sopenharmony_ci * value. The transmitter must be hung? 10098c2ecf20Sopenharmony_ci */ 10108c2ecf20Sopenharmony_cistatic void au1000_tx_timeout(struct net_device *dev, unsigned int txqueue) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci netdev_err(dev, "au1000_tx_timeout: dev=%p\n", dev); 10138c2ecf20Sopenharmony_ci au1000_reset_mac(dev); 10148c2ecf20Sopenharmony_ci au1000_init(dev); 10158c2ecf20Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 10168c2ecf20Sopenharmony_ci netif_wake_queue(dev); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic void au1000_multicast_list(struct net_device *dev) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 10228c2ecf20Sopenharmony_ci u32 reg; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci netif_dbg(aup, drv, dev, "%s: flags=%x\n", __func__, dev->flags); 10258c2ecf20Sopenharmony_ci reg = readl(&aup->mac->control); 10268c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ 10278c2ecf20Sopenharmony_ci reg |= MAC_PROMISCUOUS; 10288c2ecf20Sopenharmony_ci } else if ((dev->flags & IFF_ALLMULTI) || 10298c2ecf20Sopenharmony_ci netdev_mc_count(dev) > MULTICAST_FILTER_LIMIT) { 10308c2ecf20Sopenharmony_ci reg |= MAC_PASS_ALL_MULTI; 10318c2ecf20Sopenharmony_ci reg &= ~MAC_PROMISCUOUS; 10328c2ecf20Sopenharmony_ci netdev_info(dev, "Pass all multicast\n"); 10338c2ecf20Sopenharmony_ci } else { 10348c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 10358c2ecf20Sopenharmony_ci u32 mc_filter[2]; /* Multicast hash filter */ 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci mc_filter[1] = mc_filter[0] = 0; 10388c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) 10398c2ecf20Sopenharmony_ci set_bit(ether_crc(ETH_ALEN, ha->addr)>>26, 10408c2ecf20Sopenharmony_ci (long *)mc_filter); 10418c2ecf20Sopenharmony_ci writel(mc_filter[1], &aup->mac->multi_hash_high); 10428c2ecf20Sopenharmony_ci writel(mc_filter[0], &aup->mac->multi_hash_low); 10438c2ecf20Sopenharmony_ci reg &= ~MAC_PROMISCUOUS; 10448c2ecf20Sopenharmony_ci reg |= MAC_HASH_MODE; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci writel(reg, &aup->mac->control); 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic const struct net_device_ops au1000_netdev_ops = { 10508c2ecf20Sopenharmony_ci .ndo_open = au1000_open, 10518c2ecf20Sopenharmony_ci .ndo_stop = au1000_close, 10528c2ecf20Sopenharmony_ci .ndo_start_xmit = au1000_tx, 10538c2ecf20Sopenharmony_ci .ndo_set_rx_mode = au1000_multicast_list, 10548c2ecf20Sopenharmony_ci .ndo_do_ioctl = phy_do_ioctl_running, 10558c2ecf20Sopenharmony_ci .ndo_tx_timeout = au1000_tx_timeout, 10568c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 10578c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 10588c2ecf20Sopenharmony_ci}; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic int au1000_probe(struct platform_device *pdev) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct au1000_private *aup = NULL; 10638c2ecf20Sopenharmony_ci struct au1000_eth_platform_data *pd; 10648c2ecf20Sopenharmony_ci struct net_device *dev = NULL; 10658c2ecf20Sopenharmony_ci struct db_dest *pDB, *pDBfree; 10668c2ecf20Sopenharmony_ci int irq, i, err = 0; 10678c2ecf20Sopenharmony_ci struct resource *base, *macen, *macdma; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci base = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10708c2ecf20Sopenharmony_ci if (!base) { 10718c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to retrieve base register\n"); 10728c2ecf20Sopenharmony_ci err = -ENODEV; 10738c2ecf20Sopenharmony_ci goto out; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci macen = platform_get_resource(pdev, IORESOURCE_MEM, 1); 10778c2ecf20Sopenharmony_ci if (!macen) { 10788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to retrieve MAC Enable register\n"); 10798c2ecf20Sopenharmony_ci err = -ENODEV; 10808c2ecf20Sopenharmony_ci goto out; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 10848c2ecf20Sopenharmony_ci if (irq < 0) { 10858c2ecf20Sopenharmony_ci err = -ENODEV; 10868c2ecf20Sopenharmony_ci goto out; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci macdma = platform_get_resource(pdev, IORESOURCE_MEM, 2); 10908c2ecf20Sopenharmony_ci if (!macdma) { 10918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to retrieve MACDMA registers\n"); 10928c2ecf20Sopenharmony_ci err = -ENODEV; 10938c2ecf20Sopenharmony_ci goto out; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (!request_mem_region(base->start, resource_size(base), 10978c2ecf20Sopenharmony_ci pdev->name)) { 10988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request memory region for base registers\n"); 10998c2ecf20Sopenharmony_ci err = -ENXIO; 11008c2ecf20Sopenharmony_ci goto out; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (!request_mem_region(macen->start, resource_size(macen), 11048c2ecf20Sopenharmony_ci pdev->name)) { 11058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request memory region for MAC enable register\n"); 11068c2ecf20Sopenharmony_ci err = -ENXIO; 11078c2ecf20Sopenharmony_ci goto err_request; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (!request_mem_region(macdma->start, resource_size(macdma), 11118c2ecf20Sopenharmony_ci pdev->name)) { 11128c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request MACDMA memory region\n"); 11138c2ecf20Sopenharmony_ci err = -ENXIO; 11148c2ecf20Sopenharmony_ci goto err_macdma; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct au1000_private)); 11188c2ecf20Sopenharmony_ci if (!dev) { 11198c2ecf20Sopenharmony_ci err = -ENOMEM; 11208c2ecf20Sopenharmony_ci goto err_alloc; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 11248c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 11258c2ecf20Sopenharmony_ci aup = netdev_priv(dev); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci spin_lock_init(&aup->lock); 11288c2ecf20Sopenharmony_ci aup->msg_enable = (au1000_debug < 4 ? 11298c2ecf20Sopenharmony_ci AU1000_DEF_MSG_ENABLE : au1000_debug); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* Allocate the data buffers 11328c2ecf20Sopenharmony_ci * Snooping works fine with eth on all au1xxx 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_ci aup->vaddr = (u32)dma_alloc_coherent(&pdev->dev, MAX_BUF_SIZE * 11358c2ecf20Sopenharmony_ci (NUM_TX_BUFFS + NUM_RX_BUFFS), 11368c2ecf20Sopenharmony_ci &aup->dma_addr, 0); 11378c2ecf20Sopenharmony_ci if (!aup->vaddr) { 11388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate data buffers\n"); 11398c2ecf20Sopenharmony_ci err = -ENOMEM; 11408c2ecf20Sopenharmony_ci goto err_vaddr; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* aup->mac is the base address of the MAC's registers */ 11448c2ecf20Sopenharmony_ci aup->mac = (struct mac_reg *) 11458c2ecf20Sopenharmony_ci ioremap(base->start, resource_size(base)); 11468c2ecf20Sopenharmony_ci if (!aup->mac) { 11478c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to ioremap MAC registers\n"); 11488c2ecf20Sopenharmony_ci err = -ENXIO; 11498c2ecf20Sopenharmony_ci goto err_remap1; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* Setup some variables for quick register address access */ 11538c2ecf20Sopenharmony_ci aup->enable = (u32 *)ioremap(macen->start, 11548c2ecf20Sopenharmony_ci resource_size(macen)); 11558c2ecf20Sopenharmony_ci if (!aup->enable) { 11568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to ioremap MAC enable register\n"); 11578c2ecf20Sopenharmony_ci err = -ENXIO; 11588c2ecf20Sopenharmony_ci goto err_remap2; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci aup->mac_id = pdev->id; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci aup->macdma = ioremap(macdma->start, resource_size(macdma)); 11638c2ecf20Sopenharmony_ci if (!aup->macdma) { 11648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to ioremap MACDMA registers\n"); 11658c2ecf20Sopenharmony_ci err = -ENXIO; 11668c2ecf20Sopenharmony_ci goto err_remap3; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci au1000_setup_hw_rings(aup, aup->macdma); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci writel(0, aup->enable); 11728c2ecf20Sopenharmony_ci aup->mac_enabled = 0; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci pd = dev_get_platdata(&pdev->dev); 11758c2ecf20Sopenharmony_ci if (!pd) { 11768c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "no platform_data passed," 11778c2ecf20Sopenharmony_ci " PHY search on MAC0\n"); 11788c2ecf20Sopenharmony_ci aup->phy1_search_mac0 = 1; 11798c2ecf20Sopenharmony_ci } else { 11808c2ecf20Sopenharmony_ci if (is_valid_ether_addr(pd->mac)) { 11818c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, pd->mac, ETH_ALEN); 11828c2ecf20Sopenharmony_ci } else { 11838c2ecf20Sopenharmony_ci /* Set a random MAC since no valid provided by platform_data. */ 11848c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci aup->phy_static_config = pd->phy_static_config; 11888c2ecf20Sopenharmony_ci aup->phy_search_highest_addr = pd->phy_search_highest_addr; 11898c2ecf20Sopenharmony_ci aup->phy1_search_mac0 = pd->phy1_search_mac0; 11908c2ecf20Sopenharmony_ci aup->phy_addr = pd->phy_addr; 11918c2ecf20Sopenharmony_ci aup->phy_busid = pd->phy_busid; 11928c2ecf20Sopenharmony_ci aup->phy_irq = pd->phy_irq; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (aup->phy_busid > 0) { 11968c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "MAC0-associated PHY attached 2nd MACs MII bus not supported yet\n"); 11978c2ecf20Sopenharmony_ci err = -ENODEV; 11988c2ecf20Sopenharmony_ci goto err_mdiobus_alloc; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci aup->mii_bus = mdiobus_alloc(); 12028c2ecf20Sopenharmony_ci if (aup->mii_bus == NULL) { 12038c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate mdiobus structure\n"); 12048c2ecf20Sopenharmony_ci err = -ENOMEM; 12058c2ecf20Sopenharmony_ci goto err_mdiobus_alloc; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci aup->mii_bus->priv = dev; 12098c2ecf20Sopenharmony_ci aup->mii_bus->read = au1000_mdiobus_read; 12108c2ecf20Sopenharmony_ci aup->mii_bus->write = au1000_mdiobus_write; 12118c2ecf20Sopenharmony_ci aup->mii_bus->reset = au1000_mdiobus_reset; 12128c2ecf20Sopenharmony_ci aup->mii_bus->name = "au1000_eth_mii"; 12138c2ecf20Sopenharmony_ci snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", 12148c2ecf20Sopenharmony_ci pdev->name, aup->mac_id); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci /* if known, set corresponding PHY IRQs */ 12178c2ecf20Sopenharmony_ci if (aup->phy_static_config) 12188c2ecf20Sopenharmony_ci if (aup->phy_irq && aup->phy_busid == aup->mac_id) 12198c2ecf20Sopenharmony_ci aup->mii_bus->irq[aup->phy_addr] = aup->phy_irq; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci err = mdiobus_register(aup->mii_bus); 12228c2ecf20Sopenharmony_ci if (err) { 12238c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register MDIO bus\n"); 12248c2ecf20Sopenharmony_ci goto err_mdiobus_reg; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci err = au1000_mii_probe(dev); 12288c2ecf20Sopenharmony_ci if (err != 0) 12298c2ecf20Sopenharmony_ci goto err_out; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci pDBfree = NULL; 12328c2ecf20Sopenharmony_ci /* setup the data buffer descriptors and attach a buffer to each one */ 12338c2ecf20Sopenharmony_ci pDB = aup->db; 12348c2ecf20Sopenharmony_ci for (i = 0; i < (NUM_TX_BUFFS+NUM_RX_BUFFS); i++) { 12358c2ecf20Sopenharmony_ci pDB->pnext = pDBfree; 12368c2ecf20Sopenharmony_ci pDBfree = pDB; 12378c2ecf20Sopenharmony_ci pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i); 12388c2ecf20Sopenharmony_ci pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); 12398c2ecf20Sopenharmony_ci pDB++; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci aup->pDBfree = pDBfree; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci err = -ENODEV; 12448c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DMA; i++) { 12458c2ecf20Sopenharmony_ci pDB = au1000_GetFreeDB(aup); 12468c2ecf20Sopenharmony_ci if (!pDB) 12478c2ecf20Sopenharmony_ci goto err_out; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; 12508c2ecf20Sopenharmony_ci aup->rx_db_inuse[i] = pDB; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TX_DMA; i++) { 12548c2ecf20Sopenharmony_ci pDB = au1000_GetFreeDB(aup); 12558c2ecf20Sopenharmony_ci if (!pDB) 12568c2ecf20Sopenharmony_ci goto err_out; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; 12598c2ecf20Sopenharmony_ci aup->tx_dma_ring[i]->len = 0; 12608c2ecf20Sopenharmony_ci aup->tx_db_inuse[i] = pDB; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci dev->base_addr = base->start; 12648c2ecf20Sopenharmony_ci dev->irq = irq; 12658c2ecf20Sopenharmony_ci dev->netdev_ops = &au1000_netdev_ops; 12668c2ecf20Sopenharmony_ci dev->ethtool_ops = &au1000_ethtool_ops; 12678c2ecf20Sopenharmony_ci dev->watchdog_timeo = ETH_TX_TIMEOUT; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci /* 12708c2ecf20Sopenharmony_ci * The boot code uses the ethernet controller, so reset it to start 12718c2ecf20Sopenharmony_ci * fresh. au1000_init() expects that the device is in reset state. 12728c2ecf20Sopenharmony_ci */ 12738c2ecf20Sopenharmony_ci au1000_reset_mac(dev); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci err = register_netdev(dev); 12768c2ecf20Sopenharmony_ci if (err) { 12778c2ecf20Sopenharmony_ci netdev_err(dev, "Cannot register net device, aborting.\n"); 12788c2ecf20Sopenharmony_ci goto err_out; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci netdev_info(dev, "Au1xx0 Ethernet found at 0x%lx, irq %d\n", 12828c2ecf20Sopenharmony_ci (unsigned long)base->start, irq); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return 0; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cierr_out: 12878c2ecf20Sopenharmony_ci if (aup->mii_bus != NULL) 12888c2ecf20Sopenharmony_ci mdiobus_unregister(aup->mii_bus); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* here we should have a valid dev plus aup-> register addresses 12918c2ecf20Sopenharmony_ci * so we can reset the mac properly. 12928c2ecf20Sopenharmony_ci */ 12938c2ecf20Sopenharmony_ci au1000_reset_mac(dev); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DMA; i++) { 12968c2ecf20Sopenharmony_ci if (aup->rx_db_inuse[i]) 12978c2ecf20Sopenharmony_ci au1000_ReleaseDB(aup, aup->rx_db_inuse[i]); 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TX_DMA; i++) { 13008c2ecf20Sopenharmony_ci if (aup->tx_db_inuse[i]) 13018c2ecf20Sopenharmony_ci au1000_ReleaseDB(aup, aup->tx_db_inuse[i]); 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_cierr_mdiobus_reg: 13048c2ecf20Sopenharmony_ci mdiobus_free(aup->mii_bus); 13058c2ecf20Sopenharmony_cierr_mdiobus_alloc: 13068c2ecf20Sopenharmony_ci iounmap(aup->macdma); 13078c2ecf20Sopenharmony_cierr_remap3: 13088c2ecf20Sopenharmony_ci iounmap(aup->enable); 13098c2ecf20Sopenharmony_cierr_remap2: 13108c2ecf20Sopenharmony_ci iounmap(aup->mac); 13118c2ecf20Sopenharmony_cierr_remap1: 13128c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS), 13138c2ecf20Sopenharmony_ci (void *)aup->vaddr, aup->dma_addr); 13148c2ecf20Sopenharmony_cierr_vaddr: 13158c2ecf20Sopenharmony_ci free_netdev(dev); 13168c2ecf20Sopenharmony_cierr_alloc: 13178c2ecf20Sopenharmony_ci release_mem_region(macdma->start, resource_size(macdma)); 13188c2ecf20Sopenharmony_cierr_macdma: 13198c2ecf20Sopenharmony_ci release_mem_region(macen->start, resource_size(macen)); 13208c2ecf20Sopenharmony_cierr_request: 13218c2ecf20Sopenharmony_ci release_mem_region(base->start, resource_size(base)); 13228c2ecf20Sopenharmony_ciout: 13238c2ecf20Sopenharmony_ci return err; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic int au1000_remove(struct platform_device *pdev) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 13298c2ecf20Sopenharmony_ci struct au1000_private *aup = netdev_priv(dev); 13308c2ecf20Sopenharmony_ci int i; 13318c2ecf20Sopenharmony_ci struct resource *base, *macen; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci unregister_netdev(dev); 13348c2ecf20Sopenharmony_ci mdiobus_unregister(aup->mii_bus); 13358c2ecf20Sopenharmony_ci mdiobus_free(aup->mii_bus); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DMA; i++) 13388c2ecf20Sopenharmony_ci if (aup->rx_db_inuse[i]) 13398c2ecf20Sopenharmony_ci au1000_ReleaseDB(aup, aup->rx_db_inuse[i]); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TX_DMA; i++) 13428c2ecf20Sopenharmony_ci if (aup->tx_db_inuse[i]) 13438c2ecf20Sopenharmony_ci au1000_ReleaseDB(aup, aup->tx_db_inuse[i]); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS), 13468c2ecf20Sopenharmony_ci (void *)aup->vaddr, aup->dma_addr); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci iounmap(aup->macdma); 13498c2ecf20Sopenharmony_ci iounmap(aup->mac); 13508c2ecf20Sopenharmony_ci iounmap(aup->enable); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci base = platform_get_resource(pdev, IORESOURCE_MEM, 2); 13538c2ecf20Sopenharmony_ci release_mem_region(base->start, resource_size(base)); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci base = platform_get_resource(pdev, IORESOURCE_MEM, 0); 13568c2ecf20Sopenharmony_ci release_mem_region(base->start, resource_size(base)); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci macen = platform_get_resource(pdev, IORESOURCE_MEM, 1); 13598c2ecf20Sopenharmony_ci release_mem_region(macen->start, resource_size(macen)); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci free_netdev(dev); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci return 0; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic struct platform_driver au1000_eth_driver = { 13678c2ecf20Sopenharmony_ci .probe = au1000_probe, 13688c2ecf20Sopenharmony_ci .remove = au1000_remove, 13698c2ecf20Sopenharmony_ci .driver = { 13708c2ecf20Sopenharmony_ci .name = "au1000-eth", 13718c2ecf20Sopenharmony_ci }, 13728c2ecf20Sopenharmony_ci}; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cimodule_platform_driver(au1000_eth_driver); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:au1000-eth"); 1377