18c2ecf20Sopenharmony_ci/* de2104x.c: A Linux PCI Ethernet driver for Intel/Digital 21040/1 chips. */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Copyright 2001,2003 Jeff Garzik <jgarzik@pobox.com> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright 1994, 1995 Digital Equipment Corporation. [de4x5.c] 68c2ecf20Sopenharmony_ci Written/copyright 1994-2001 by Donald Becker. [tulip.c] 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci This software may be used and distributed according to the terms of 98c2ecf20Sopenharmony_ci the GNU General Public License (GPL), incorporated herein by reference. 108c2ecf20Sopenharmony_ci Drivers based on or derived from this code fall under the GPL and must 118c2ecf20Sopenharmony_ci retain the authorship, copyright and license notice. This file is not 128c2ecf20Sopenharmony_ci a complete program and may only be used when the entire operating 138c2ecf20Sopenharmony_ci system is licensed under the GPL. 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci See the file COPYING in this distribution for more information. 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci TODO, in rough priority order: 188c2ecf20Sopenharmony_ci * Support forcing media type with a module parameter, 198c2ecf20Sopenharmony_ci like dl2k.c/sundance.c 208c2ecf20Sopenharmony_ci * Constants (module parms?) for Rx work limit 218c2ecf20Sopenharmony_ci * Complete reset on PciErr 228c2ecf20Sopenharmony_ci * Jumbo frames / dev->change_mtu 238c2ecf20Sopenharmony_ci * Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error 248c2ecf20Sopenharmony_ci * Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error 258c2ecf20Sopenharmony_ci * Implement Tx software interrupt mitigation via 268c2ecf20Sopenharmony_ci Tx descriptor bit 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define DRV_NAME "de2104x" 338c2ecf20Sopenharmony_ci#define DRV_RELDATE "Mar 17, 2004" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/module.h> 368c2ecf20Sopenharmony_ci#include <linux/kernel.h> 378c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 388c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 398c2ecf20Sopenharmony_ci#include <linux/init.h> 408c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 418c2ecf20Sopenharmony_ci#include <linux/pci.h> 428c2ecf20Sopenharmony_ci#include <linux/delay.h> 438c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 448c2ecf20Sopenharmony_ci#include <linux/compiler.h> 458c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 468c2ecf20Sopenharmony_ci#include <linux/crc32.h> 478c2ecf20Sopenharmony_ci#include <linux/slab.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <asm/io.h> 508c2ecf20Sopenharmony_ci#include <asm/irq.h> 518c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 528c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>"); 558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver"); 568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int debug = -1; 598c2ecf20Sopenharmony_cimodule_param (debug, int, 0); 608c2ecf20Sopenharmony_ciMODULE_PARM_DESC (debug, "de2104x bitmapped message enable number"); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ 638c2ecf20Sopenharmony_ci#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \ 648c2ecf20Sopenharmony_ci defined(CONFIG_SPARC) || defined(__ia64__) || \ 658c2ecf20Sopenharmony_ci defined(__sh__) || defined(__mips__) 668c2ecf20Sopenharmony_cistatic int rx_copybreak = 1518; 678c2ecf20Sopenharmony_ci#else 688c2ecf20Sopenharmony_cistatic int rx_copybreak = 100; 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_cimodule_param (rx_copybreak, int, 0); 718c2ecf20Sopenharmony_ciMODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied"); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define DE_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ 748c2ecf20Sopenharmony_ci NETIF_MSG_PROBE | \ 758c2ecf20Sopenharmony_ci NETIF_MSG_LINK | \ 768c2ecf20Sopenharmony_ci NETIF_MSG_IFDOWN | \ 778c2ecf20Sopenharmony_ci NETIF_MSG_IFUP | \ 788c2ecf20Sopenharmony_ci NETIF_MSG_RX_ERR | \ 798c2ecf20Sopenharmony_ci NETIF_MSG_TX_ERR) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Descriptor skip length in 32 bit longwords. */ 828c2ecf20Sopenharmony_ci#ifndef CONFIG_DE2104X_DSL 838c2ecf20Sopenharmony_ci#define DSL 0 848c2ecf20Sopenharmony_ci#else 858c2ecf20Sopenharmony_ci#define DSL CONFIG_DE2104X_DSL 868c2ecf20Sopenharmony_ci#endif 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define DE_RX_RING_SIZE 128 898c2ecf20Sopenharmony_ci#define DE_TX_RING_SIZE 64 908c2ecf20Sopenharmony_ci#define DE_RING_BYTES \ 918c2ecf20Sopenharmony_ci ((sizeof(struct de_desc) * DE_RX_RING_SIZE) + \ 928c2ecf20Sopenharmony_ci (sizeof(struct de_desc) * DE_TX_RING_SIZE)) 938c2ecf20Sopenharmony_ci#define NEXT_TX(N) (((N) + 1) & (DE_TX_RING_SIZE - 1)) 948c2ecf20Sopenharmony_ci#define NEXT_RX(N) (((N) + 1) & (DE_RX_RING_SIZE - 1)) 958c2ecf20Sopenharmony_ci#define TX_BUFFS_AVAIL(CP) \ 968c2ecf20Sopenharmony_ci (((CP)->tx_tail <= (CP)->tx_head) ? \ 978c2ecf20Sopenharmony_ci (CP)->tx_tail + (DE_TX_RING_SIZE - 1) - (CP)->tx_head : \ 988c2ecf20Sopenharmony_ci (CP)->tx_tail - (CP)->tx_head - 1) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ 1018c2ecf20Sopenharmony_ci#define RX_OFFSET 2 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define DE_SETUP_SKB ((struct sk_buff *) 1) 1048c2ecf20Sopenharmony_ci#define DE_DUMMY_SKB ((struct sk_buff *) 2) 1058c2ecf20Sopenharmony_ci#define DE_SETUP_FRAME_WORDS 96 1068c2ecf20Sopenharmony_ci#define DE_EEPROM_WORDS 256 1078c2ecf20Sopenharmony_ci#define DE_EEPROM_SIZE (DE_EEPROM_WORDS * sizeof(u16)) 1088c2ecf20Sopenharmony_ci#define DE_MAX_MEDIA 5 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#define DE_MEDIA_TP_AUTO 0 1118c2ecf20Sopenharmony_ci#define DE_MEDIA_BNC 1 1128c2ecf20Sopenharmony_ci#define DE_MEDIA_AUI 2 1138c2ecf20Sopenharmony_ci#define DE_MEDIA_TP 3 1148c2ecf20Sopenharmony_ci#define DE_MEDIA_TP_FD 4 1158c2ecf20Sopenharmony_ci#define DE_MEDIA_INVALID DE_MAX_MEDIA 1168c2ecf20Sopenharmony_ci#define DE_MEDIA_FIRST 0 1178c2ecf20Sopenharmony_ci#define DE_MEDIA_LAST (DE_MAX_MEDIA - 1) 1188c2ecf20Sopenharmony_ci#define DE_AUI_BNC (SUPPORTED_AUI | SUPPORTED_BNC) 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci#define DE_TIMER_LINK (60 * HZ) 1218c2ecf20Sopenharmony_ci#define DE_TIMER_NO_LINK (5 * HZ) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#define DE_NUM_REGS 16 1248c2ecf20Sopenharmony_ci#define DE_REGS_SIZE (DE_NUM_REGS * sizeof(u32)) 1258c2ecf20Sopenharmony_ci#define DE_REGS_VER 1 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */ 1288c2ecf20Sopenharmony_ci#define TX_TIMEOUT (6*HZ) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* This is a mysterious value that can be written to CSR11 in the 21040 (only) 1318c2ecf20Sopenharmony_ci to support a pre-NWay full-duplex signaling mechanism using short frames. 1328c2ecf20Sopenharmony_ci No one knows what it should be, but if left at its default value some 1338c2ecf20Sopenharmony_ci 10base2(!) packets trigger a full-duplex-request interrupt. */ 1348c2ecf20Sopenharmony_ci#define FULL_DUPLEX_MAGIC 0x6969 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cienum { 1378c2ecf20Sopenharmony_ci /* NIC registers */ 1388c2ecf20Sopenharmony_ci BusMode = 0x00, 1398c2ecf20Sopenharmony_ci TxPoll = 0x08, 1408c2ecf20Sopenharmony_ci RxPoll = 0x10, 1418c2ecf20Sopenharmony_ci RxRingAddr = 0x18, 1428c2ecf20Sopenharmony_ci TxRingAddr = 0x20, 1438c2ecf20Sopenharmony_ci MacStatus = 0x28, 1448c2ecf20Sopenharmony_ci MacMode = 0x30, 1458c2ecf20Sopenharmony_ci IntrMask = 0x38, 1468c2ecf20Sopenharmony_ci RxMissed = 0x40, 1478c2ecf20Sopenharmony_ci ROMCmd = 0x48, 1488c2ecf20Sopenharmony_ci CSR11 = 0x58, 1498c2ecf20Sopenharmony_ci SIAStatus = 0x60, 1508c2ecf20Sopenharmony_ci CSR13 = 0x68, 1518c2ecf20Sopenharmony_ci CSR14 = 0x70, 1528c2ecf20Sopenharmony_ci CSR15 = 0x78, 1538c2ecf20Sopenharmony_ci PCIPM = 0x40, 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* BusMode bits */ 1568c2ecf20Sopenharmony_ci CmdReset = (1 << 0), 1578c2ecf20Sopenharmony_ci CacheAlign16 = 0x00008000, 1588c2ecf20Sopenharmony_ci BurstLen4 = 0x00000400, 1598c2ecf20Sopenharmony_ci DescSkipLen = (DSL << 2), 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Rx/TxPoll bits */ 1628c2ecf20Sopenharmony_ci NormalTxPoll = (1 << 0), 1638c2ecf20Sopenharmony_ci NormalRxPoll = (1 << 0), 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Tx/Rx descriptor status bits */ 1668c2ecf20Sopenharmony_ci DescOwn = (1 << 31), 1678c2ecf20Sopenharmony_ci RxError = (1 << 15), 1688c2ecf20Sopenharmony_ci RxErrLong = (1 << 7), 1698c2ecf20Sopenharmony_ci RxErrCRC = (1 << 1), 1708c2ecf20Sopenharmony_ci RxErrFIFO = (1 << 0), 1718c2ecf20Sopenharmony_ci RxErrRunt = (1 << 11), 1728c2ecf20Sopenharmony_ci RxErrFrame = (1 << 14), 1738c2ecf20Sopenharmony_ci RingEnd = (1 << 25), 1748c2ecf20Sopenharmony_ci FirstFrag = (1 << 29), 1758c2ecf20Sopenharmony_ci LastFrag = (1 << 30), 1768c2ecf20Sopenharmony_ci TxError = (1 << 15), 1778c2ecf20Sopenharmony_ci TxFIFOUnder = (1 << 1), 1788c2ecf20Sopenharmony_ci TxLinkFail = (1 << 2) | (1 << 10) | (1 << 11), 1798c2ecf20Sopenharmony_ci TxMaxCol = (1 << 8), 1808c2ecf20Sopenharmony_ci TxOWC = (1 << 9), 1818c2ecf20Sopenharmony_ci TxJabber = (1 << 14), 1828c2ecf20Sopenharmony_ci SetupFrame = (1 << 27), 1838c2ecf20Sopenharmony_ci TxSwInt = (1 << 31), 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* MacStatus bits */ 1868c2ecf20Sopenharmony_ci IntrOK = (1 << 16), 1878c2ecf20Sopenharmony_ci IntrErr = (1 << 15), 1888c2ecf20Sopenharmony_ci RxIntr = (1 << 6), 1898c2ecf20Sopenharmony_ci RxEmpty = (1 << 7), 1908c2ecf20Sopenharmony_ci TxIntr = (1 << 0), 1918c2ecf20Sopenharmony_ci TxEmpty = (1 << 2), 1928c2ecf20Sopenharmony_ci PciErr = (1 << 13), 1938c2ecf20Sopenharmony_ci TxState = (1 << 22) | (1 << 21) | (1 << 20), 1948c2ecf20Sopenharmony_ci RxState = (1 << 19) | (1 << 18) | (1 << 17), 1958c2ecf20Sopenharmony_ci LinkFail = (1 << 12), 1968c2ecf20Sopenharmony_ci LinkPass = (1 << 4), 1978c2ecf20Sopenharmony_ci RxStopped = (1 << 8), 1988c2ecf20Sopenharmony_ci TxStopped = (1 << 1), 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* MacMode bits */ 2018c2ecf20Sopenharmony_ci TxEnable = (1 << 13), 2028c2ecf20Sopenharmony_ci RxEnable = (1 << 1), 2038c2ecf20Sopenharmony_ci RxTx = TxEnable | RxEnable, 2048c2ecf20Sopenharmony_ci FullDuplex = (1 << 9), 2058c2ecf20Sopenharmony_ci AcceptAllMulticast = (1 << 7), 2068c2ecf20Sopenharmony_ci AcceptAllPhys = (1 << 6), 2078c2ecf20Sopenharmony_ci BOCnt = (1 << 5), 2088c2ecf20Sopenharmony_ci MacModeClear = (1<<12) | (1<<11) | (1<<10) | (1<<8) | (1<<3) | 2098c2ecf20Sopenharmony_ci RxTx | BOCnt | AcceptAllPhys | AcceptAllMulticast, 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* ROMCmd bits */ 2128c2ecf20Sopenharmony_ci EE_SHIFT_CLK = 0x02, /* EEPROM shift clock. */ 2138c2ecf20Sopenharmony_ci EE_CS = 0x01, /* EEPROM chip select. */ 2148c2ecf20Sopenharmony_ci EE_DATA_WRITE = 0x04, /* Data from the Tulip to EEPROM. */ 2158c2ecf20Sopenharmony_ci EE_WRITE_0 = 0x01, 2168c2ecf20Sopenharmony_ci EE_WRITE_1 = 0x05, 2178c2ecf20Sopenharmony_ci EE_DATA_READ = 0x08, /* Data from the EEPROM chip. */ 2188c2ecf20Sopenharmony_ci EE_ENB = (0x4800 | EE_CS), 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* The EEPROM commands include the alway-set leading bit. */ 2218c2ecf20Sopenharmony_ci EE_READ_CMD = 6, 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* RxMissed bits */ 2248c2ecf20Sopenharmony_ci RxMissedOver = (1 << 16), 2258c2ecf20Sopenharmony_ci RxMissedMask = 0xffff, 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* SROM-related bits */ 2288c2ecf20Sopenharmony_ci SROMC0InfoLeaf = 27, 2298c2ecf20Sopenharmony_ci MediaBlockMask = 0x3f, 2308c2ecf20Sopenharmony_ci MediaCustomCSRs = (1 << 6), 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* PCIPM bits */ 2338c2ecf20Sopenharmony_ci PM_Sleep = (1 << 31), 2348c2ecf20Sopenharmony_ci PM_Snooze = (1 << 30), 2358c2ecf20Sopenharmony_ci PM_Mask = PM_Sleep | PM_Snooze, 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* SIAStatus bits */ 2388c2ecf20Sopenharmony_ci NWayState = (1 << 14) | (1 << 13) | (1 << 12), 2398c2ecf20Sopenharmony_ci NWayRestart = (1 << 12), 2408c2ecf20Sopenharmony_ci NonselPortActive = (1 << 9), 2418c2ecf20Sopenharmony_ci SelPortActive = (1 << 8), 2428c2ecf20Sopenharmony_ci LinkFailStatus = (1 << 2), 2438c2ecf20Sopenharmony_ci NetCxnErr = (1 << 1), 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic const u32 de_intr_mask = 2478c2ecf20Sopenharmony_ci IntrOK | IntrErr | RxIntr | RxEmpty | TxIntr | TxEmpty | 2488c2ecf20Sopenharmony_ci LinkPass | LinkFail | PciErr; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * Set the programmable burst length to 4 longwords for all: 2528c2ecf20Sopenharmony_ci * DMA errors result without these values. Cache align 16 long. 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic const u32 de_bus_mode = CacheAlign16 | BurstLen4 | DescSkipLen; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistruct de_srom_media_block { 2578c2ecf20Sopenharmony_ci u8 opts; 2588c2ecf20Sopenharmony_ci u16 csr13; 2598c2ecf20Sopenharmony_ci u16 csr14; 2608c2ecf20Sopenharmony_ci u16 csr15; 2618c2ecf20Sopenharmony_ci} __packed; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistruct de_srom_info_leaf { 2648c2ecf20Sopenharmony_ci u16 default_media; 2658c2ecf20Sopenharmony_ci u8 n_blocks; 2668c2ecf20Sopenharmony_ci u8 unused; 2678c2ecf20Sopenharmony_ci} __packed; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistruct de_desc { 2708c2ecf20Sopenharmony_ci __le32 opts1; 2718c2ecf20Sopenharmony_ci __le32 opts2; 2728c2ecf20Sopenharmony_ci __le32 addr1; 2738c2ecf20Sopenharmony_ci __le32 addr2; 2748c2ecf20Sopenharmony_ci#if DSL 2758c2ecf20Sopenharmony_ci __le32 skip[DSL]; 2768c2ecf20Sopenharmony_ci#endif 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistruct media_info { 2808c2ecf20Sopenharmony_ci u16 type; /* DE_MEDIA_xxx */ 2818c2ecf20Sopenharmony_ci u16 csr13; 2828c2ecf20Sopenharmony_ci u16 csr14; 2838c2ecf20Sopenharmony_ci u16 csr15; 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistruct ring_info { 2878c2ecf20Sopenharmony_ci struct sk_buff *skb; 2888c2ecf20Sopenharmony_ci dma_addr_t mapping; 2898c2ecf20Sopenharmony_ci}; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistruct de_private { 2928c2ecf20Sopenharmony_ci unsigned tx_head; 2938c2ecf20Sopenharmony_ci unsigned tx_tail; 2948c2ecf20Sopenharmony_ci unsigned rx_tail; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci void __iomem *regs; 2978c2ecf20Sopenharmony_ci struct net_device *dev; 2988c2ecf20Sopenharmony_ci spinlock_t lock; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci struct de_desc *rx_ring; 3018c2ecf20Sopenharmony_ci struct de_desc *tx_ring; 3028c2ecf20Sopenharmony_ci struct ring_info tx_skb[DE_TX_RING_SIZE]; 3038c2ecf20Sopenharmony_ci struct ring_info rx_skb[DE_RX_RING_SIZE]; 3048c2ecf20Sopenharmony_ci unsigned rx_buf_sz; 3058c2ecf20Sopenharmony_ci dma_addr_t ring_dma; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci u32 msg_enable; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci struct pci_dev *pdev; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci u16 setup_frame[DE_SETUP_FRAME_WORDS]; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci u32 media_type; 3148c2ecf20Sopenharmony_ci u32 media_supported; 3158c2ecf20Sopenharmony_ci u32 media_advertise; 3168c2ecf20Sopenharmony_ci struct media_info media[DE_MAX_MEDIA]; 3178c2ecf20Sopenharmony_ci struct timer_list media_timer; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci u8 *ee_data; 3208c2ecf20Sopenharmony_ci unsigned board_idx; 3218c2ecf20Sopenharmony_ci unsigned de21040 : 1; 3228c2ecf20Sopenharmony_ci unsigned media_lock : 1; 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void de_set_rx_mode (struct net_device *dev); 3278c2ecf20Sopenharmony_cistatic void de_tx (struct de_private *de); 3288c2ecf20Sopenharmony_cistatic void de_clean_rings (struct de_private *de); 3298c2ecf20Sopenharmony_cistatic void de_media_interrupt (struct de_private *de, u32 status); 3308c2ecf20Sopenharmony_cistatic void de21040_media_timer (struct timer_list *t); 3318c2ecf20Sopenharmony_cistatic void de21041_media_timer (struct timer_list *t); 3328c2ecf20Sopenharmony_cistatic unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic const struct pci_device_id de_pci_tbl[] = { 3368c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, 3378c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 3388c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, 3398c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, 3408c2ecf20Sopenharmony_ci { }, 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, de_pci_tbl); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic const char * const media_name[DE_MAX_MEDIA] = { 3458c2ecf20Sopenharmony_ci "10baseT auto", 3468c2ecf20Sopenharmony_ci "BNC", 3478c2ecf20Sopenharmony_ci "AUI", 3488c2ecf20Sopenharmony_ci "10baseT-HD", 3498c2ecf20Sopenharmony_ci "10baseT-FD" 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* 21040 transceiver register settings: 3538c2ecf20Sopenharmony_ci * TP AUTO(unused), BNC(unused), AUI, TP, TP FD*/ 3548c2ecf20Sopenharmony_cistatic u16 t21040_csr13[] = { 0, 0, 0x8F09, 0x8F01, 0x8F01, }; 3558c2ecf20Sopenharmony_cistatic u16 t21040_csr14[] = { 0, 0, 0x0705, 0xFFFF, 0xFFFD, }; 3568c2ecf20Sopenharmony_cistatic u16 t21040_csr15[] = { 0, 0, 0x0006, 0x0000, 0x0000, }; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/* 21041 transceiver register settings: TP AUTO, BNC, AUI, TP, TP FD*/ 3598c2ecf20Sopenharmony_cistatic u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; 3608c2ecf20Sopenharmony_cistatic u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; 3618c2ecf20Sopenharmony_ci/* If on-chip autonegotiation is broken, use half-duplex (FF3F) instead */ 3628c2ecf20Sopenharmony_cistatic u16 t21041_csr14_brk[] = { 0xFF3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; 3638c2ecf20Sopenharmony_cistatic u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci#define dr32(reg) ioread32(de->regs + (reg)) 3678c2ecf20Sopenharmony_ci#define dw32(reg, val) iowrite32((val), de->regs + (reg)) 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void de_rx_err_acct (struct de_private *de, unsigned rx_tail, 3718c2ecf20Sopenharmony_ci u32 status, u32 len) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci netif_dbg(de, rx_err, de->dev, 3748c2ecf20Sopenharmony_ci "rx err, slot %d status 0x%x len %d\n", 3758c2ecf20Sopenharmony_ci rx_tail, status, len); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if ((status & 0x38000300) != 0x0300) { 3788c2ecf20Sopenharmony_ci /* Ingore earlier buffers. */ 3798c2ecf20Sopenharmony_ci if ((status & 0xffff) != 0x7fff) { 3808c2ecf20Sopenharmony_ci netif_warn(de, rx_err, de->dev, 3818c2ecf20Sopenharmony_ci "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", 3828c2ecf20Sopenharmony_ci status); 3838c2ecf20Sopenharmony_ci de->dev->stats.rx_length_errors++; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } else if (status & RxError) { 3868c2ecf20Sopenharmony_ci /* There was a fatal error. */ 3878c2ecf20Sopenharmony_ci de->dev->stats.rx_errors++; /* end of a packet.*/ 3888c2ecf20Sopenharmony_ci if (status & 0x0890) de->dev->stats.rx_length_errors++; 3898c2ecf20Sopenharmony_ci if (status & RxErrCRC) de->dev->stats.rx_crc_errors++; 3908c2ecf20Sopenharmony_ci if (status & RxErrFIFO) de->dev->stats.rx_fifo_errors++; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void de_rx (struct de_private *de) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci unsigned rx_tail = de->rx_tail; 3978c2ecf20Sopenharmony_ci unsigned rx_work = DE_RX_RING_SIZE; 3988c2ecf20Sopenharmony_ci unsigned drop = 0; 3998c2ecf20Sopenharmony_ci int rc; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci while (--rx_work) { 4028c2ecf20Sopenharmony_ci u32 status, len; 4038c2ecf20Sopenharmony_ci dma_addr_t mapping; 4048c2ecf20Sopenharmony_ci struct sk_buff *skb, *copy_skb; 4058c2ecf20Sopenharmony_ci unsigned copying_skb, buflen; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci skb = de->rx_skb[rx_tail].skb; 4088c2ecf20Sopenharmony_ci BUG_ON(!skb); 4098c2ecf20Sopenharmony_ci rmb(); 4108c2ecf20Sopenharmony_ci status = le32_to_cpu(de->rx_ring[rx_tail].opts1); 4118c2ecf20Sopenharmony_ci if (status & DescOwn) 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* the length is actually a 15 bit value here according 4158c2ecf20Sopenharmony_ci * to Table 4-1 in the DE2104x spec so mask is 0x7fff 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci len = ((status >> 16) & 0x7fff) - 4; 4188c2ecf20Sopenharmony_ci mapping = de->rx_skb[rx_tail].mapping; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (unlikely(drop)) { 4218c2ecf20Sopenharmony_ci de->dev->stats.rx_dropped++; 4228c2ecf20Sopenharmony_ci goto rx_next; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (unlikely((status & 0x38008300) != 0x0300)) { 4268c2ecf20Sopenharmony_ci de_rx_err_acct(de, rx_tail, status, len); 4278c2ecf20Sopenharmony_ci goto rx_next; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci copying_skb = (len <= rx_copybreak); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci netif_dbg(de, rx_status, de->dev, 4338c2ecf20Sopenharmony_ci "rx slot %d status 0x%x len %d copying? %d\n", 4348c2ecf20Sopenharmony_ci rx_tail, status, len, copying_skb); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz; 4378c2ecf20Sopenharmony_ci copy_skb = netdev_alloc_skb(de->dev, buflen); 4388c2ecf20Sopenharmony_ci if (unlikely(!copy_skb)) { 4398c2ecf20Sopenharmony_ci de->dev->stats.rx_dropped++; 4408c2ecf20Sopenharmony_ci drop = 1; 4418c2ecf20Sopenharmony_ci rx_work = 100; 4428c2ecf20Sopenharmony_ci goto rx_next; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!copying_skb) { 4468c2ecf20Sopenharmony_ci dma_unmap_single(&de->pdev->dev, mapping, buflen, 4478c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4488c2ecf20Sopenharmony_ci skb_put(skb, len); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci mapping = 4518c2ecf20Sopenharmony_ci de->rx_skb[rx_tail].mapping = 4528c2ecf20Sopenharmony_ci dma_map_single(&de->pdev->dev, copy_skb->data, 4538c2ecf20Sopenharmony_ci buflen, DMA_FROM_DEVICE); 4548c2ecf20Sopenharmony_ci de->rx_skb[rx_tail].skb = copy_skb; 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&de->pdev->dev, mapping, len, 4578c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4588c2ecf20Sopenharmony_ci skb_reserve(copy_skb, RX_OFFSET); 4598c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, skb_put(copy_skb, len), 4608c2ecf20Sopenharmony_ci len); 4618c2ecf20Sopenharmony_ci dma_sync_single_for_device(&de->pdev->dev, mapping, 4628c2ecf20Sopenharmony_ci len, DMA_FROM_DEVICE); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* We'll reuse the original ring buffer. */ 4658c2ecf20Sopenharmony_ci skb = copy_skb; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans (skb, de->dev); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci de->dev->stats.rx_packets++; 4718c2ecf20Sopenharmony_ci de->dev->stats.rx_bytes += skb->len; 4728c2ecf20Sopenharmony_ci rc = netif_rx (skb); 4738c2ecf20Sopenharmony_ci if (rc == NET_RX_DROP) 4748c2ecf20Sopenharmony_ci drop = 1; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cirx_next: 4778c2ecf20Sopenharmony_ci if (rx_tail == (DE_RX_RING_SIZE - 1)) 4788c2ecf20Sopenharmony_ci de->rx_ring[rx_tail].opts2 = 4798c2ecf20Sopenharmony_ci cpu_to_le32(RingEnd | de->rx_buf_sz); 4808c2ecf20Sopenharmony_ci else 4818c2ecf20Sopenharmony_ci de->rx_ring[rx_tail].opts2 = cpu_to_le32(de->rx_buf_sz); 4828c2ecf20Sopenharmony_ci de->rx_ring[rx_tail].addr1 = cpu_to_le32(mapping); 4838c2ecf20Sopenharmony_ci wmb(); 4848c2ecf20Sopenharmony_ci de->rx_ring[rx_tail].opts1 = cpu_to_le32(DescOwn); 4858c2ecf20Sopenharmony_ci rx_tail = NEXT_RX(rx_tail); 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (!rx_work) 4898c2ecf20Sopenharmony_ci netdev_warn(de->dev, "rx work limit reached\n"); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci de->rx_tail = rx_tail; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic irqreturn_t de_interrupt (int irq, void *dev_instance) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct net_device *dev = dev_instance; 4978c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 4988c2ecf20Sopenharmony_ci u32 status; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci status = dr32(MacStatus); 5018c2ecf20Sopenharmony_ci if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF)) 5028c2ecf20Sopenharmony_ci return IRQ_NONE; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci netif_dbg(de, intr, dev, "intr, status %08x mode %08x desc %u/%u/%u\n", 5058c2ecf20Sopenharmony_ci status, dr32(MacMode), 5068c2ecf20Sopenharmony_ci de->rx_tail, de->tx_head, de->tx_tail); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci dw32(MacStatus, status); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (status & (RxIntr | RxEmpty)) { 5118c2ecf20Sopenharmony_ci de_rx(de); 5128c2ecf20Sopenharmony_ci if (status & RxEmpty) 5138c2ecf20Sopenharmony_ci dw32(RxPoll, NormalRxPoll); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci spin_lock(&de->lock); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (status & (TxIntr | TxEmpty)) 5198c2ecf20Sopenharmony_ci de_tx(de); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (status & (LinkPass | LinkFail)) 5228c2ecf20Sopenharmony_ci de_media_interrupt(de, status); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci spin_unlock(&de->lock); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (status & PciErr) { 5278c2ecf20Sopenharmony_ci u16 pci_status; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci pci_read_config_word(de->pdev, PCI_STATUS, &pci_status); 5308c2ecf20Sopenharmony_ci pci_write_config_word(de->pdev, PCI_STATUS, pci_status); 5318c2ecf20Sopenharmony_ci netdev_err(de->dev, 5328c2ecf20Sopenharmony_ci "PCI bus error, status=%08x, PCI status=%04x\n", 5338c2ecf20Sopenharmony_ci status, pci_status); 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic void de_tx (struct de_private *de) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci unsigned tx_head = de->tx_head; 5428c2ecf20Sopenharmony_ci unsigned tx_tail = de->tx_tail; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci while (tx_tail != tx_head) { 5458c2ecf20Sopenharmony_ci struct sk_buff *skb; 5468c2ecf20Sopenharmony_ci u32 status; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci rmb(); 5498c2ecf20Sopenharmony_ci status = le32_to_cpu(de->tx_ring[tx_tail].opts1); 5508c2ecf20Sopenharmony_ci if (status & DescOwn) 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci skb = de->tx_skb[tx_tail].skb; 5548c2ecf20Sopenharmony_ci BUG_ON(!skb); 5558c2ecf20Sopenharmony_ci if (unlikely(skb == DE_DUMMY_SKB)) 5568c2ecf20Sopenharmony_ci goto next; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (unlikely(skb == DE_SETUP_SKB)) { 5598c2ecf20Sopenharmony_ci dma_unmap_single(&de->pdev->dev, 5608c2ecf20Sopenharmony_ci de->tx_skb[tx_tail].mapping, 5618c2ecf20Sopenharmony_ci sizeof(de->setup_frame), 5628c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 5638c2ecf20Sopenharmony_ci goto next; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci dma_unmap_single(&de->pdev->dev, de->tx_skb[tx_tail].mapping, 5678c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (status & LastFrag) { 5708c2ecf20Sopenharmony_ci if (status & TxError) { 5718c2ecf20Sopenharmony_ci netif_dbg(de, tx_err, de->dev, 5728c2ecf20Sopenharmony_ci "tx err, status 0x%x\n", 5738c2ecf20Sopenharmony_ci status); 5748c2ecf20Sopenharmony_ci de->dev->stats.tx_errors++; 5758c2ecf20Sopenharmony_ci if (status & TxOWC) 5768c2ecf20Sopenharmony_ci de->dev->stats.tx_window_errors++; 5778c2ecf20Sopenharmony_ci if (status & TxMaxCol) 5788c2ecf20Sopenharmony_ci de->dev->stats.tx_aborted_errors++; 5798c2ecf20Sopenharmony_ci if (status & TxLinkFail) 5808c2ecf20Sopenharmony_ci de->dev->stats.tx_carrier_errors++; 5818c2ecf20Sopenharmony_ci if (status & TxFIFOUnder) 5828c2ecf20Sopenharmony_ci de->dev->stats.tx_fifo_errors++; 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci de->dev->stats.tx_packets++; 5858c2ecf20Sopenharmony_ci de->dev->stats.tx_bytes += skb->len; 5868c2ecf20Sopenharmony_ci netif_dbg(de, tx_done, de->dev, 5878c2ecf20Sopenharmony_ci "tx done, slot %d\n", tx_tail); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci dev_consume_skb_irq(skb); 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cinext: 5938c2ecf20Sopenharmony_ci de->tx_skb[tx_tail].skb = NULL; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci tx_tail = NEXT_TX(tx_tail); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci de->tx_tail = tx_tail; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (netif_queue_stopped(de->dev) && (TX_BUFFS_AVAIL(de) > (DE_TX_RING_SIZE / 4))) 6018c2ecf20Sopenharmony_ci netif_wake_queue(de->dev); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic netdev_tx_t de_start_xmit (struct sk_buff *skb, 6058c2ecf20Sopenharmony_ci struct net_device *dev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 6088c2ecf20Sopenharmony_ci unsigned int entry, tx_free; 6098c2ecf20Sopenharmony_ci u32 mapping, len, flags = FirstFrag | LastFrag; 6108c2ecf20Sopenharmony_ci struct de_desc *txd; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci spin_lock_irq(&de->lock); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci tx_free = TX_BUFFS_AVAIL(de); 6158c2ecf20Sopenharmony_ci if (tx_free == 0) { 6168c2ecf20Sopenharmony_ci netif_stop_queue(dev); 6178c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 6188c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci tx_free--; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci entry = de->tx_head; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci txd = &de->tx_ring[entry]; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci len = skb->len; 6278c2ecf20Sopenharmony_ci mapping = dma_map_single(&de->pdev->dev, skb->data, len, 6288c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6298c2ecf20Sopenharmony_ci if (entry == (DE_TX_RING_SIZE - 1)) 6308c2ecf20Sopenharmony_ci flags |= RingEnd; 6318c2ecf20Sopenharmony_ci if (!tx_free || (tx_free == (DE_TX_RING_SIZE / 2))) 6328c2ecf20Sopenharmony_ci flags |= TxSwInt; 6338c2ecf20Sopenharmony_ci flags |= len; 6348c2ecf20Sopenharmony_ci txd->opts2 = cpu_to_le32(flags); 6358c2ecf20Sopenharmony_ci txd->addr1 = cpu_to_le32(mapping); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci de->tx_skb[entry].skb = skb; 6388c2ecf20Sopenharmony_ci de->tx_skb[entry].mapping = mapping; 6398c2ecf20Sopenharmony_ci wmb(); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci txd->opts1 = cpu_to_le32(DescOwn); 6428c2ecf20Sopenharmony_ci wmb(); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci de->tx_head = NEXT_TX(entry); 6458c2ecf20Sopenharmony_ci netif_dbg(de, tx_queued, dev, "tx queued, slot %d, skblen %d\n", 6468c2ecf20Sopenharmony_ci entry, skb->len); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (tx_free == 0) 6498c2ecf20Sopenharmony_ci netif_stop_queue(dev); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Trigger an immediate transmit demand. */ 6548c2ecf20Sopenharmony_ci dw32(TxPoll, NormalTxPoll); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci/* Set or clear the multicast filter for this adaptor. 6608c2ecf20Sopenharmony_ci Note that we only use exclusion around actually queueing the 6618c2ecf20Sopenharmony_ci new frame, not around filling de->setup_frame. This is non-deterministic 6628c2ecf20Sopenharmony_ci when re-entered but still correct. */ 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 6678c2ecf20Sopenharmony_ci u16 hash_table[32]; 6688c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 6698c2ecf20Sopenharmony_ci int i; 6708c2ecf20Sopenharmony_ci u16 *eaddrs; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci memset(hash_table, 0, sizeof(hash_table)); 6738c2ecf20Sopenharmony_ci __set_bit_le(255, hash_table); /* Broadcast entry */ 6748c2ecf20Sopenharmony_ci /* This should work on big-endian machines as well. */ 6758c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 6768c2ecf20Sopenharmony_ci int index = ether_crc_le(ETH_ALEN, ha->addr) & 0x1ff; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci __set_bit_le(index, hash_table); 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 6828c2ecf20Sopenharmony_ci *setup_frm++ = hash_table[i]; 6838c2ecf20Sopenharmony_ci *setup_frm++ = hash_table[i]; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci setup_frm = &de->setup_frame[13*6]; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* Fill the final entry with our physical address. */ 6888c2ecf20Sopenharmony_ci eaddrs = (u16 *)dev->dev_addr; 6898c2ecf20Sopenharmony_ci *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; 6908c2ecf20Sopenharmony_ci *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; 6918c2ecf20Sopenharmony_ci *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 6978c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 6988c2ecf20Sopenharmony_ci u16 *eaddrs; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* We have <= 14 addresses so we can use the wonderful 7018c2ecf20Sopenharmony_ci 16 address perfect filtering of the Tulip. */ 7028c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 7038c2ecf20Sopenharmony_ci eaddrs = (u16 *) ha->addr; 7048c2ecf20Sopenharmony_ci *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; 7058c2ecf20Sopenharmony_ci *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; 7068c2ecf20Sopenharmony_ci *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci /* Fill the unused entries with the broadcast address. */ 7098c2ecf20Sopenharmony_ci memset(setup_frm, 0xff, (15 - netdev_mc_count(dev)) * 12); 7108c2ecf20Sopenharmony_ci setup_frm = &de->setup_frame[15*6]; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* Fill the final entry with our physical address. */ 7138c2ecf20Sopenharmony_ci eaddrs = (u16 *)dev->dev_addr; 7148c2ecf20Sopenharmony_ci *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; 7158c2ecf20Sopenharmony_ci *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; 7168c2ecf20Sopenharmony_ci *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic void __de_set_rx_mode (struct net_device *dev) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 7238c2ecf20Sopenharmony_ci u32 macmode; 7248c2ecf20Sopenharmony_ci unsigned int entry; 7258c2ecf20Sopenharmony_ci u32 mapping; 7268c2ecf20Sopenharmony_ci struct de_desc *txd; 7278c2ecf20Sopenharmony_ci struct de_desc *dummy_txd = NULL; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci macmode = dr32(MacMode) & ~(AcceptAllMulticast | AcceptAllPhys); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ 7328c2ecf20Sopenharmony_ci macmode |= AcceptAllMulticast | AcceptAllPhys; 7338c2ecf20Sopenharmony_ci goto out; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if ((netdev_mc_count(dev) > 1000) || (dev->flags & IFF_ALLMULTI)) { 7378c2ecf20Sopenharmony_ci /* Too many to filter well -- accept all multicasts. */ 7388c2ecf20Sopenharmony_ci macmode |= AcceptAllMulticast; 7398c2ecf20Sopenharmony_ci goto out; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Note that only the low-address shortword of setup_frame is valid! 7438c2ecf20Sopenharmony_ci The values are doubled for big-endian architectures. */ 7448c2ecf20Sopenharmony_ci if (netdev_mc_count(dev) > 14) /* Must use a multicast hash table. */ 7458c2ecf20Sopenharmony_ci build_setup_frame_hash (de->setup_frame, dev); 7468c2ecf20Sopenharmony_ci else 7478c2ecf20Sopenharmony_ci build_setup_frame_perfect (de->setup_frame, dev); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* 7508c2ecf20Sopenharmony_ci * Now add this frame to the Tx list. 7518c2ecf20Sopenharmony_ci */ 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci entry = de->tx_head; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Avoid a chip errata by prefixing a dummy entry. */ 7568c2ecf20Sopenharmony_ci if (entry != 0) { 7578c2ecf20Sopenharmony_ci de->tx_skb[entry].skb = DE_DUMMY_SKB; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci dummy_txd = &de->tx_ring[entry]; 7608c2ecf20Sopenharmony_ci dummy_txd->opts2 = (entry == (DE_TX_RING_SIZE - 1)) ? 7618c2ecf20Sopenharmony_ci cpu_to_le32(RingEnd) : 0; 7628c2ecf20Sopenharmony_ci dummy_txd->addr1 = 0; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Must set DescOwned later to avoid race with chip */ 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci entry = NEXT_TX(entry); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci de->tx_skb[entry].skb = DE_SETUP_SKB; 7708c2ecf20Sopenharmony_ci de->tx_skb[entry].mapping = mapping = 7718c2ecf20Sopenharmony_ci dma_map_single(&de->pdev->dev, de->setup_frame, 7728c2ecf20Sopenharmony_ci sizeof(de->setup_frame), DMA_TO_DEVICE); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Put the setup frame on the Tx list. */ 7758c2ecf20Sopenharmony_ci txd = &de->tx_ring[entry]; 7768c2ecf20Sopenharmony_ci if (entry == (DE_TX_RING_SIZE - 1)) 7778c2ecf20Sopenharmony_ci txd->opts2 = cpu_to_le32(SetupFrame | RingEnd | sizeof (de->setup_frame)); 7788c2ecf20Sopenharmony_ci else 7798c2ecf20Sopenharmony_ci txd->opts2 = cpu_to_le32(SetupFrame | sizeof (de->setup_frame)); 7808c2ecf20Sopenharmony_ci txd->addr1 = cpu_to_le32(mapping); 7818c2ecf20Sopenharmony_ci wmb(); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci txd->opts1 = cpu_to_le32(DescOwn); 7848c2ecf20Sopenharmony_ci wmb(); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (dummy_txd) { 7878c2ecf20Sopenharmony_ci dummy_txd->opts1 = cpu_to_le32(DescOwn); 7888c2ecf20Sopenharmony_ci wmb(); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci de->tx_head = NEXT_TX(entry); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (TX_BUFFS_AVAIL(de) == 0) 7948c2ecf20Sopenharmony_ci netif_stop_queue(dev); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* Trigger an immediate transmit demand. */ 7978c2ecf20Sopenharmony_ci dw32(TxPoll, NormalTxPoll); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ciout: 8008c2ecf20Sopenharmony_ci if (macmode != dr32(MacMode)) 8018c2ecf20Sopenharmony_ci dw32(MacMode, macmode); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic void de_set_rx_mode (struct net_device *dev) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci unsigned long flags; 8078c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci spin_lock_irqsave (&de->lock, flags); 8108c2ecf20Sopenharmony_ci __de_set_rx_mode(dev); 8118c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&de->lock, flags); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic inline void de_rx_missed(struct de_private *de, u32 rx_missed) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci if (unlikely(rx_missed & RxMissedOver)) 8178c2ecf20Sopenharmony_ci de->dev->stats.rx_missed_errors += RxMissedMask; 8188c2ecf20Sopenharmony_ci else 8198c2ecf20Sopenharmony_ci de->dev->stats.rx_missed_errors += (rx_missed & RxMissedMask); 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic void __de_get_stats(struct de_private *de) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci u32 tmp = dr32(RxMissed); /* self-clearing */ 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci de_rx_missed(de, tmp); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic struct net_device_stats *de_get_stats(struct net_device *dev) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* The chip only need report frame silently dropped. */ 8348c2ecf20Sopenharmony_ci spin_lock_irq(&de->lock); 8358c2ecf20Sopenharmony_ci if (netif_running(dev) && netif_device_present(dev)) 8368c2ecf20Sopenharmony_ci __de_get_stats(de); 8378c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return &dev->stats; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic inline int de_is_running (struct de_private *de) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci return (dr32(MacStatus) & (RxState | TxState)) ? 1 : 0; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void de_stop_rxtx (struct de_private *de) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci u32 macmode; 8508c2ecf20Sopenharmony_ci unsigned int i = 1300/100; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci macmode = dr32(MacMode); 8538c2ecf20Sopenharmony_ci if (macmode & RxTx) { 8548c2ecf20Sopenharmony_ci dw32(MacMode, macmode & ~RxTx); 8558c2ecf20Sopenharmony_ci dr32(MacMode); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* wait until in-flight frame completes. 8598c2ecf20Sopenharmony_ci * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin) 8608c2ecf20Sopenharmony_ci * Typically expect this loop to end in < 50 us on 100BT. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci while (--i) { 8638c2ecf20Sopenharmony_ci if (!de_is_running(de)) 8648c2ecf20Sopenharmony_ci return; 8658c2ecf20Sopenharmony_ci udelay(100); 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci netdev_warn(de->dev, "timeout expired, stopping DMA\n"); 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_cistatic inline void de_start_rxtx (struct de_private *de) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci u32 macmode; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci macmode = dr32(MacMode); 8768c2ecf20Sopenharmony_ci if ((macmode & RxTx) != RxTx) { 8778c2ecf20Sopenharmony_ci dw32(MacMode, macmode | RxTx); 8788c2ecf20Sopenharmony_ci dr32(MacMode); 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic void de_stop_hw (struct de_private *de) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci udelay(5); 8868c2ecf20Sopenharmony_ci dw32(IntrMask, 0); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci de_stop_rxtx(de); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci dw32(MacStatus, dr32(MacStatus)); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci udelay(10); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci de->rx_tail = 0; 8958c2ecf20Sopenharmony_ci de->tx_head = de->tx_tail = 0; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void de_link_up(struct de_private *de) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci if (!netif_carrier_ok(de->dev)) { 9018c2ecf20Sopenharmony_ci netif_carrier_on(de->dev); 9028c2ecf20Sopenharmony_ci netif_info(de, link, de->dev, "link up, media %s\n", 9038c2ecf20Sopenharmony_ci media_name[de->media_type]); 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic void de_link_down(struct de_private *de) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci if (netif_carrier_ok(de->dev)) { 9108c2ecf20Sopenharmony_ci netif_carrier_off(de->dev); 9118c2ecf20Sopenharmony_ci netif_info(de, link, de->dev, "link down\n"); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic void de_set_media (struct de_private *de) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci unsigned media = de->media_type; 9188c2ecf20Sopenharmony_ci u32 macmode = dr32(MacMode); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (de_is_running(de)) 9218c2ecf20Sopenharmony_ci netdev_warn(de->dev, "chip is running while changing media!\n"); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (de->de21040) 9248c2ecf20Sopenharmony_ci dw32(CSR11, FULL_DUPLEX_MAGIC); 9258c2ecf20Sopenharmony_ci dw32(CSR13, 0); /* Reset phy */ 9268c2ecf20Sopenharmony_ci dw32(CSR14, de->media[media].csr14); 9278c2ecf20Sopenharmony_ci dw32(CSR15, de->media[media].csr15); 9288c2ecf20Sopenharmony_ci dw32(CSR13, de->media[media].csr13); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* must delay 10ms before writing to other registers, 9318c2ecf20Sopenharmony_ci * especially CSR6 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_ci mdelay(10); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (media == DE_MEDIA_TP_FD) 9368c2ecf20Sopenharmony_ci macmode |= FullDuplex; 9378c2ecf20Sopenharmony_ci else 9388c2ecf20Sopenharmony_ci macmode &= ~FullDuplex; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci netif_info(de, link, de->dev, "set link %s\n", media_name[media]); 9418c2ecf20Sopenharmony_ci netif_info(de, hw, de->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n", 9428c2ecf20Sopenharmony_ci dr32(MacMode), dr32(SIAStatus), 9438c2ecf20Sopenharmony_ci dr32(CSR13), dr32(CSR14), dr32(CSR15)); 9448c2ecf20Sopenharmony_ci netif_info(de, hw, de->dev, "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", 9458c2ecf20Sopenharmony_ci macmode, de->media[media].csr13, 9468c2ecf20Sopenharmony_ci de->media[media].csr14, de->media[media].csr15); 9478c2ecf20Sopenharmony_ci if (macmode != dr32(MacMode)) 9488c2ecf20Sopenharmony_ci dw32(MacMode, macmode); 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic void de_next_media (struct de_private *de, const u32 *media, 9528c2ecf20Sopenharmony_ci unsigned int n_media) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci unsigned int i; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci for (i = 0; i < n_media; i++) { 9578c2ecf20Sopenharmony_ci if (de_ok_to_advertise(de, media[i])) { 9588c2ecf20Sopenharmony_ci de->media_type = media[i]; 9598c2ecf20Sopenharmony_ci return; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic void de21040_media_timer (struct timer_list *t) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct de_private *de = from_timer(de, t, media_timer); 9678c2ecf20Sopenharmony_ci struct net_device *dev = de->dev; 9688c2ecf20Sopenharmony_ci u32 status = dr32(SIAStatus); 9698c2ecf20Sopenharmony_ci unsigned int carrier; 9708c2ecf20Sopenharmony_ci unsigned long flags; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci carrier = (status & NetCxnErr) ? 0 : 1; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (carrier) { 9758c2ecf20Sopenharmony_ci if (de->media_type != DE_MEDIA_AUI && (status & LinkFailStatus)) 9768c2ecf20Sopenharmony_ci goto no_link_yet; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci de->media_timer.expires = jiffies + DE_TIMER_LINK; 9798c2ecf20Sopenharmony_ci add_timer(&de->media_timer); 9808c2ecf20Sopenharmony_ci if (!netif_carrier_ok(dev)) 9818c2ecf20Sopenharmony_ci de_link_up(de); 9828c2ecf20Sopenharmony_ci else 9838c2ecf20Sopenharmony_ci netif_info(de, timer, dev, "%s link ok, status %x\n", 9848c2ecf20Sopenharmony_ci media_name[de->media_type], status); 9858c2ecf20Sopenharmony_ci return; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci de_link_down(de); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (de->media_lock) 9918c2ecf20Sopenharmony_ci return; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (de->media_type == DE_MEDIA_AUI) { 9948c2ecf20Sopenharmony_ci static const u32 next_state = DE_MEDIA_TP; 9958c2ecf20Sopenharmony_ci de_next_media(de, &next_state, 1); 9968c2ecf20Sopenharmony_ci } else { 9978c2ecf20Sopenharmony_ci static const u32 next_state = DE_MEDIA_AUI; 9988c2ecf20Sopenharmony_ci de_next_media(de, &next_state, 1); 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci spin_lock_irqsave(&de->lock, flags); 10028c2ecf20Sopenharmony_ci de_stop_rxtx(de); 10038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&de->lock, flags); 10048c2ecf20Sopenharmony_ci de_set_media(de); 10058c2ecf20Sopenharmony_ci de_start_rxtx(de); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cino_link_yet: 10088c2ecf20Sopenharmony_ci de->media_timer.expires = jiffies + DE_TIMER_NO_LINK; 10098c2ecf20Sopenharmony_ci add_timer(&de->media_timer); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci netif_info(de, timer, dev, "no link, trying media %s, status %x\n", 10128c2ecf20Sopenharmony_ci media_name[de->media_type], status); 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci switch (new_media) { 10188c2ecf20Sopenharmony_ci case DE_MEDIA_TP_AUTO: 10198c2ecf20Sopenharmony_ci if (!(de->media_advertise & ADVERTISED_Autoneg)) 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci if (!(de->media_advertise & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full))) 10228c2ecf20Sopenharmony_ci return 0; 10238c2ecf20Sopenharmony_ci break; 10248c2ecf20Sopenharmony_ci case DE_MEDIA_BNC: 10258c2ecf20Sopenharmony_ci if (!(de->media_advertise & ADVERTISED_BNC)) 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci break; 10288c2ecf20Sopenharmony_ci case DE_MEDIA_AUI: 10298c2ecf20Sopenharmony_ci if (!(de->media_advertise & ADVERTISED_AUI)) 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci case DE_MEDIA_TP: 10338c2ecf20Sopenharmony_ci if (!(de->media_advertise & ADVERTISED_10baseT_Half)) 10348c2ecf20Sopenharmony_ci return 0; 10358c2ecf20Sopenharmony_ci break; 10368c2ecf20Sopenharmony_ci case DE_MEDIA_TP_FD: 10378c2ecf20Sopenharmony_ci if (!(de->media_advertise & ADVERTISED_10baseT_Full)) 10388c2ecf20Sopenharmony_ci return 0; 10398c2ecf20Sopenharmony_ci break; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return 1; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic void de21041_media_timer (struct timer_list *t) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct de_private *de = from_timer(de, t, media_timer); 10488c2ecf20Sopenharmony_ci struct net_device *dev = de->dev; 10498c2ecf20Sopenharmony_ci u32 status = dr32(SIAStatus); 10508c2ecf20Sopenharmony_ci unsigned int carrier; 10518c2ecf20Sopenharmony_ci unsigned long flags; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* clear port active bits */ 10548c2ecf20Sopenharmony_ci dw32(SIAStatus, NonselPortActive | SelPortActive); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci carrier = (status & NetCxnErr) ? 0 : 1; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (carrier) { 10598c2ecf20Sopenharmony_ci if ((de->media_type == DE_MEDIA_TP_AUTO || 10608c2ecf20Sopenharmony_ci de->media_type == DE_MEDIA_TP || 10618c2ecf20Sopenharmony_ci de->media_type == DE_MEDIA_TP_FD) && 10628c2ecf20Sopenharmony_ci (status & LinkFailStatus)) 10638c2ecf20Sopenharmony_ci goto no_link_yet; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci de->media_timer.expires = jiffies + DE_TIMER_LINK; 10668c2ecf20Sopenharmony_ci add_timer(&de->media_timer); 10678c2ecf20Sopenharmony_ci if (!netif_carrier_ok(dev)) 10688c2ecf20Sopenharmony_ci de_link_up(de); 10698c2ecf20Sopenharmony_ci else 10708c2ecf20Sopenharmony_ci netif_info(de, timer, dev, 10718c2ecf20Sopenharmony_ci "%s link ok, mode %x status %x\n", 10728c2ecf20Sopenharmony_ci media_name[de->media_type], 10738c2ecf20Sopenharmony_ci dr32(MacMode), status); 10748c2ecf20Sopenharmony_ci return; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci de_link_down(de); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* if media type locked, don't switch media */ 10808c2ecf20Sopenharmony_ci if (de->media_lock) 10818c2ecf20Sopenharmony_ci goto set_media; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* if activity detected, use that as hint for new media type */ 10848c2ecf20Sopenharmony_ci if (status & NonselPortActive) { 10858c2ecf20Sopenharmony_ci unsigned int have_media = 1; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* if AUI/BNC selected, then activity is on TP port */ 10888c2ecf20Sopenharmony_ci if (de->media_type == DE_MEDIA_AUI || 10898c2ecf20Sopenharmony_ci de->media_type == DE_MEDIA_BNC) { 10908c2ecf20Sopenharmony_ci if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO)) 10918c2ecf20Sopenharmony_ci de->media_type = DE_MEDIA_TP_AUTO; 10928c2ecf20Sopenharmony_ci else 10938c2ecf20Sopenharmony_ci have_media = 0; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* TP selected. If there is only TP and BNC, then it's BNC */ 10978c2ecf20Sopenharmony_ci else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) && 10988c2ecf20Sopenharmony_ci de_ok_to_advertise(de, DE_MEDIA_BNC)) 10998c2ecf20Sopenharmony_ci de->media_type = DE_MEDIA_BNC; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* TP selected. If there is only TP and AUI, then it's AUI */ 11028c2ecf20Sopenharmony_ci else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) && 11038c2ecf20Sopenharmony_ci de_ok_to_advertise(de, DE_MEDIA_AUI)) 11048c2ecf20Sopenharmony_ci de->media_type = DE_MEDIA_AUI; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* otherwise, ignore the hint */ 11078c2ecf20Sopenharmony_ci else 11088c2ecf20Sopenharmony_ci have_media = 0; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (have_media) 11118c2ecf20Sopenharmony_ci goto set_media; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* 11158c2ecf20Sopenharmony_ci * Absent or ambiguous activity hint, move to next advertised 11168c2ecf20Sopenharmony_ci * media state. If de->media_type is left unchanged, this 11178c2ecf20Sopenharmony_ci * simply resets the PHY and reloads the current media settings. 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_ci if (de->media_type == DE_MEDIA_AUI) { 11208c2ecf20Sopenharmony_ci static const u32 next_states[] = { 11218c2ecf20Sopenharmony_ci DE_MEDIA_BNC, DE_MEDIA_TP_AUTO 11228c2ecf20Sopenharmony_ci }; 11238c2ecf20Sopenharmony_ci de_next_media(de, next_states, ARRAY_SIZE(next_states)); 11248c2ecf20Sopenharmony_ci } else if (de->media_type == DE_MEDIA_BNC) { 11258c2ecf20Sopenharmony_ci static const u32 next_states[] = { 11268c2ecf20Sopenharmony_ci DE_MEDIA_TP_AUTO, DE_MEDIA_AUI 11278c2ecf20Sopenharmony_ci }; 11288c2ecf20Sopenharmony_ci de_next_media(de, next_states, ARRAY_SIZE(next_states)); 11298c2ecf20Sopenharmony_ci } else { 11308c2ecf20Sopenharmony_ci static const u32 next_states[] = { 11318c2ecf20Sopenharmony_ci DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO 11328c2ecf20Sopenharmony_ci }; 11338c2ecf20Sopenharmony_ci de_next_media(de, next_states, ARRAY_SIZE(next_states)); 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ciset_media: 11378c2ecf20Sopenharmony_ci spin_lock_irqsave(&de->lock, flags); 11388c2ecf20Sopenharmony_ci de_stop_rxtx(de); 11398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&de->lock, flags); 11408c2ecf20Sopenharmony_ci de_set_media(de); 11418c2ecf20Sopenharmony_ci de_start_rxtx(de); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cino_link_yet: 11448c2ecf20Sopenharmony_ci de->media_timer.expires = jiffies + DE_TIMER_NO_LINK; 11458c2ecf20Sopenharmony_ci add_timer(&de->media_timer); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci netif_info(de, timer, dev, "no link, trying media %s, status %x\n", 11488c2ecf20Sopenharmony_ci media_name[de->media_type], status); 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic void de_media_interrupt (struct de_private *de, u32 status) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci if (status & LinkPass) { 11548c2ecf20Sopenharmony_ci /* Ignore if current media is AUI or BNC and we can't use TP */ 11558c2ecf20Sopenharmony_ci if ((de->media_type == DE_MEDIA_AUI || 11568c2ecf20Sopenharmony_ci de->media_type == DE_MEDIA_BNC) && 11578c2ecf20Sopenharmony_ci (de->media_lock || 11588c2ecf20Sopenharmony_ci !de_ok_to_advertise(de, DE_MEDIA_TP_AUTO))) 11598c2ecf20Sopenharmony_ci return; 11608c2ecf20Sopenharmony_ci /* If current media is not TP, change it to TP */ 11618c2ecf20Sopenharmony_ci if ((de->media_type == DE_MEDIA_AUI || 11628c2ecf20Sopenharmony_ci de->media_type == DE_MEDIA_BNC)) { 11638c2ecf20Sopenharmony_ci de->media_type = DE_MEDIA_TP_AUTO; 11648c2ecf20Sopenharmony_ci de_stop_rxtx(de); 11658c2ecf20Sopenharmony_ci de_set_media(de); 11668c2ecf20Sopenharmony_ci de_start_rxtx(de); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci de_link_up(de); 11698c2ecf20Sopenharmony_ci mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK); 11708c2ecf20Sopenharmony_ci return; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci BUG_ON(!(status & LinkFail)); 11748c2ecf20Sopenharmony_ci /* Mark the link as down only if current media is TP */ 11758c2ecf20Sopenharmony_ci if (netif_carrier_ok(de->dev) && de->media_type != DE_MEDIA_AUI && 11768c2ecf20Sopenharmony_ci de->media_type != DE_MEDIA_BNC) { 11778c2ecf20Sopenharmony_ci de_link_down(de); 11788c2ecf20Sopenharmony_ci mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK); 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci} 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic int de_reset_mac (struct de_private *de) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci u32 status, tmp; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* 11878c2ecf20Sopenharmony_ci * Reset MAC. de4x5.c and tulip.c examined for "advice" 11888c2ecf20Sopenharmony_ci * in this area. 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (dr32(BusMode) == 0xffffffff) 11928c2ecf20Sopenharmony_ci return -EBUSY; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ 11958c2ecf20Sopenharmony_ci dw32 (BusMode, CmdReset); 11968c2ecf20Sopenharmony_ci mdelay (1); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci dw32 (BusMode, de_bus_mode); 11998c2ecf20Sopenharmony_ci mdelay (1); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci for (tmp = 0; tmp < 5; tmp++) { 12028c2ecf20Sopenharmony_ci dr32 (BusMode); 12038c2ecf20Sopenharmony_ci mdelay (1); 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci mdelay (1); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci status = dr32(MacStatus); 12098c2ecf20Sopenharmony_ci if (status & (RxState | TxState)) 12108c2ecf20Sopenharmony_ci return -EBUSY; 12118c2ecf20Sopenharmony_ci if (status == 0xffffffff) 12128c2ecf20Sopenharmony_ci return -ENODEV; 12138c2ecf20Sopenharmony_ci return 0; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic void de_adapter_wake (struct de_private *de) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci u32 pmctl; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (de->de21040) 12218c2ecf20Sopenharmony_ci return; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci pci_read_config_dword(de->pdev, PCIPM, &pmctl); 12248c2ecf20Sopenharmony_ci if (pmctl & PM_Mask) { 12258c2ecf20Sopenharmony_ci pmctl &= ~PM_Mask; 12268c2ecf20Sopenharmony_ci pci_write_config_dword(de->pdev, PCIPM, pmctl); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* de4x5.c delays, so we do too */ 12298c2ecf20Sopenharmony_ci msleep(10); 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic void de_adapter_sleep (struct de_private *de) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci u32 pmctl; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (de->de21040) 12388c2ecf20Sopenharmony_ci return; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci dw32(CSR13, 0); /* Reset phy */ 12418c2ecf20Sopenharmony_ci pci_read_config_dword(de->pdev, PCIPM, &pmctl); 12428c2ecf20Sopenharmony_ci pmctl |= PM_Sleep; 12438c2ecf20Sopenharmony_ci pci_write_config_dword(de->pdev, PCIPM, pmctl); 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_cistatic int de_init_hw (struct de_private *de) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci struct net_device *dev = de->dev; 12498c2ecf20Sopenharmony_ci u32 macmode; 12508c2ecf20Sopenharmony_ci int rc; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci de_adapter_wake(de); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci macmode = dr32(MacMode) & ~MacModeClear; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci rc = de_reset_mac(de); 12578c2ecf20Sopenharmony_ci if (rc) 12588c2ecf20Sopenharmony_ci return rc; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci de_set_media(de); /* reset phy */ 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci dw32(RxRingAddr, de->ring_dma); 12638c2ecf20Sopenharmony_ci dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE)); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci dw32(MacMode, RxTx | macmode); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci dr32(RxMissed); /* self-clearing */ 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci dw32(IntrMask, de_intr_mask); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci de_set_rx_mode(dev); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return 0; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cistatic int de_refill_rx (struct de_private *de) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci unsigned i; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci for (i = 0; i < DE_RX_RING_SIZE; i++) { 12818c2ecf20Sopenharmony_ci struct sk_buff *skb; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(de->dev, de->rx_buf_sz); 12848c2ecf20Sopenharmony_ci if (!skb) 12858c2ecf20Sopenharmony_ci goto err_out; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci de->rx_skb[i].mapping = dma_map_single(&de->pdev->dev, 12888c2ecf20Sopenharmony_ci skb->data, 12898c2ecf20Sopenharmony_ci de->rx_buf_sz, 12908c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 12918c2ecf20Sopenharmony_ci de->rx_skb[i].skb = skb; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci de->rx_ring[i].opts1 = cpu_to_le32(DescOwn); 12948c2ecf20Sopenharmony_ci if (i == (DE_RX_RING_SIZE - 1)) 12958c2ecf20Sopenharmony_ci de->rx_ring[i].opts2 = 12968c2ecf20Sopenharmony_ci cpu_to_le32(RingEnd | de->rx_buf_sz); 12978c2ecf20Sopenharmony_ci else 12988c2ecf20Sopenharmony_ci de->rx_ring[i].opts2 = cpu_to_le32(de->rx_buf_sz); 12998c2ecf20Sopenharmony_ci de->rx_ring[i].addr1 = cpu_to_le32(de->rx_skb[i].mapping); 13008c2ecf20Sopenharmony_ci de->rx_ring[i].addr2 = 0; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci return 0; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cierr_out: 13068c2ecf20Sopenharmony_ci de_clean_rings(de); 13078c2ecf20Sopenharmony_ci return -ENOMEM; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic int de_init_rings (struct de_private *de) 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE); 13138c2ecf20Sopenharmony_ci de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci de->rx_tail = 0; 13168c2ecf20Sopenharmony_ci de->tx_head = de->tx_tail = 0; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return de_refill_rx (de); 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic int de_alloc_rings (struct de_private *de) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci de->rx_ring = dma_alloc_coherent(&de->pdev->dev, DE_RING_BYTES, 13248c2ecf20Sopenharmony_ci &de->ring_dma, GFP_KERNEL); 13258c2ecf20Sopenharmony_ci if (!de->rx_ring) 13268c2ecf20Sopenharmony_ci return -ENOMEM; 13278c2ecf20Sopenharmony_ci de->tx_ring = &de->rx_ring[DE_RX_RING_SIZE]; 13288c2ecf20Sopenharmony_ci return de_init_rings(de); 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic void de_clean_rings (struct de_private *de) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci unsigned i; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci memset(de->rx_ring, 0, sizeof(struct de_desc) * DE_RX_RING_SIZE); 13368c2ecf20Sopenharmony_ci de->rx_ring[DE_RX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd); 13378c2ecf20Sopenharmony_ci wmb(); 13388c2ecf20Sopenharmony_ci memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE); 13398c2ecf20Sopenharmony_ci de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd); 13408c2ecf20Sopenharmony_ci wmb(); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci for (i = 0; i < DE_RX_RING_SIZE; i++) { 13438c2ecf20Sopenharmony_ci if (de->rx_skb[i].skb) { 13448c2ecf20Sopenharmony_ci dma_unmap_single(&de->pdev->dev, 13458c2ecf20Sopenharmony_ci de->rx_skb[i].mapping, de->rx_buf_sz, 13468c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 13478c2ecf20Sopenharmony_ci dev_kfree_skb(de->rx_skb[i].skb); 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci for (i = 0; i < DE_TX_RING_SIZE; i++) { 13528c2ecf20Sopenharmony_ci struct sk_buff *skb = de->tx_skb[i].skb; 13538c2ecf20Sopenharmony_ci if ((skb) && (skb != DE_DUMMY_SKB)) { 13548c2ecf20Sopenharmony_ci if (skb != DE_SETUP_SKB) { 13558c2ecf20Sopenharmony_ci de->dev->stats.tx_dropped++; 13568c2ecf20Sopenharmony_ci dma_unmap_single(&de->pdev->dev, 13578c2ecf20Sopenharmony_ci de->tx_skb[i].mapping, 13588c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 13598c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 13608c2ecf20Sopenharmony_ci } else { 13618c2ecf20Sopenharmony_ci dma_unmap_single(&de->pdev->dev, 13628c2ecf20Sopenharmony_ci de->tx_skb[i].mapping, 13638c2ecf20Sopenharmony_ci sizeof(de->setup_frame), 13648c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci memset(&de->rx_skb, 0, sizeof(struct ring_info) * DE_RX_RING_SIZE); 13708c2ecf20Sopenharmony_ci memset(&de->tx_skb, 0, sizeof(struct ring_info) * DE_TX_RING_SIZE); 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic void de_free_rings (struct de_private *de) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci de_clean_rings(de); 13768c2ecf20Sopenharmony_ci dma_free_coherent(&de->pdev->dev, DE_RING_BYTES, de->rx_ring, 13778c2ecf20Sopenharmony_ci de->ring_dma); 13788c2ecf20Sopenharmony_ci de->rx_ring = NULL; 13798c2ecf20Sopenharmony_ci de->tx_ring = NULL; 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic int de_open (struct net_device *dev) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 13858c2ecf20Sopenharmony_ci const int irq = de->pdev->irq; 13868c2ecf20Sopenharmony_ci int rc; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci netif_dbg(de, ifup, dev, "enabling interface\n"); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci rc = de_alloc_rings(de); 13938c2ecf20Sopenharmony_ci if (rc) { 13948c2ecf20Sopenharmony_ci netdev_err(dev, "ring allocation failure, err=%d\n", rc); 13958c2ecf20Sopenharmony_ci return rc; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci dw32(IntrMask, 0); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci rc = request_irq(irq, de_interrupt, IRQF_SHARED, dev->name, dev); 14018c2ecf20Sopenharmony_ci if (rc) { 14028c2ecf20Sopenharmony_ci netdev_err(dev, "IRQ %d request failure, err=%d\n", irq, rc); 14038c2ecf20Sopenharmony_ci goto err_out_free; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci rc = de_init_hw(de); 14078c2ecf20Sopenharmony_ci if (rc) { 14088c2ecf20Sopenharmony_ci netdev_err(dev, "h/w init failure, err=%d\n", rc); 14098c2ecf20Sopenharmony_ci goto err_out_free_irq; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci netif_start_queue(dev); 14138c2ecf20Sopenharmony_ci mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci return 0; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cierr_out_free_irq: 14188c2ecf20Sopenharmony_ci free_irq(irq, dev); 14198c2ecf20Sopenharmony_cierr_out_free: 14208c2ecf20Sopenharmony_ci de_free_rings(de); 14218c2ecf20Sopenharmony_ci return rc; 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_cistatic int de_close (struct net_device *dev) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 14278c2ecf20Sopenharmony_ci unsigned long flags; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci netif_dbg(de, ifdown, dev, "disabling interface\n"); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci del_timer_sync(&de->media_timer); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci spin_lock_irqsave(&de->lock, flags); 14348c2ecf20Sopenharmony_ci de_stop_hw(de); 14358c2ecf20Sopenharmony_ci netif_stop_queue(dev); 14368c2ecf20Sopenharmony_ci netif_carrier_off(dev); 14378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&de->lock, flags); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci free_irq(de->pdev->irq, dev); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci de_free_rings(de); 14428c2ecf20Sopenharmony_ci de_adapter_sleep(de); 14438c2ecf20Sopenharmony_ci return 0; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic void de_tx_timeout (struct net_device *dev, unsigned int txqueue) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 14498c2ecf20Sopenharmony_ci const int irq = de->pdev->irq; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci netdev_dbg(dev, "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", 14528c2ecf20Sopenharmony_ci dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), 14538c2ecf20Sopenharmony_ci de->rx_tail, de->tx_head, de->tx_tail); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci del_timer_sync(&de->media_timer); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci disable_irq(irq); 14588c2ecf20Sopenharmony_ci spin_lock_irq(&de->lock); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci de_stop_hw(de); 14618c2ecf20Sopenharmony_ci netif_stop_queue(dev); 14628c2ecf20Sopenharmony_ci netif_carrier_off(dev); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 14658c2ecf20Sopenharmony_ci enable_irq(irq); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci /* Update the error counts. */ 14688c2ecf20Sopenharmony_ci __de_get_stats(de); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci synchronize_irq(irq); 14718c2ecf20Sopenharmony_ci de_clean_rings(de); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci de_init_rings(de); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci de_init_hw(de); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci netif_wake_queue(dev); 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_cistatic void __de_get_regs(struct de_private *de, u8 *buf) 14818c2ecf20Sopenharmony_ci{ 14828c2ecf20Sopenharmony_ci int i; 14838c2ecf20Sopenharmony_ci u32 *rbuf = (u32 *)buf; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci /* read all CSRs */ 14868c2ecf20Sopenharmony_ci for (i = 0; i < DE_NUM_REGS; i++) 14878c2ecf20Sopenharmony_ci rbuf[i] = dr32(i * 8); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci /* handle self-clearing RxMissed counter, CSR8 */ 14908c2ecf20Sopenharmony_ci de_rx_missed(de, rbuf[8]); 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic void __de_get_link_ksettings(struct de_private *de, 14948c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 14978c2ecf20Sopenharmony_ci de->media_supported); 14988c2ecf20Sopenharmony_ci cmd->base.phy_address = 0; 14998c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 15008c2ecf20Sopenharmony_ci de->media_advertise); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci switch (de->media_type) { 15038c2ecf20Sopenharmony_ci case DE_MEDIA_AUI: 15048c2ecf20Sopenharmony_ci cmd->base.port = PORT_AUI; 15058c2ecf20Sopenharmony_ci break; 15068c2ecf20Sopenharmony_ci case DE_MEDIA_BNC: 15078c2ecf20Sopenharmony_ci cmd->base.port = PORT_BNC; 15088c2ecf20Sopenharmony_ci break; 15098c2ecf20Sopenharmony_ci default: 15108c2ecf20Sopenharmony_ci cmd->base.port = PORT_TP; 15118c2ecf20Sopenharmony_ci break; 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci cmd->base.speed = 10; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (dr32(MacMode) & FullDuplex) 15178c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 15188c2ecf20Sopenharmony_ci else 15198c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_HALF; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (de->media_lock) 15228c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 15238c2ecf20Sopenharmony_ci else 15248c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* ignore maxtxpkt, maxrxpkt for now */ 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic int __de_set_link_ksettings(struct de_private *de, 15308c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci u32 new_media; 15338c2ecf20Sopenharmony_ci unsigned int media_lock; 15348c2ecf20Sopenharmony_ci u8 duplex = cmd->base.duplex; 15358c2ecf20Sopenharmony_ci u8 port = cmd->base.port; 15368c2ecf20Sopenharmony_ci u8 autoneg = cmd->base.autoneg; 15378c2ecf20Sopenharmony_ci u32 advertising; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32(&advertising, 15408c2ecf20Sopenharmony_ci cmd->link_modes.advertising); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (cmd->base.speed != 10) 15438c2ecf20Sopenharmony_ci return -EINVAL; 15448c2ecf20Sopenharmony_ci if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL) 15458c2ecf20Sopenharmony_ci return -EINVAL; 15468c2ecf20Sopenharmony_ci if (port != PORT_TP && port != PORT_AUI && port != PORT_BNC) 15478c2ecf20Sopenharmony_ci return -EINVAL; 15488c2ecf20Sopenharmony_ci if (de->de21040 && port == PORT_BNC) 15498c2ecf20Sopenharmony_ci return -EINVAL; 15508c2ecf20Sopenharmony_ci if (autoneg != AUTONEG_DISABLE && autoneg != AUTONEG_ENABLE) 15518c2ecf20Sopenharmony_ci return -EINVAL; 15528c2ecf20Sopenharmony_ci if (advertising & ~de->media_supported) 15538c2ecf20Sopenharmony_ci return -EINVAL; 15548c2ecf20Sopenharmony_ci if (autoneg == AUTONEG_ENABLE && 15558c2ecf20Sopenharmony_ci (!(advertising & ADVERTISED_Autoneg))) 15568c2ecf20Sopenharmony_ci return -EINVAL; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci switch (port) { 15598c2ecf20Sopenharmony_ci case PORT_AUI: 15608c2ecf20Sopenharmony_ci new_media = DE_MEDIA_AUI; 15618c2ecf20Sopenharmony_ci if (!(advertising & ADVERTISED_AUI)) 15628c2ecf20Sopenharmony_ci return -EINVAL; 15638c2ecf20Sopenharmony_ci break; 15648c2ecf20Sopenharmony_ci case PORT_BNC: 15658c2ecf20Sopenharmony_ci new_media = DE_MEDIA_BNC; 15668c2ecf20Sopenharmony_ci if (!(advertising & ADVERTISED_BNC)) 15678c2ecf20Sopenharmony_ci return -EINVAL; 15688c2ecf20Sopenharmony_ci break; 15698c2ecf20Sopenharmony_ci default: 15708c2ecf20Sopenharmony_ci if (autoneg == AUTONEG_ENABLE) 15718c2ecf20Sopenharmony_ci new_media = DE_MEDIA_TP_AUTO; 15728c2ecf20Sopenharmony_ci else if (duplex == DUPLEX_FULL) 15738c2ecf20Sopenharmony_ci new_media = DE_MEDIA_TP_FD; 15748c2ecf20Sopenharmony_ci else 15758c2ecf20Sopenharmony_ci new_media = DE_MEDIA_TP; 15768c2ecf20Sopenharmony_ci if (!(advertising & ADVERTISED_TP)) 15778c2ecf20Sopenharmony_ci return -EINVAL; 15788c2ecf20Sopenharmony_ci if (!(advertising & (ADVERTISED_10baseT_Full | 15798c2ecf20Sopenharmony_ci ADVERTISED_10baseT_Half))) 15808c2ecf20Sopenharmony_ci return -EINVAL; 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci media_lock = (autoneg == AUTONEG_ENABLE) ? 0 : 1; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci if ((new_media == de->media_type) && 15878c2ecf20Sopenharmony_ci (media_lock == de->media_lock) && 15888c2ecf20Sopenharmony_ci (advertising == de->media_advertise)) 15898c2ecf20Sopenharmony_ci return 0; /* nothing to change */ 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci de_link_down(de); 15928c2ecf20Sopenharmony_ci mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK); 15938c2ecf20Sopenharmony_ci de_stop_rxtx(de); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci de->media_type = new_media; 15968c2ecf20Sopenharmony_ci de->media_lock = media_lock; 15978c2ecf20Sopenharmony_ci de->media_advertise = advertising; 15988c2ecf20Sopenharmony_ci de_set_media(de); 15998c2ecf20Sopenharmony_ci if (netif_running(de->dev)) 16008c2ecf20Sopenharmony_ci de_start_rxtx(de); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci return 0; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info) 16068c2ecf20Sopenharmony_ci{ 16078c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 16108c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(de->pdev), sizeof(info->bus_info)); 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_cistatic int de_get_regs_len(struct net_device *dev) 16148c2ecf20Sopenharmony_ci{ 16158c2ecf20Sopenharmony_ci return DE_REGS_SIZE; 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_cistatic int de_get_link_ksettings(struct net_device *dev, 16198c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 16208c2ecf20Sopenharmony_ci{ 16218c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci spin_lock_irq(&de->lock); 16248c2ecf20Sopenharmony_ci __de_get_link_ksettings(de, cmd); 16258c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci return 0; 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cistatic int de_set_link_ksettings(struct net_device *dev, 16318c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 16328c2ecf20Sopenharmony_ci{ 16338c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16348c2ecf20Sopenharmony_ci int rc; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci spin_lock_irq(&de->lock); 16378c2ecf20Sopenharmony_ci rc = __de_set_link_ksettings(de, cmd); 16388c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci return rc; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic u32 de_get_msglevel(struct net_device *dev) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci return de->msg_enable; 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic void de_set_msglevel(struct net_device *dev, u32 msglvl) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci de->msg_enable = msglvl; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic int de_get_eeprom(struct net_device *dev, 16588c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (!de->ee_data) 16638c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16648c2ecf20Sopenharmony_ci if ((eeprom->offset != 0) || (eeprom->magic != 0) || 16658c2ecf20Sopenharmony_ci (eeprom->len != DE_EEPROM_SIZE)) 16668c2ecf20Sopenharmony_ci return -EINVAL; 16678c2ecf20Sopenharmony_ci memcpy(data, de->ee_data, eeprom->len); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci return 0; 16708c2ecf20Sopenharmony_ci} 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_cistatic int de_nway_reset(struct net_device *dev) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16758c2ecf20Sopenharmony_ci u32 status; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (de->media_type != DE_MEDIA_TP_AUTO) 16788c2ecf20Sopenharmony_ci return -EINVAL; 16798c2ecf20Sopenharmony_ci if (netif_carrier_ok(de->dev)) 16808c2ecf20Sopenharmony_ci de_link_down(de); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci status = dr32(SIAStatus); 16838c2ecf20Sopenharmony_ci dw32(SIAStatus, (status & ~NWayState) | NWayRestart); 16848c2ecf20Sopenharmony_ci netif_info(de, link, dev, "link nway restart, status %x,%x\n", 16858c2ecf20Sopenharmony_ci status, dr32(SIAStatus)); 16868c2ecf20Sopenharmony_ci return 0; 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_cistatic void de_get_regs(struct net_device *dev, struct ethtool_regs *regs, 16908c2ecf20Sopenharmony_ci void *data) 16918c2ecf20Sopenharmony_ci{ 16928c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci regs->version = (DE_REGS_VER << 2) | de->de21040; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci spin_lock_irq(&de->lock); 16978c2ecf20Sopenharmony_ci __de_get_regs(de, data); 16988c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_cistatic const struct ethtool_ops de_ethtool_ops = { 17028c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 17038c2ecf20Sopenharmony_ci .get_drvinfo = de_get_drvinfo, 17048c2ecf20Sopenharmony_ci .get_regs_len = de_get_regs_len, 17058c2ecf20Sopenharmony_ci .get_msglevel = de_get_msglevel, 17068c2ecf20Sopenharmony_ci .set_msglevel = de_set_msglevel, 17078c2ecf20Sopenharmony_ci .get_eeprom = de_get_eeprom, 17088c2ecf20Sopenharmony_ci .nway_reset = de_nway_reset, 17098c2ecf20Sopenharmony_ci .get_regs = de_get_regs, 17108c2ecf20Sopenharmony_ci .get_link_ksettings = de_get_link_ksettings, 17118c2ecf20Sopenharmony_ci .set_link_ksettings = de_set_link_ksettings, 17128c2ecf20Sopenharmony_ci}; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_cistatic void de21040_get_mac_address(struct de_private *de) 17158c2ecf20Sopenharmony_ci{ 17168c2ecf20Sopenharmony_ci unsigned i; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci dw32 (ROMCmd, 0); /* Reset the pointer with a dummy write. */ 17198c2ecf20Sopenharmony_ci udelay(5); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 17228c2ecf20Sopenharmony_ci int value, boguscnt = 100000; 17238c2ecf20Sopenharmony_ci do { 17248c2ecf20Sopenharmony_ci value = dr32(ROMCmd); 17258c2ecf20Sopenharmony_ci rmb(); 17268c2ecf20Sopenharmony_ci } while (value < 0 && --boguscnt > 0); 17278c2ecf20Sopenharmony_ci de->dev->dev_addr[i] = value; 17288c2ecf20Sopenharmony_ci udelay(1); 17298c2ecf20Sopenharmony_ci if (boguscnt <= 0) 17308c2ecf20Sopenharmony_ci pr_warn("timeout reading 21040 MAC address byte %u\n", 17318c2ecf20Sopenharmony_ci i); 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci} 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_cistatic void de21040_get_media_info(struct de_private *de) 17368c2ecf20Sopenharmony_ci{ 17378c2ecf20Sopenharmony_ci unsigned int i; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci de->media_type = DE_MEDIA_TP; 17408c2ecf20Sopenharmony_ci de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full | 17418c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Half | SUPPORTED_AUI; 17428c2ecf20Sopenharmony_ci de->media_advertise = de->media_supported; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci for (i = 0; i < DE_MAX_MEDIA; i++) { 17458c2ecf20Sopenharmony_ci switch (i) { 17468c2ecf20Sopenharmony_ci case DE_MEDIA_AUI: 17478c2ecf20Sopenharmony_ci case DE_MEDIA_TP: 17488c2ecf20Sopenharmony_ci case DE_MEDIA_TP_FD: 17498c2ecf20Sopenharmony_ci de->media[i].type = i; 17508c2ecf20Sopenharmony_ci de->media[i].csr13 = t21040_csr13[i]; 17518c2ecf20Sopenharmony_ci de->media[i].csr14 = t21040_csr14[i]; 17528c2ecf20Sopenharmony_ci de->media[i].csr15 = t21040_csr15[i]; 17538c2ecf20Sopenharmony_ci break; 17548c2ecf20Sopenharmony_ci default: 17558c2ecf20Sopenharmony_ci de->media[i].type = DE_MEDIA_INVALID; 17568c2ecf20Sopenharmony_ci break; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci/* Note: this routine returns extra data bits for size detection. */ 17628c2ecf20Sopenharmony_cistatic unsigned tulip_read_eeprom(void __iomem *regs, int location, 17638c2ecf20Sopenharmony_ci int addr_len) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci int i; 17668c2ecf20Sopenharmony_ci unsigned retval = 0; 17678c2ecf20Sopenharmony_ci void __iomem *ee_addr = regs + ROMCmd; 17688c2ecf20Sopenharmony_ci int read_cmd = location | (EE_READ_CMD << addr_len); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci writel(EE_ENB & ~EE_CS, ee_addr); 17718c2ecf20Sopenharmony_ci writel(EE_ENB, ee_addr); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci /* Shift the read command bits out. */ 17748c2ecf20Sopenharmony_ci for (i = 4 + addr_len; i >= 0; i--) { 17758c2ecf20Sopenharmony_ci short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; 17768c2ecf20Sopenharmony_ci writel(EE_ENB | dataval, ee_addr); 17778c2ecf20Sopenharmony_ci readl(ee_addr); 17788c2ecf20Sopenharmony_ci writel(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); 17798c2ecf20Sopenharmony_ci readl(ee_addr); 17808c2ecf20Sopenharmony_ci retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0); 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci writel(EE_ENB, ee_addr); 17838c2ecf20Sopenharmony_ci readl(ee_addr); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci for (i = 16; i > 0; i--) { 17868c2ecf20Sopenharmony_ci writel(EE_ENB | EE_SHIFT_CLK, ee_addr); 17878c2ecf20Sopenharmony_ci readl(ee_addr); 17888c2ecf20Sopenharmony_ci retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0); 17898c2ecf20Sopenharmony_ci writel(EE_ENB, ee_addr); 17908c2ecf20Sopenharmony_ci readl(ee_addr); 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci /* Terminate the EEPROM access. */ 17948c2ecf20Sopenharmony_ci writel(EE_ENB & ~EE_CS, ee_addr); 17958c2ecf20Sopenharmony_ci return retval; 17968c2ecf20Sopenharmony_ci} 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_cistatic void de21041_get_srom_info(struct de_private *de) 17998c2ecf20Sopenharmony_ci{ 18008c2ecf20Sopenharmony_ci unsigned i, sa_offset = 0, ofs; 18018c2ecf20Sopenharmony_ci u8 ee_data[DE_EEPROM_SIZE + 6] = {}; 18028c2ecf20Sopenharmony_ci unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6; 18038c2ecf20Sopenharmony_ci struct de_srom_info_leaf *il; 18048c2ecf20Sopenharmony_ci void *bufp; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci /* download entire eeprom */ 18078c2ecf20Sopenharmony_ci for (i = 0; i < DE_EEPROM_WORDS; i++) 18088c2ecf20Sopenharmony_ci ((__le16 *)ee_data)[i] = 18098c2ecf20Sopenharmony_ci cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size)); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* DEC now has a specification but early board makers 18128c2ecf20Sopenharmony_ci just put the address in the first EEPROM locations. */ 18138c2ecf20Sopenharmony_ci /* This does memcmp(eedata, eedata+16, 8) */ 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci#ifndef CONFIG_MIPS_COBALT 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci for (i = 0; i < 8; i ++) 18188c2ecf20Sopenharmony_ci if (ee_data[i] != ee_data[16+i]) 18198c2ecf20Sopenharmony_ci sa_offset = 20; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci#endif 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* store MAC address */ 18248c2ecf20Sopenharmony_ci for (i = 0; i < 6; i ++) 18258c2ecf20Sopenharmony_ci de->dev->dev_addr[i] = ee_data[i + sa_offset]; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* get offset of controller 0 info leaf. ignore 2nd byte. */ 18288c2ecf20Sopenharmony_ci ofs = ee_data[SROMC0InfoLeaf]; 18298c2ecf20Sopenharmony_ci if (ofs >= (sizeof(ee_data) - sizeof(struct de_srom_info_leaf) - sizeof(struct de_srom_media_block))) 18308c2ecf20Sopenharmony_ci goto bad_srom; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* get pointer to info leaf */ 18338c2ecf20Sopenharmony_ci il = (struct de_srom_info_leaf *) &ee_data[ofs]; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci /* paranoia checks */ 18368c2ecf20Sopenharmony_ci if (il->n_blocks == 0) 18378c2ecf20Sopenharmony_ci goto bad_srom; 18388c2ecf20Sopenharmony_ci if ((sizeof(ee_data) - ofs) < 18398c2ecf20Sopenharmony_ci (sizeof(struct de_srom_info_leaf) + (sizeof(struct de_srom_media_block) * il->n_blocks))) 18408c2ecf20Sopenharmony_ci goto bad_srom; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* get default media type */ 18438c2ecf20Sopenharmony_ci switch (get_unaligned(&il->default_media)) { 18448c2ecf20Sopenharmony_ci case 0x0001: de->media_type = DE_MEDIA_BNC; break; 18458c2ecf20Sopenharmony_ci case 0x0002: de->media_type = DE_MEDIA_AUI; break; 18468c2ecf20Sopenharmony_ci case 0x0204: de->media_type = DE_MEDIA_TP_FD; break; 18478c2ecf20Sopenharmony_ci default: de->media_type = DE_MEDIA_TP_AUTO; break; 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (netif_msg_probe(de)) 18518c2ecf20Sopenharmony_ci pr_info("de%d: SROM leaf offset %u, default media %s\n", 18528c2ecf20Sopenharmony_ci de->board_idx, ofs, media_name[de->media_type]); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* init SIA register values to defaults */ 18558c2ecf20Sopenharmony_ci for (i = 0; i < DE_MAX_MEDIA; i++) { 18568c2ecf20Sopenharmony_ci de->media[i].type = DE_MEDIA_INVALID; 18578c2ecf20Sopenharmony_ci de->media[i].csr13 = 0xffff; 18588c2ecf20Sopenharmony_ci de->media[i].csr14 = 0xffff; 18598c2ecf20Sopenharmony_ci de->media[i].csr15 = 0xffff; 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci /* parse media blocks to see what medias are supported, 18638c2ecf20Sopenharmony_ci * and if any custom CSR values are provided 18648c2ecf20Sopenharmony_ci */ 18658c2ecf20Sopenharmony_ci bufp = ((void *)il) + sizeof(*il); 18668c2ecf20Sopenharmony_ci for (i = 0; i < il->n_blocks; i++) { 18678c2ecf20Sopenharmony_ci struct de_srom_media_block *ib = bufp; 18688c2ecf20Sopenharmony_ci unsigned idx; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci /* index based on media type in media block */ 18718c2ecf20Sopenharmony_ci switch(ib->opts & MediaBlockMask) { 18728c2ecf20Sopenharmony_ci case 0: /* 10baseT */ 18738c2ecf20Sopenharmony_ci de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half 18748c2ecf20Sopenharmony_ci | SUPPORTED_Autoneg; 18758c2ecf20Sopenharmony_ci idx = DE_MEDIA_TP; 18768c2ecf20Sopenharmony_ci de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO; 18778c2ecf20Sopenharmony_ci break; 18788c2ecf20Sopenharmony_ci case 1: /* BNC */ 18798c2ecf20Sopenharmony_ci de->media_supported |= SUPPORTED_BNC; 18808c2ecf20Sopenharmony_ci idx = DE_MEDIA_BNC; 18818c2ecf20Sopenharmony_ci break; 18828c2ecf20Sopenharmony_ci case 2: /* AUI */ 18838c2ecf20Sopenharmony_ci de->media_supported |= SUPPORTED_AUI; 18848c2ecf20Sopenharmony_ci idx = DE_MEDIA_AUI; 18858c2ecf20Sopenharmony_ci break; 18868c2ecf20Sopenharmony_ci case 4: /* 10baseT-FD */ 18878c2ecf20Sopenharmony_ci de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full 18888c2ecf20Sopenharmony_ci | SUPPORTED_Autoneg; 18898c2ecf20Sopenharmony_ci idx = DE_MEDIA_TP_FD; 18908c2ecf20Sopenharmony_ci de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO; 18918c2ecf20Sopenharmony_ci break; 18928c2ecf20Sopenharmony_ci default: 18938c2ecf20Sopenharmony_ci goto bad_srom; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci de->media[idx].type = idx; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (netif_msg_probe(de)) 18998c2ecf20Sopenharmony_ci pr_info("de%d: media block #%u: %s", 19008c2ecf20Sopenharmony_ci de->board_idx, i, 19018c2ecf20Sopenharmony_ci media_name[de->media[idx].type]); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci bufp += sizeof (ib->opts); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (ib->opts & MediaCustomCSRs) { 19068c2ecf20Sopenharmony_ci de->media[idx].csr13 = get_unaligned(&ib->csr13); 19078c2ecf20Sopenharmony_ci de->media[idx].csr14 = get_unaligned(&ib->csr14); 19088c2ecf20Sopenharmony_ci de->media[idx].csr15 = get_unaligned(&ib->csr15); 19098c2ecf20Sopenharmony_ci bufp += sizeof(ib->csr13) + sizeof(ib->csr14) + 19108c2ecf20Sopenharmony_ci sizeof(ib->csr15); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci if (netif_msg_probe(de)) 19138c2ecf20Sopenharmony_ci pr_cont(" (%x,%x,%x)\n", 19148c2ecf20Sopenharmony_ci de->media[idx].csr13, 19158c2ecf20Sopenharmony_ci de->media[idx].csr14, 19168c2ecf20Sopenharmony_ci de->media[idx].csr15); 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci } else { 19198c2ecf20Sopenharmony_ci if (netif_msg_probe(de)) 19208c2ecf20Sopenharmony_ci pr_cont("\n"); 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3])) 19248c2ecf20Sopenharmony_ci break; 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci de->media_advertise = de->media_supported; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_cifill_defaults: 19308c2ecf20Sopenharmony_ci /* fill in defaults, for cases where custom CSRs not used */ 19318c2ecf20Sopenharmony_ci for (i = 0; i < DE_MAX_MEDIA; i++) { 19328c2ecf20Sopenharmony_ci if (de->media[i].csr13 == 0xffff) 19338c2ecf20Sopenharmony_ci de->media[i].csr13 = t21041_csr13[i]; 19348c2ecf20Sopenharmony_ci if (de->media[i].csr14 == 0xffff) { 19358c2ecf20Sopenharmony_ci /* autonegotiation is broken at least on some chip 19368c2ecf20Sopenharmony_ci revisions - rev. 0x21 works, 0x11 does not */ 19378c2ecf20Sopenharmony_ci if (de->pdev->revision < 0x20) 19388c2ecf20Sopenharmony_ci de->media[i].csr14 = t21041_csr14_brk[i]; 19398c2ecf20Sopenharmony_ci else 19408c2ecf20Sopenharmony_ci de->media[i].csr14 = t21041_csr14[i]; 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci if (de->media[i].csr15 == 0xffff) 19438c2ecf20Sopenharmony_ci de->media[i].csr15 = t21041_csr15[i]; 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci de->ee_data = kmemdup(&ee_data[0], DE_EEPROM_SIZE, GFP_KERNEL); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci return; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cibad_srom: 19518c2ecf20Sopenharmony_ci /* for error cases, it's ok to assume we support all these */ 19528c2ecf20Sopenharmony_ci for (i = 0; i < DE_MAX_MEDIA; i++) 19538c2ecf20Sopenharmony_ci de->media[i].type = i; 19548c2ecf20Sopenharmony_ci de->media_supported = 19558c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Half | 19568c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Full | 19578c2ecf20Sopenharmony_ci SUPPORTED_Autoneg | 19588c2ecf20Sopenharmony_ci SUPPORTED_TP | 19598c2ecf20Sopenharmony_ci SUPPORTED_AUI | 19608c2ecf20Sopenharmony_ci SUPPORTED_BNC; 19618c2ecf20Sopenharmony_ci goto fill_defaults; 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_cistatic const struct net_device_ops de_netdev_ops = { 19658c2ecf20Sopenharmony_ci .ndo_open = de_open, 19668c2ecf20Sopenharmony_ci .ndo_stop = de_close, 19678c2ecf20Sopenharmony_ci .ndo_set_rx_mode = de_set_rx_mode, 19688c2ecf20Sopenharmony_ci .ndo_start_xmit = de_start_xmit, 19698c2ecf20Sopenharmony_ci .ndo_get_stats = de_get_stats, 19708c2ecf20Sopenharmony_ci .ndo_tx_timeout = de_tx_timeout, 19718c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 19728c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 19738c2ecf20Sopenharmony_ci}; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_cistatic int de_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 19768c2ecf20Sopenharmony_ci{ 19778c2ecf20Sopenharmony_ci struct net_device *dev; 19788c2ecf20Sopenharmony_ci struct de_private *de; 19798c2ecf20Sopenharmony_ci int rc; 19808c2ecf20Sopenharmony_ci void __iomem *regs; 19818c2ecf20Sopenharmony_ci unsigned long pciaddr; 19828c2ecf20Sopenharmony_ci static int board_idx = -1; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci board_idx++; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci /* allocate a new ethernet device structure, and fill in defaults */ 19878c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct de_private)); 19888c2ecf20Sopenharmony_ci if (!dev) 19898c2ecf20Sopenharmony_ci return -ENOMEM; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci dev->netdev_ops = &de_netdev_ops; 19928c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 19938c2ecf20Sopenharmony_ci dev->ethtool_ops = &de_ethtool_ops; 19948c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci de = netdev_priv(dev); 19978c2ecf20Sopenharmony_ci de->de21040 = ent->driver_data == 0 ? 1 : 0; 19988c2ecf20Sopenharmony_ci de->pdev = pdev; 19998c2ecf20Sopenharmony_ci de->dev = dev; 20008c2ecf20Sopenharmony_ci de->msg_enable = (debug < 0 ? DE_DEF_MSG_ENABLE : debug); 20018c2ecf20Sopenharmony_ci de->board_idx = board_idx; 20028c2ecf20Sopenharmony_ci spin_lock_init (&de->lock); 20038c2ecf20Sopenharmony_ci timer_setup(&de->media_timer, 20048c2ecf20Sopenharmony_ci de->de21040 ? de21040_media_timer : de21041_media_timer, 20058c2ecf20Sopenharmony_ci 0); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci netif_carrier_off(dev); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci /* wake up device, assign resources */ 20108c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 20118c2ecf20Sopenharmony_ci if (rc) 20128c2ecf20Sopenharmony_ci goto err_out_free; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci /* reserve PCI resources to ensure driver atomicity */ 20158c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, DRV_NAME); 20168c2ecf20Sopenharmony_ci if (rc) 20178c2ecf20Sopenharmony_ci goto err_out_disable; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci /* check for invalid IRQ value */ 20208c2ecf20Sopenharmony_ci if (pdev->irq < 2) { 20218c2ecf20Sopenharmony_ci rc = -EIO; 20228c2ecf20Sopenharmony_ci pr_err("invalid irq (%d) for pci dev %s\n", 20238c2ecf20Sopenharmony_ci pdev->irq, pci_name(pdev)); 20248c2ecf20Sopenharmony_ci goto err_out_res; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci /* obtain and check validity of PCI I/O address */ 20288c2ecf20Sopenharmony_ci pciaddr = pci_resource_start(pdev, 1); 20298c2ecf20Sopenharmony_ci if (!pciaddr) { 20308c2ecf20Sopenharmony_ci rc = -EIO; 20318c2ecf20Sopenharmony_ci pr_err("no MMIO resource for pci dev %s\n", pci_name(pdev)); 20328c2ecf20Sopenharmony_ci goto err_out_res; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) { 20358c2ecf20Sopenharmony_ci rc = -EIO; 20368c2ecf20Sopenharmony_ci pr_err("MMIO resource (%llx) too small on pci dev %s\n", 20378c2ecf20Sopenharmony_ci (unsigned long long)pci_resource_len(pdev, 1), 20388c2ecf20Sopenharmony_ci pci_name(pdev)); 20398c2ecf20Sopenharmony_ci goto err_out_res; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci /* remap CSR registers */ 20438c2ecf20Sopenharmony_ci regs = ioremap(pciaddr, DE_REGS_SIZE); 20448c2ecf20Sopenharmony_ci if (!regs) { 20458c2ecf20Sopenharmony_ci rc = -EIO; 20468c2ecf20Sopenharmony_ci pr_err("Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n", 20478c2ecf20Sopenharmony_ci (unsigned long long)pci_resource_len(pdev, 1), 20488c2ecf20Sopenharmony_ci pciaddr, pci_name(pdev)); 20498c2ecf20Sopenharmony_ci goto err_out_res; 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci de->regs = regs; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci de_adapter_wake(de); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci /* make sure hardware is not running */ 20568c2ecf20Sopenharmony_ci rc = de_reset_mac(de); 20578c2ecf20Sopenharmony_ci if (rc) { 20588c2ecf20Sopenharmony_ci pr_err("Cannot reset MAC, pci dev %s\n", pci_name(pdev)); 20598c2ecf20Sopenharmony_ci goto err_out_iomap; 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /* get MAC address, initialize default media type and 20638c2ecf20Sopenharmony_ci * get list of supported media 20648c2ecf20Sopenharmony_ci */ 20658c2ecf20Sopenharmony_ci if (de->de21040) { 20668c2ecf20Sopenharmony_ci de21040_get_mac_address(de); 20678c2ecf20Sopenharmony_ci de21040_get_media_info(de); 20688c2ecf20Sopenharmony_ci } else { 20698c2ecf20Sopenharmony_ci de21041_get_srom_info(de); 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci /* register new network interface with kernel */ 20738c2ecf20Sopenharmony_ci rc = register_netdev(dev); 20748c2ecf20Sopenharmony_ci if (rc) 20758c2ecf20Sopenharmony_ci goto err_out_iomap; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci /* print info about board and interface just registered */ 20788c2ecf20Sopenharmony_ci netdev_info(dev, "%s at %p, %pM, IRQ %d\n", 20798c2ecf20Sopenharmony_ci de->de21040 ? "21040" : "21041", 20808c2ecf20Sopenharmony_ci regs, dev->dev_addr, pdev->irq); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci /* enable busmastering */ 20858c2ecf20Sopenharmony_ci pci_set_master(pdev); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci /* put adapter to sleep */ 20888c2ecf20Sopenharmony_ci de_adapter_sleep(de); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci return 0; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cierr_out_iomap: 20938c2ecf20Sopenharmony_ci kfree(de->ee_data); 20948c2ecf20Sopenharmony_ci iounmap(regs); 20958c2ecf20Sopenharmony_cierr_out_res: 20968c2ecf20Sopenharmony_ci pci_release_regions(pdev); 20978c2ecf20Sopenharmony_cierr_out_disable: 20988c2ecf20Sopenharmony_ci pci_disable_device(pdev); 20998c2ecf20Sopenharmony_cierr_out_free: 21008c2ecf20Sopenharmony_ci free_netdev(dev); 21018c2ecf20Sopenharmony_ci return rc; 21028c2ecf20Sopenharmony_ci} 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_cistatic void de_remove_one(struct pci_dev *pdev) 21058c2ecf20Sopenharmony_ci{ 21068c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 21078c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci BUG_ON(!dev); 21108c2ecf20Sopenharmony_ci unregister_netdev(dev); 21118c2ecf20Sopenharmony_ci kfree(de->ee_data); 21128c2ecf20Sopenharmony_ci iounmap(de->regs); 21138c2ecf20Sopenharmony_ci pci_release_regions(pdev); 21148c2ecf20Sopenharmony_ci pci_disable_device(pdev); 21158c2ecf20Sopenharmony_ci free_netdev(dev); 21168c2ecf20Sopenharmony_ci} 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_cistatic int __maybe_unused de_suspend(struct device *dev_d) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_d); 21218c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 21228c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci rtnl_lock(); 21258c2ecf20Sopenharmony_ci if (netif_running (dev)) { 21268c2ecf20Sopenharmony_ci const int irq = pdev->irq; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci del_timer_sync(&de->media_timer); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci disable_irq(irq); 21318c2ecf20Sopenharmony_ci spin_lock_irq(&de->lock); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci de_stop_hw(de); 21348c2ecf20Sopenharmony_ci netif_stop_queue(dev); 21358c2ecf20Sopenharmony_ci netif_device_detach(dev); 21368c2ecf20Sopenharmony_ci netif_carrier_off(dev); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci spin_unlock_irq(&de->lock); 21398c2ecf20Sopenharmony_ci enable_irq(irq); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci /* Update the error counts. */ 21428c2ecf20Sopenharmony_ci __de_get_stats(de); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci synchronize_irq(irq); 21458c2ecf20Sopenharmony_ci de_clean_rings(de); 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci de_adapter_sleep(de); 21488c2ecf20Sopenharmony_ci } else { 21498c2ecf20Sopenharmony_ci netif_device_detach(dev); 21508c2ecf20Sopenharmony_ci } 21518c2ecf20Sopenharmony_ci rtnl_unlock(); 21528c2ecf20Sopenharmony_ci return 0; 21538c2ecf20Sopenharmony_ci} 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_cistatic int __maybe_unused de_resume(struct device *dev_d) 21568c2ecf20Sopenharmony_ci{ 21578c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_d); 21588c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 21598c2ecf20Sopenharmony_ci struct de_private *de = netdev_priv(dev); 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci rtnl_lock(); 21628c2ecf20Sopenharmony_ci if (netif_device_present(dev)) 21638c2ecf20Sopenharmony_ci goto out; 21648c2ecf20Sopenharmony_ci if (!netif_running(dev)) 21658c2ecf20Sopenharmony_ci goto out_attach; 21668c2ecf20Sopenharmony_ci pci_set_master(pdev); 21678c2ecf20Sopenharmony_ci de_init_rings(de); 21688c2ecf20Sopenharmony_ci de_init_hw(de); 21698c2ecf20Sopenharmony_ciout_attach: 21708c2ecf20Sopenharmony_ci netif_device_attach(dev); 21718c2ecf20Sopenharmony_ciout: 21728c2ecf20Sopenharmony_ci rtnl_unlock(); 21738c2ecf20Sopenharmony_ci return 0; 21748c2ecf20Sopenharmony_ci} 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(de_pm_ops, de_suspend, de_resume); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_cistatic struct pci_driver de_driver = { 21798c2ecf20Sopenharmony_ci .name = DRV_NAME, 21808c2ecf20Sopenharmony_ci .id_table = de_pci_tbl, 21818c2ecf20Sopenharmony_ci .probe = de_init_one, 21828c2ecf20Sopenharmony_ci .remove = de_remove_one, 21838c2ecf20Sopenharmony_ci .driver.pm = &de_pm_ops, 21848c2ecf20Sopenharmony_ci}; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_cistatic int __init de_init (void) 21878c2ecf20Sopenharmony_ci{ 21888c2ecf20Sopenharmony_ci return pci_register_driver(&de_driver); 21898c2ecf20Sopenharmony_ci} 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_cistatic void __exit de_exit (void) 21928c2ecf20Sopenharmony_ci{ 21938c2ecf20Sopenharmony_ci pci_unregister_driver (&de_driver); 21948c2ecf20Sopenharmony_ci} 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_cimodule_init(de_init); 21978c2ecf20Sopenharmony_cimodule_exit(de_exit); 2198