1a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* 2a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * Copyright (c) 2008-2009 Nuvoton technology corporation. 3a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * 4a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * Wan ZongShun <mcuos.com@gmail.com> 5a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * 6a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * This program is free software; you can redistribute it and/or modify 7a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * it under the terms of the GNU General Public License as published by 8a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * the Free Software Foundation;version 2 of the License. 9a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * 10a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun */ 11a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 12a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/module.h> 13a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/init.h> 14a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/mii.h> 15a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/netdevice.h> 16a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/etherdevice.h> 17a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/skbuff.h> 18a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/ethtool.h> 19a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/platform_device.h> 20a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/clk.h> 215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 22a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 23a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define DRV_MODULE_NAME "w90p910-emc" 24a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define DRV_MODULE_VERSION "0.1" 25a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 26a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* Ethernet MAC Registers */ 27a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAMCMR 0x00 28a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAMEN 0x04 29a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAMM_BASE 0x08 30a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAML_BASE 0x0c 31a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_TXDLSA 0x88 32a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_RXDLSA 0x8C 33a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MCMDR 0x90 34a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MIID 0x94 35a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MIIDA 0x98 36a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_FFTCR 0x9C 37a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_TSDR 0xa0 38a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_RSDR 0xa4 39a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_DMARFC 0xa8 40a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MIEN 0xac 41a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MISTA 0xb0 42a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CTXDSA 0xcc 43a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CTXBSA 0xd0 44a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CRXDSA 0xd4 45a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CRXBSA 0xd8 46a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 47a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* mac controller bit */ 48a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_RXON 0x01 49a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_ACP (0x01 << 3) 50a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_SPCRC (0x01 << 5) 51a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_TXON (0x01 << 8) 52a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_FDUP (0x01 << 18) 53a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_ENMDC (0x01 << 19) 54a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_OPMOD (0x01 << 20) 55a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define SWR (0x01 << 24) 56a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 57a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* cam command regiser */ 58a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_AUP 0x01 59a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_AMP (0x01 << 1) 60a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_ABP (0x01 << 2) 61a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_CCAM (0x01 << 3) 62a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_ECMP (0x01 << 4) 63a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAM0EN 0x01 64a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 65a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* mac mii controller bit */ 66a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MDCCR (0x0a << 20) 67a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYAD (0x01 << 8) 68a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYWR (0x01 << 16) 69a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYBUSY (0x01 << 17) 70a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYPRESP (0x01 << 18) 71a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAM_ENTRY_SIZE 0x08 72a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 73a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* rx and tx status */ 74a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TXDS_TXCP (0x01 << 19) 75a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_CRCE (0x01 << 17) 76a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_PTLE (0x01 << 19) 77a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_RXGD (0x01 << 20) 78a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_ALIE (0x01 << 21) 79a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_RP (0x01 << 22) 80a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 81a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* mac interrupt status*/ 82a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_EXDEF (0x01 << 19) 83a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_TXBERR (0x01 << 24) 84a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_TDU (0x01 << 23) 85a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_RDU (0x01 << 10) 86a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_RXBERR (0x01 << 11) 87a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 88a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENSTART 0x01 89a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENRXINTR 0x01 90a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENRXGD (0x01 << 4) 91a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENRXBERR (0x01 << 11) 92a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXINTR (0x01 << 16) 93a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXCP (0x01 << 18) 94a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXABT (0x01 << 21) 95a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXBERR (0x01 << 24) 96a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENMDC (0x01 << 19) 97a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYBUSY (0x01 << 17) 98a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MDCCR_VAL 0xa00000 99a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 100a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* rx and tx owner bit */ 101a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RX_OWEN_DMA (0x01 << 31) 102a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RX_OWEN_CPU (~(0x03 << 30)) 103a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TX_OWEN_DMA (0x01 << 31) 104a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TX_OWEN_CPU (~(0x01 << 31)) 105a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 106a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* tx frame desc controller bit */ 107a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MACTXINTEN 0x04 108a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CRCMODE 0x02 109a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PADDINGMODE 0x01 110a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 111a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* fftcr controller bit */ 112a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TXTHD (0x03 << 8) 113a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define BLENGTH (0x01 << 20) 114a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 115a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* global setting for driver */ 116a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RX_DESC_SIZE 50 117a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TX_DESC_SIZE 10 118a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MAX_RBUFF_SZ 0x600 119a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MAX_TBUFF_SZ 0x600 120c63fdf46ad0a7f8fe3c0252a0e763515617e0ea7Eric Dumazet#define TX_TIMEOUT (HZ/2) 121a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define DELAY 1000 122a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAM0 0x0 123a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 124a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg); 125a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 126a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct w90p910_rxbd { 127a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int sl; 128a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int buffer; 129a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int reserved; 130a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int next; 131a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 132a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 133a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct w90p910_txbd { 134a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int mode; 135a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int buffer; 136a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int sl; 137a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int next; 138a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 139a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 140a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct recv_pdesc { 141a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_rxbd desclist[RX_DESC_SIZE]; 142a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun char recv_buf[RX_DESC_SIZE][MAX_RBUFF_SZ]; 143a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 144a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 145a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct tran_pdesc { 146a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_txbd desclist[TX_DESC_SIZE]; 1471e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ]; 148a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 149a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 150a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct w90p910_ether { 151a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct recv_pdesc *rdesc; 152a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct tran_pdesc *tdesc; 1531e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dma_addr_t rdesc_phys; 1541e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dma_addr_t tdesc_phys; 155a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct net_device_stats stats; 156a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 1571e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun struct resource *res; 158a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct sk_buff *skb; 159a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct clk *clk; 160a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct clk *rmiiclk; 161a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct mii_if_info mii; 162a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct timer_list check_timer; 163a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun void __iomem *reg; 164ddb1417529559810ec2024fd8ca21e4d497a3275Wan ZongShun int rxirq; 165ddb1417529559810ec2024fd8ca21e4d497a3275Wan ZongShun int txirq; 166a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int cur_tx; 167a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int cur_rx; 168a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int finish_tx; 169a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int rx_packets; 170a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int rx_bytes; 171a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int start_tx_ptr; 172a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int start_rx_ptr; 173a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int linkflag; 174a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 175a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 176a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void update_linkspeed_register(struct net_device *dev, 177a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int speed, unsigned int duplex) 178a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 179a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 180a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 181a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 182a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = __raw_readl(ether->reg + REG_MCMDR); 183a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 184a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (speed == SPEED_100) { 185a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun /* 100 full/half duplex */ 186a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (duplex == DUPLEX_FULL) { 187a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= (MCMDR_OPMOD | MCMDR_FDUP); 188a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else { 189a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= MCMDR_OPMOD; 190a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val &= ~MCMDR_FDUP; 191a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 192a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else { 193a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun /* 10 full/half duplex */ 194a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (duplex == DUPLEX_FULL) { 195a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= MCMDR_FDUP; 196a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val &= ~MCMDR_OPMOD; 197a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else { 198a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val &= ~(MCMDR_FDUP | MCMDR_OPMOD); 199a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 200a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 201a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 202a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MCMDR); 203a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 204a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 205a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void update_linkspeed(struct net_device *dev) 206a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 207a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 208a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 209a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int bmsr, bmcr, lpa, speed, duplex; 210a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 211a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 212a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 213a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (!mii_link_ok(ðer->mii)) { 214a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->linkflag = 0x0; 215a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_carrier_off(dev); 216a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_warn(&pdev->dev, "%s: Link down.\n", dev->name); 217a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return; 218a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 219a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 220a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (ether->linkflag == 1) 221a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return; 222a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 223a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun bmsr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMSR); 224a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun bmcr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMCR); 225a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 226a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (bmcr & BMCR_ANENABLE) { 227a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (!(bmsr & BMSR_ANEGCOMPLETE)) 228a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return; 229a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 230a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun lpa = w90p910_mdio_read(dev, ether->mii.phy_id, MII_LPA); 231a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 232a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) 233a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun speed = SPEED_100; 234a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun else 235a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun speed = SPEED_10; 236a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 237a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) 238a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun duplex = DUPLEX_FULL; 239a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun else 240a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun duplex = DUPLEX_HALF; 241a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 242a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else { 243a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; 244a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 245a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 246a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 247a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun update_linkspeed_register(dev, speed, duplex); 248a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 249a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_info(&pdev->dev, "%s: Link now %i-%s\n", dev->name, speed, 250a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); 251a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->linkflag = 0x01; 252a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 253a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_carrier_on(dev); 254a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 255a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 256a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_check_link(unsigned long dev_id) 257a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 258a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct net_device *dev = (struct net_device *) dev_id; 259a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 260a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 261a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun update_linkspeed(dev); 262a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun mod_timer(ðer->check_timer, jiffies + msecs_to_jiffies(1000)); 263a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 264a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 265a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_write_cam(struct net_device *dev, 266a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int x, unsigned char *pval) 267a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 268a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 269a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int msw, lsw; 270a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 271a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3]; 272a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 273a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun lsw = (pval[4] << 24) | (pval[5] << 16); 274a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 275a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(lsw, ether->reg + REG_CAML_BASE + x * CAM_ENTRY_SIZE); 276a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE); 277a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 278a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 2791e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShunstatic int w90p910_init_desc(struct net_device *dev) 280a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 281a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 2821e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun struct w90p910_txbd *tdesc; 2831e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun struct w90p910_rxbd *rdesc; 2841e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun struct platform_device *pdev; 2851e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun unsigned int i; 286a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 287a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 2881e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun pdev = ether->pdev; 289a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 290a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->tdesc = (struct tran_pdesc *) 2911e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc), 2921e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ðer->tdesc_phys, GFP_KERNEL); 2931e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 2941e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (!ether->tdesc) { 2951e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n"); 2961e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun return -ENOMEM; 2971e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun } 298a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 299a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->rdesc = (struct recv_pdesc *) 3001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc), 3011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ðer->rdesc_phys, GFP_KERNEL); 3021e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 3031e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (!ether->rdesc) { 3041e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n"); 3051e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), 3061e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->tdesc, ether->tdesc_phys); 3071e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun return -ENOMEM; 3081e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun } 309a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 310a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun for (i = 0; i < TX_DESC_SIZE; i++) { 3111e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun unsigned int offset; 312a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 3131e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun tdesc = &(ether->tdesc->desclist[i]); 314a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 3151e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (i == TX_DESC_SIZE - 1) 3161e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offset = offsetof(struct tran_pdesc, desclist[0]); 3171e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun else 3181e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offset = offsetof(struct tran_pdesc, desclist[i + 1]); 319a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 3201e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun tdesc->next = ether->tdesc_phys + offset; 3211e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun tdesc->buffer = ether->tdesc_phys + 3221e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offsetof(struct tran_pdesc, tran_buf[i]); 323a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun tdesc->sl = 0; 324a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun tdesc->mode = 0; 325a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 326a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 3271e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->start_tx_ptr = ether->tdesc_phys; 3281e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 329a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun for (i = 0; i < RX_DESC_SIZE; i++) { 3301e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun unsigned int offset; 331a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 3321e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun rdesc = &(ether->rdesc->desclist[i]); 333a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 3341e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (i == RX_DESC_SIZE - 1) 3351e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offset = offsetof(struct recv_pdesc, desclist[0]); 3361e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun else 3371e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offset = offsetof(struct recv_pdesc, desclist[i + 1]); 338a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 3391e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun rdesc->next = ether->rdesc_phys + offset; 340a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun rdesc->sl = RX_OWEN_DMA; 3411e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun rdesc->buffer = ether->rdesc_phys + 3421e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offsetof(struct recv_pdesc, recv_buf[i]); 343a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 3441e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 3451e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->start_rx_ptr = ether->rdesc_phys; 3461e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 3471e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun return 0; 348a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 349a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 350a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_set_fifo_threshold(struct net_device *dev) 351a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 352a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 353a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 354a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 355a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = TXTHD | BLENGTH; 356a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_FFTCR); 357a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 358a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 359a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_return_default_idle(struct net_device *dev) 360a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 361a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 362a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 363a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 364a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = __raw_readl(ether->reg + REG_MCMDR); 365a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= SWR; 366a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MCMDR); 367a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 368a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 369a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_trigger_rx(struct net_device *dev) 370a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 371a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 372a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 373a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(ENSTART, ether->reg + REG_RSDR); 374a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 375a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 376a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_trigger_tx(struct net_device *dev) 377a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 378a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 379a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 380a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(ENSTART, ether->reg + REG_TSDR); 381a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 382a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 383a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_mac_interrupt(struct net_device *dev) 384a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 385a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 386a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 387a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 388a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = ENTXINTR | ENRXINTR | ENRXGD | ENTXCP; 389a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= ENTXBERR | ENRXBERR | ENTXABT; 390a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 391a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MIEN); 392a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 393a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 394a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_get_and_clear_int(struct net_device *dev, 395a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int *val) 396a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 397a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 398a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 399a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun *val = __raw_readl(ether->reg + REG_MISTA); 400a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(*val, ether->reg + REG_MISTA); 401a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 402a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 403a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_set_global_maccmd(struct net_device *dev) 404a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 405a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 406a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 407a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 408a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = __raw_readl(ether->reg + REG_MCMDR); 409a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | ENMDC; 410a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MCMDR); 411a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 412a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 413a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_cam(struct net_device *dev) 414a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 415a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 416a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 417a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 418a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_write_cam(dev, CAM0, dev->dev_addr); 419a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 420a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = __raw_readl(ether->reg + REG_CAMEN); 421a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= CAM0EN; 422a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_CAMEN); 423a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 424a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 425a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_cam_command(struct net_device *dev) 426a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 427a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 428a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 429a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 430a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = CAMCMR_ECMP | CAMCMR_ABP | CAMCMR_AMP; 431a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_CAMCMR); 432a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 433a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 434a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_tx(struct net_device *dev, unsigned int enable) 435a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 436a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 437a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 438a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 439a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = __raw_readl(ether->reg + REG_MCMDR); 440a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 441a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (enable) 442a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= MCMDR_TXON; 443a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun else 444a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val &= ~MCMDR_TXON; 445a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 446a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MCMDR); 447a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 448a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 449a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_rx(struct net_device *dev, unsigned int enable) 450a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 451a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 452a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val; 453a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 454a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = __raw_readl(ether->reg + REG_MCMDR); 455a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 456a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (enable) 457a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= MCMDR_RXON; 458a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun else 459a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val &= ~MCMDR_RXON; 460a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 461a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MCMDR); 462a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 463a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 464a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_set_curdest(struct net_device *dev) 465a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 466a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 467a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 468a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(ether->start_rx_ptr, ether->reg + REG_RXDLSA); 469a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(ether->start_tx_ptr, ether->reg + REG_TXDLSA); 470a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 471a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 472a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_reset_mac(struct net_device *dev) 473a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 474a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 475a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 476a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_tx(dev, 0); 477a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_rx(dev, 0); 478a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_set_fifo_threshold(dev); 479a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_return_default_idle(dev); 480a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 481a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (!netif_queue_stopped(dev)) 482a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_stop_queue(dev); 483a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 484a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_init_desc(dev); 485a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 4861ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet dev->trans_start = jiffies; /* prevent tx timeout */ 487a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->cur_tx = 0x0; 488a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->finish_tx = 0x0; 489a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->cur_rx = 0x0; 490a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 491a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_set_curdest(dev); 492a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_cam(dev); 493a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_cam_command(dev); 494a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_mac_interrupt(dev); 495a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_tx(dev, 1); 496a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_rx(dev, 1); 497a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_trigger_tx(dev); 498a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_trigger_rx(dev); 499a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 5001ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet dev->trans_start = jiffies; /* prevent tx timeout */ 501a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 502a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (netif_queue_stopped(dev)) 503a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_wake_queue(dev); 504a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 505a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 506a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_mdio_write(struct net_device *dev, 507a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun int phy_id, int reg, int data) 508a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 509a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 510a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 511a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val, i; 512a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 513a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 514a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 515a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(data, ether->reg + REG_MIID); 516a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 517a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = (phy_id << 0x08) | reg; 518a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= PHYBUSY | PHYWR | MDCCR_VAL; 519a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MIIDA); 520a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 521a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun for (i = 0; i < DELAY; i++) { 522a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0) 523a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun break; 524a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 525a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 526a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (i == DELAY) 527a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_warn(&pdev->dev, "mdio write timed out\n"); 528a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 529a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 530a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg) 531a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 532a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 533a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 534a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int val, i, data; 535a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 536a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 537a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 538a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = (phy_id << 0x08) | reg; 539a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val |= PHYBUSY | MDCCR_VAL; 540a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(val, ether->reg + REG_MIIDA); 541a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 542a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun for (i = 0; i < DELAY; i++) { 543a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0) 544a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun break; 545a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 546a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 547a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (i == DELAY) { 548a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_warn(&pdev->dev, "mdio read timed out\n"); 549a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun data = 0xffff; 550a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else { 551a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun data = __raw_readl(ether->reg + REG_MIID); 552a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 553a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 554a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return data; 555a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 556a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 5571e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShunstatic int w90p910_set_mac_address(struct net_device *dev, void *addr) 558a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 559a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct sockaddr *address = addr; 560a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 561a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (!is_valid_ether_addr(address->sa_data)) 562a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return -EADDRNOTAVAIL; 563a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 564a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun memcpy(dev->dev_addr, address->sa_data, dev->addr_len); 565a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_write_cam(dev, CAM0, dev->dev_addr); 566a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 567a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 568a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 569a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 570a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_close(struct net_device *dev) 571a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 572a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 5731e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun struct platform_device *pdev; 574a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 5751e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun pdev = ether->pdev; 5761e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 5771e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc), 5781e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->rdesc, ether->rdesc_phys); 5791e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), 5801e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->tdesc, ether->tdesc_phys); 581a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 582a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_stop_queue(dev); 583a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 584a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun del_timer_sync(ðer->check_timer); 585a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun clk_disable(ether->rmiiclk); 586a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun clk_disable(ether->clk); 587a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 588a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun free_irq(ether->txirq, dev); 589a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun free_irq(ether->rxirq, dev); 590a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 591a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 592a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 593a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 594a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic struct net_device_stats *w90p910_ether_stats(struct net_device *dev) 595a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 596a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 597a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 598a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 599a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 600a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return ðer->stats; 601a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 602a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 603a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_send_frame(struct net_device *dev, 604a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned char *data, int length) 605a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 606a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 607a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_txbd *txbd; 608a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 609a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned char *buffer; 610a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 611a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 612a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 613a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 614a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun txbd = ðer->tdesc->desclist[ether->cur_tx]; 615a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun buffer = ether->tdesc->tran_buf[ether->cur_tx]; 6161e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 617a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (length > 1514) { 618a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "send data %d bytes, check it\n", length); 619a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun length = 1514; 620a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 621a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 622a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun txbd->sl = length & 0xFFFF; 623a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 624a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun memcpy(buffer, data, length); 625a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 626a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun txbd->mode = TX_OWEN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN; 627a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 628a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_tx(dev, 1); 629a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 630a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_trigger_tx(dev); 631a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 6321e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (++ether->cur_tx >= TX_DESC_SIZE) 6331e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->cur_tx = 0; 6341e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 635a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun txbd = ðer->tdesc->desclist[ether->cur_tx]; 636a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 637a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (txbd->mode & TX_OWEN_DMA) 638a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_stop_queue(dev); 639a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 640a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 641a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 642a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 643a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_start_xmit(struct sk_buff *skb, struct net_device *dev) 644a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 645a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 646a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 647a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (!(w90p910_send_frame(dev, skb->data, skb->len))) { 648a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->skb = skb; 649a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_kfree_skb_irq(skb); 650a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 651a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 6521e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun return -EAGAIN; 653a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 654a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 655a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) 656a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 657a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 658a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_txbd *txbd; 659a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 660a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct net_device *dev; 661a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int cur_entry, entry, status; 662a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 6631e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev = dev_id; 664a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 665a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 666a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 667a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_get_and_clear_int(dev, &status); 668a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 669a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun cur_entry = __raw_readl(ether->reg + REG_CTXDSA); 670a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 6711e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun entry = ether->tdesc_phys + 6721e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offsetof(struct tran_pdesc, desclist[ether->finish_tx]); 673a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 674a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun while (entry != cur_entry) { 675a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun txbd = ðer->tdesc->desclist[ether->finish_tx]; 676a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 6771e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (++ether->finish_tx >= TX_DESC_SIZE) 6781e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->finish_tx = 0; 679a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 680a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (txbd->sl & TXDS_TXCP) { 681a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.tx_packets++; 682a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.tx_bytes += txbd->sl & 0xFFFF; 683a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else { 684a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.tx_errors++; 685a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 686a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 687a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun txbd->sl = 0x0; 688a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun txbd->mode = 0x0; 689a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 690a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (netif_queue_stopped(dev)) 691a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_wake_queue(dev); 692a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 6931e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun entry = ether->tdesc_phys + 6941e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offsetof(struct tran_pdesc, desclist[ether->finish_tx]); 695a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 696a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 697a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (status & MISTA_EXDEF) { 698a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "emc defer exceed interrupt\n"); 699a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else if (status & MISTA_TXBERR) { 7001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev_err(&pdev->dev, "emc bus error interrupt\n"); 7011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun w90p910_reset_mac(dev); 7021e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun } else if (status & MISTA_TDU) { 7031e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (netif_queue_stopped(dev)) 7041e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun netif_wake_queue(dev); 7051e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun } 706a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 707a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return IRQ_HANDLED; 708a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 709a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 710a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void netdev_rx(struct net_device *dev) 711a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 712a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 713a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_rxbd *rxbd; 714a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 715a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct sk_buff *skb; 716a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned char *data; 717a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int length, status, val, entry; 718a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 719a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 720a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 721a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 722a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun rxbd = ðer->rdesc->desclist[ether->cur_rx]; 723a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 724a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun do { 725a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun val = __raw_readl(ether->reg + REG_CRXDSA); 7261e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 7271e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun entry = ether->rdesc_phys + 7281e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun offsetof(struct recv_pdesc, desclist[ether->cur_rx]); 729a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 730a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (val == entry) 731a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun break; 732a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 733a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun status = rxbd->sl; 734a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun length = status & 0xFFFF; 735a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 736a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (status & RXDS_RXGD) { 737a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun data = ether->rdesc->recv_buf[ether->cur_rx]; 738a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun skb = dev_alloc_skb(length+2); 739a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (!skb) { 740a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "get skb buffer error\n"); 741a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.rx_dropped++; 742a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return; 743a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 744a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 745a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun skb_reserve(skb, 2); 746a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun skb_put(skb, length); 747a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun skb_copy_to_linear_data(skb, data, length); 748a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun skb->protocol = eth_type_trans(skb, dev); 749a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.rx_packets++; 750a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.rx_bytes += length; 751a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_rx(skb); 752a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else { 753a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.rx_errors++; 754a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 755a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (status & RXDS_RP) { 756a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "rx runt err\n"); 757a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.rx_length_errors++; 758a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else if (status & RXDS_CRCE) { 7591e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev_err(&pdev->dev, "rx crc err\n"); 7601e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->stats.rx_crc_errors++; 7611e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun } else if (status & RXDS_ALIE) { 762a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "rx aligment err\n"); 763a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->stats.rx_frame_errors++; 764a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else if (status & RXDS_PTLE) { 7651e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev_err(&pdev->dev, "rx longer err\n"); 7661e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->stats.rx_over_errors++; 767a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 7681e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun } 769a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 770a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun rxbd->sl = RX_OWEN_DMA; 771a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun rxbd->reserved = 0x0; 7721e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 7731e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (++ether->cur_rx >= RX_DESC_SIZE) 7741e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->cur_rx = 0; 7751e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 776a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun rxbd = ðer->rdesc->desclist[ether->cur_rx]; 777a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 778a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } while (1); 779a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 780a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 781a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic irqreturn_t w90p910_rx_interrupt(int irq, void *dev_id) 782a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 783a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct net_device *dev; 784a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 785a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 786a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int status; 787a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 7881e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev = dev_id; 789a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 790a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 791a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 792a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_get_and_clear_int(dev, &status); 793a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 794a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (status & MISTA_RDU) { 795a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netdev_rx(dev); 796a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_trigger_rx(dev); 797a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 798a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return IRQ_HANDLED; 799a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } else if (status & MISTA_RXBERR) { 8001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun dev_err(&pdev->dev, "emc rx bus error\n"); 8011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun w90p910_reset_mac(dev); 8021e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun } 803a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 804a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netdev_rx(dev); 805a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return IRQ_HANDLED; 806a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 807a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 808a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_open(struct net_device *dev) 809a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 810a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 811a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 812a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 813a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 814a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 815a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 816a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_reset_mac(dev); 817a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_set_fifo_threshold(dev); 818a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_set_curdest(dev); 819a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_cam(dev); 820a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_cam_command(dev); 821a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_mac_interrupt(dev); 822a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_set_global_maccmd(dev); 823a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_enable_rx(dev, 1); 824a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 825d1853dc8fa8e6478707bf5d8e9d0b949974c2ddeWan ZongShun clk_enable(ether->rmiiclk); 826d1853dc8fa8e6478707bf5d8e9d0b949974c2ddeWan ZongShun clk_enable(ether->clk); 827d1853dc8fa8e6478707bf5d8e9d0b949974c2ddeWan ZongShun 828a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->rx_packets = 0x0; 829a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->rx_bytes = 0x0; 830a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 831a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (request_irq(ether->txirq, w90p910_tx_interrupt, 832a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 0x0, pdev->name, dev)) { 833a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "register irq tx failed\n"); 834a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return -EAGAIN; 835a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 836a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 837a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (request_irq(ether->rxirq, w90p910_rx_interrupt, 838a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 0x0, pdev->name, dev)) { 839a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "register irq rx failed\n"); 8401e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun free_irq(ether->txirq, dev); 841a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return -EAGAIN; 842a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 843a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 844a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun mod_timer(ðer->check_timer, jiffies + msecs_to_jiffies(1000)); 845a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun netif_start_queue(dev); 846a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_trigger_rx(dev); 847a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 848a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_info(&pdev->dev, "%s is OPENED\n", dev->name); 849a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 850a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 851a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 852a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 853a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_ether_set_multicast_list(struct net_device *dev) 854a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 855a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 856a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unsigned int rx_mode; 857a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 858a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether = netdev_priv(dev); 859a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 860a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (dev->flags & IFF_PROMISC) 861a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP; 8623b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) 8633b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP; 8643b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko else 8653b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko rx_mode = CAMCMR_ECMP | CAMCMR_ABP; 866a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun __raw_writel(rx_mode, ether->reg + REG_CAMCMR); 867a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 868a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 869a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_ioctl(struct net_device *dev, 870a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct ifreq *ifr, int cmd) 871a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 872a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 873a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct mii_ioctl_data *data = if_mii(ifr); 874a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 875a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return generic_mii_ioctl(ðer->mii, data, cmd, NULL); 876a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 877a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 878a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_get_drvinfo(struct net_device *dev, 879a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct ethtool_drvinfo *info) 880a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 881a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun strcpy(info->driver, DRV_MODULE_NAME); 882a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun strcpy(info->version, DRV_MODULE_VERSION); 883a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 884a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 885a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 886a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 887a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 888a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return mii_ethtool_gset(ðer->mii, cmd); 889a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 890a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 891a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 892a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 893a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 894a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return mii_ethtool_sset(ðer->mii, cmd); 895a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 896a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 897a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_nway_reset(struct net_device *dev) 898a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 899a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 900a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return mii_nway_restart(ðer->mii); 901a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 902a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 903a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic u32 w90p910_get_link(struct net_device *dev) 904a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 905a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 906a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return mii_link_ok(ðer->mii); 907a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 908a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 909a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic const struct ethtool_ops w90p910_ether_ethtool_ops = { 910a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .get_settings = w90p910_get_settings, 911a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .set_settings = w90p910_set_settings, 912a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .get_drvinfo = w90p910_get_drvinfo, 913a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .nway_reset = w90p910_nway_reset, 914a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .get_link = w90p910_get_link, 915a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 916a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 917a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic const struct net_device_ops w90p910_ether_netdev_ops = { 918a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .ndo_open = w90p910_ether_open, 919a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .ndo_stop = w90p910_ether_close, 920a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .ndo_start_xmit = w90p910_ether_start_xmit, 921a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .ndo_get_stats = w90p910_ether_stats, 922afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = w90p910_ether_set_multicast_list, 9231e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun .ndo_set_mac_address = w90p910_set_mac_address, 924a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .ndo_do_ioctl = w90p910_ether_ioctl, 925a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .ndo_validate_addr = eth_validate_addr, 926a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .ndo_change_mtu = eth_change_mtu, 927a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 928a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 929a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void __init get_mac_address(struct net_device *dev) 930a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 931a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 932a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct platform_device *pdev; 933a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun char addr[6]; 934a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 935a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun pdev = ether->pdev; 936a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 937a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun addr[0] = 0x00; 938a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun addr[1] = 0x02; 939a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun addr[2] = 0xac; 940a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun addr[3] = 0x55; 941a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun addr[4] = 0x88; 942a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun addr[5] = 0xa8; 943a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 944a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (is_valid_ether_addr(addr)) 945a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun memcpy(dev->dev_addr, &addr, 0x06); 946a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun else 947a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "invalid mac address\n"); 948a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 949a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 950a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_setup(struct net_device *dev) 951a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 952a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 953a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 954a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether_setup(dev); 955a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev->netdev_ops = &w90p910_ether_netdev_ops; 956a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev->ethtool_ops = &w90p910_ether_ethtool_ops; 957a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 958a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev->tx_queue_len = 16; 959a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev->dma = 0x0; 960a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev->watchdog_timeo = TX_TIMEOUT; 961a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 962a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun get_mac_address(dev); 963a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 964a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->cur_tx = 0x0; 965a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->cur_rx = 0x0; 966a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->finish_tx = 0x0; 967a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->linkflag = 0x0; 968a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->mii.phy_id = 0x01; 969a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->mii.phy_id_mask = 0x1f; 970a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->mii.reg_num_mask = 0x1f; 971a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->mii.dev = dev; 972a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->mii.mdio_read = w90p910_mdio_read; 973a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->mii.mdio_write = w90p910_mdio_write; 974a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 975a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun setup_timer(ðer->check_timer, w90p910_check_link, 976a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun (unsigned long)dev); 977a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 978a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 979a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 980a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 981a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int __devinit w90p910_ether_probe(struct platform_device *pdev) 982a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 983a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether; 984a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct net_device *dev; 985a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun int error; 986a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 987a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev = alloc_etherdev(sizeof(struct w90p910_ether)); 988a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (!dev) 989a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return -ENOMEM; 990a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 9911e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether = netdev_priv(dev); 9921e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 9931e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9941e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (ether->res == NULL) { 995a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "failed to get I/O memory\n"); 996a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = -ENXIO; 997a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_free; 998a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 999a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 10001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun if (!request_mem_region(ether->res->start, 10011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun resource_size(ether->res), pdev->name)) { 1002a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "failed to request I/O memory\n"); 1003a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = -EBUSY; 1004a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_free; 1005a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 1006a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 10071e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun ether->reg = ioremap(ether->res->start, resource_size(ether->res)); 1008a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (ether->reg == NULL) { 1009a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "failed to remap I/O memory\n"); 1010a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = -ENXIO; 1011a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_free_mem; 1012a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 1013a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1014a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->txirq = platform_get_irq(pdev, 0); 1015a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (ether->txirq < 0) { 1016a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "failed to get ether tx irq\n"); 1017a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = -ENXIO; 1018a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_free_io; 1019a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 1020a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1021a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->rxirq = platform_get_irq(pdev, 1); 1022a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (ether->rxirq < 0) { 1023a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "failed to get ether rx irq\n"); 1024a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = -ENXIO; 1025a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_free_txirq; 1026a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 1027a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1028a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun platform_set_drvdata(pdev, dev); 1029a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1030a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->clk = clk_get(&pdev->dev, NULL); 1031a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (IS_ERR(ether->clk)) { 1032a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "failed to get ether clock\n"); 1033a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = PTR_ERR(ether->clk); 1034a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_free_rxirq; 1035a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 1036a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1037a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->rmiiclk = clk_get(&pdev->dev, "RMII"); 1038a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (IS_ERR(ether->rmiiclk)) { 1039a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "failed to get ether clock\n"); 1040a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = PTR_ERR(ether->rmiiclk); 1041a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_put_clk; 1042a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 1043a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1044a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun ether->pdev = pdev; 1045a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1046a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun w90p910_ether_setup(dev); 1047a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1048a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = register_netdev(dev); 1049a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun if (error != 0) { 1050a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun dev_err(&pdev->dev, "Regiter EMC w90p910 FAILED\n"); 1051a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun error = -ENODEV; 1052a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun goto failed_put_rmiiclk; 1053a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun } 1054a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1055a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 1056a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_put_rmiiclk: 1057a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun clk_put(ether->rmiiclk); 1058a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_put_clk: 1059a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun clk_put(ether->clk); 1060a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_rxirq: 1061a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun free_irq(ether->rxirq, pdev); 1062a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun platform_set_drvdata(pdev, NULL); 1063a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_txirq: 1064a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun free_irq(ether->txirq, pdev); 1065a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_io: 1066a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun iounmap(ether->reg); 1067a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_mem: 10681e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun release_mem_region(ether->res->start, resource_size(ether->res)); 1069a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free: 1070a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun free_netdev(dev); 1071a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return error; 1072a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 1073a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1074a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int __devexit w90p910_ether_remove(struct platform_device *pdev) 1075a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{ 1076a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct net_device *dev = platform_get_drvdata(pdev); 1077a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun struct w90p910_ether *ether = netdev_priv(dev); 1078a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1079a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun unregister_netdev(dev); 10801e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 1081a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun clk_put(ether->rmiiclk); 1082a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun clk_put(ether->clk); 10831e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 10841e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun iounmap(ether->reg); 10851e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun release_mem_region(ether->res->start, resource_size(ether->res)); 10861e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 10871e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun free_irq(ether->txirq, dev); 10881e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun free_irq(ether->rxirq, dev); 10891e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 1090a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun del_timer_sync(ðer->check_timer); 1091a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun platform_set_drvdata(pdev, NULL); 10921e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun 1093a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun free_netdev(dev); 1094a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun return 0; 1095a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun} 1096a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1097a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic struct platform_driver w90p910_ether_driver = { 1098a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .probe = w90p910_ether_probe, 1099a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .remove = __devexit_p(w90p910_ether_remove), 1100a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .driver = { 1101456d8991a795ff5e44dbc1c2a7f8d5b4ed675866Wan ZongShun .name = "nuc900-emc", 1102a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun .owner = THIS_MODULE, 1103a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun }, 1104a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}; 1105a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1106db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(w90p910_ether_driver); 1107a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1108a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunMODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); 1109a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunMODULE_DESCRIPTION("w90p910 MAC driver!"); 1110a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunMODULE_LICENSE("GPL"); 1111456d8991a795ff5e44dbc1c2a7f8d5b4ed675866Wan ZongShunMODULE_ALIAS("platform:nuc900-emc"); 1112a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun 1113