1a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* 23396c7823efb3a5b8630388c464e1034ea031cedPaul Gortmaker * linux/drivers/net/ethernet/ethoc.c 3a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * 4a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * Copyright (C) 2007-2008 Avionic Design Development GmbH 5a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * Copyright (C) 2008-2009 Avionic Design GmbH 6a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * 7a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * This program is free software; you can redistribute it and/or modify 8a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * it under the terms of the GNU General Public License version 2 as 9a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * published by the Free Software Foundation. 10a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * 11a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * Written by Thierry Reding <thierry.reding@avionic-design.de> 12a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */ 13a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 14b7f080cfe223b3b7424872639d153695615a9255Alexey Dobriyan#include <linux/dma-mapping.h> 15a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/etherdevice.h> 16a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/crc32.h> 17a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 18a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/io.h> 19a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/mii.h> 20a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/phy.h> 21a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/platform_device.h> 22d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 24e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn#include <linux/of.h> 259d9779e723a5d23b94abbe5bb7d1197921f6f3ddPaul Gortmaker#include <linux/module.h> 26a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <net/ethoc.h> 27a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 280baa080c75cea6357bfba9b93ba598d747457cbdThomas Choustatic int buffer_size = 0x8000; /* 32 KBytes */ 290baa080c75cea6357bfba9b93ba598d747457cbdThomas Choumodule_param(buffer_size, int, 0); 300baa080c75cea6357bfba9b93ba598d747457cbdThomas ChouMODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); 310baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou 32a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* register offsets */ 33a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER 0x00 34a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_SOURCE 0x04 35a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK 0x08 36a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define IPGT 0x0c 37a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define IPGR1 0x10 38a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define IPGR2 0x14 39a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define PACKETLEN 0x18 40a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define COLLCONF 0x1c 41a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_NUM 0x20 42a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define CTRLMODER 0x24 43a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIMODER 0x28 44a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIICOMMAND 0x2c 45a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIADDRESS 0x30 46a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIITX_DATA 0x34 47a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIRX_DATA 0x38 48a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIISTATUS 0x3c 49a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MAC_ADDR0 0x40 50a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MAC_ADDR1 0x44 51a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETH_HASH0 0x48 52a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETH_HASH1 0x4c 53a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETH_TXCTRL 0x50 54a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 55a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* mode register */ 56a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_RXEN (1 << 0) /* receive enable */ 57a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_TXEN (1 << 1) /* transmit enable */ 58a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_NOPRE (1 << 2) /* no preamble */ 59a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_BRO (1 << 3) /* broadcast address */ 60a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_IAM (1 << 4) /* individual address mode */ 61a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_PRO (1 << 5) /* promiscuous mode */ 62a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_IFG (1 << 6) /* interframe gap for incoming frames */ 63a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_LOOP (1 << 7) /* loopback */ 64a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_NBO (1 << 8) /* no back-off */ 65a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_EDE (1 << 9) /* excess defer enable */ 66a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_FULLD (1 << 10) /* full duplex */ 67a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_RESET (1 << 11) /* FIXME: reset (undocumented) */ 68a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_DCRC (1 << 12) /* delayed CRC enable */ 69a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_CRC (1 << 13) /* CRC enable */ 70a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_HUGE (1 << 14) /* huge packets enable */ 71a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_PAD (1 << 15) /* padding enabled */ 72a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MODER_RSM (1 << 16) /* receive small packets */ 73a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 74a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* interrupt source and mask registers */ 75a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_TXF (1 << 0) /* transmit frame */ 76a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_TXE (1 << 1) /* transmit error */ 77a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_RXF (1 << 2) /* receive frame */ 78a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_RXE (1 << 3) /* receive error */ 79a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_BUSY (1 << 4) 80a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_TXC (1 << 5) /* transmit control frame */ 81a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_RXC (1 << 6) /* receive control frame */ 82a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 83a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_TX (INT_MASK_TXF | INT_MASK_TXE) 84a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_RX (INT_MASK_RXF | INT_MASK_RXE) 85a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 86a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define INT_MASK_ALL ( \ 87a1702857724fb39cb68ce581490010df99168fd0Thierry Reding INT_MASK_TXF | INT_MASK_TXE | \ 88a1702857724fb39cb68ce581490010df99168fd0Thierry Reding INT_MASK_RXF | INT_MASK_RXE | \ 89a1702857724fb39cb68ce581490010df99168fd0Thierry Reding INT_MASK_TXC | INT_MASK_RXC | \ 90a1702857724fb39cb68ce581490010df99168fd0Thierry Reding INT_MASK_BUSY \ 91a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ) 92a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 93a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* packet length register */ 94a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define PACKETLEN_MIN(min) (((min) & 0xffff) << 16) 95a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define PACKETLEN_MAX(max) (((max) & 0xffff) << 0) 96a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define PACKETLEN_MIN_MAX(min, max) (PACKETLEN_MIN(min) | \ 97a1702857724fb39cb68ce581490010df99168fd0Thierry Reding PACKETLEN_MAX(max)) 98a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 99a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* transmit buffer number register */ 100a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_NUM_VAL(x) (((x) <= 0x80) ? (x) : 0x80) 101a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 102a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* control module mode register */ 103a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define CTRLMODER_PASSALL (1 << 0) /* pass all receive frames */ 104a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define CTRLMODER_RXFLOW (1 << 1) /* receive control flow */ 105a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define CTRLMODER_TXFLOW (1 << 2) /* transmit control flow */ 106a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 107a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII mode register */ 108a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIMODER_CLKDIV(x) ((x) & 0xfe) /* needs to be an even number */ 109a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIMODER_NOPRE (1 << 8) /* no preamble */ 110a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 111a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII command register */ 112a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIICOMMAND_SCAN (1 << 0) /* scan status */ 113a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIICOMMAND_READ (1 << 1) /* read status */ 114a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIICOMMAND_WRITE (1 << 2) /* write control data */ 115a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 116a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII address register */ 117a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIADDRESS_FIAD(x) (((x) & 0x1f) << 0) 118a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIADDRESS_RGAD(x) (((x) & 0x1f) << 8) 119a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIADDRESS_ADDR(phy, reg) (MIIADDRESS_FIAD(phy) | \ 120a1702857724fb39cb68ce581490010df99168fd0Thierry Reding MIIADDRESS_RGAD(reg)) 121a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 122a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII transmit data register */ 123a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIITX_DATA_VAL(x) ((x) & 0xffff) 124a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 125a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII receive data register */ 126a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIIRX_DATA_VAL(x) ((x) & 0xffff) 127a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 128a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII status register */ 129a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIISTATUS_LINKFAIL (1 << 0) 130a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIISTATUS_BUSY (1 << 1) 131a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define MIISTATUS_INVALID (1 << 2) 132a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 133a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* TX buffer descriptor */ 134a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_CS (1 << 0) /* carrier sense lost */ 135a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_DF (1 << 1) /* defer indication */ 136a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_LC (1 << 2) /* late collision */ 137a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_RL (1 << 3) /* retransmission limit */ 138a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_RETRY_MASK (0x00f0) 139a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_RETRY(x) (((x) & 0x00f0) >> 4) 140a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_UR (1 << 8) /* transmitter underrun */ 141a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_CRC (1 << 11) /* TX CRC enable */ 142a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_PAD (1 << 12) /* pad enable for short packets */ 143a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_WRAP (1 << 13) 144a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_IRQ (1 << 14) /* interrupt request enable */ 145a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_READY (1 << 15) /* TX buffer ready */ 146a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_LEN(x) (((x) & 0xffff) << 16) 147a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_LEN_MASK (0xffff << 16) 148a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 149a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define TX_BD_STATS (TX_BD_CS | TX_BD_DF | TX_BD_LC | \ 150a1702857724fb39cb68ce581490010df99168fd0Thierry Reding TX_BD_RL | TX_BD_RETRY_MASK | TX_BD_UR) 151a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 152a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* RX buffer descriptor */ 153a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_LC (1 << 0) /* late collision */ 154a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_CRC (1 << 1) /* RX CRC error */ 155a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_SF (1 << 2) /* short frame */ 156a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_TL (1 << 3) /* too long */ 157a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_DN (1 << 4) /* dribble nibble */ 158a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_IS (1 << 5) /* invalid symbol */ 159a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_OR (1 << 6) /* receiver overrun */ 160a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_MISS (1 << 7) 161a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_CF (1 << 8) /* control frame */ 162a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_WRAP (1 << 13) 163a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_IRQ (1 << 14) /* interrupt request enable */ 164a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_EMPTY (1 << 15) 165a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_LEN(x) (((x) & 0xffff) << 16) 166a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 167a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define RX_BD_STATS (RX_BD_LC | RX_BD_CRC | RX_BD_SF | RX_BD_TL | \ 168a1702857724fb39cb68ce581490010df99168fd0Thierry Reding RX_BD_DN | RX_BD_IS | RX_BD_OR | RX_BD_MISS) 169a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 170a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETHOC_BUFSIZ 1536 171a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETHOC_ZLEN 64 172a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETHOC_BD_BASE 0x400 173a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETHOC_TIMEOUT (HZ / 2) 174a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define ETHOC_MII_TIMEOUT (1 + (HZ / 5)) 175a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 176a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/** 177a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * struct ethoc - driver-private device structure 178a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @iobase: pointer to I/O memory region 179a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @membase: pointer to buffer memory region 1800baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou * @dma_alloc: dma allocated buffer size 181ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou * @io_region_size: I/O memory region size 182a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @num_tx: number of send buffers 183a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @cur_tx: last send buffer written 184a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @dty_tx: last buffer actually sent 185a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @num_rx: number of receive buffers 186a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @cur_rx: current receive buffer 187f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn * @vma: pointer to array of virtual memory addresses for buffers 188a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @netdev: pointer to network device structure 189a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @napi: NAPI structure 190a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @msg_enable: device state flags 191a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @lock: device lock 192a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @phy: attached PHY 193a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @mdio: MDIO bus for PHY access 194a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @phy_id: address of attached PHY 195a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */ 196a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstruct ethoc { 197a1702857724fb39cb68ce581490010df99168fd0Thierry Reding void __iomem *iobase; 198a1702857724fb39cb68ce581490010df99168fd0Thierry Reding void __iomem *membase; 1990baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou int dma_alloc; 200ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou resource_size_t io_region_size; 201a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 202a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int num_tx; 203a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int cur_tx; 204a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int dty_tx; 205a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 206a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int num_rx; 207a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int cur_rx; 208a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 209f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn void** vma; 210f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn 211a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct net_device *netdev; 212a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct napi_struct napi; 213a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 msg_enable; 214a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 215a1702857724fb39cb68ce581490010df99168fd0Thierry Reding spinlock_t lock; 216a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 217a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct phy_device *phy; 218a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct mii_bus *mdio; 219a1702857724fb39cb68ce581490010df99168fd0Thierry Reding s8 phy_id; 220a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}; 221a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 222a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/** 223a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * struct ethoc_bd - buffer descriptor 224a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @stat: buffer statistics 225a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @addr: physical memory address 226a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */ 227a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstruct ethoc_bd { 228a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 stat; 229a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 addr; 230a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}; 231a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 23216dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline u32 ethoc_read(struct ethoc *dev, loff_t offset) 233a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 234a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return ioread32(dev->iobase + offset); 235a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 236a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 23716dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_write(struct ethoc *dev, loff_t offset, u32 data) 238a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 239a1702857724fb39cb68ce581490010df99168fd0Thierry Reding iowrite32(data, dev->iobase + offset); 240a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 241a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 24216dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_read_bd(struct ethoc *dev, int index, 24316dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Chou struct ethoc_bd *bd) 244a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 245a1702857724fb39cb68ce581490010df99168fd0Thierry Reding loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd)); 246a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd->stat = ethoc_read(dev, offset + 0); 247a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd->addr = ethoc_read(dev, offset + 4); 248a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 249a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 25016dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_write_bd(struct ethoc *dev, int index, 251a1702857724fb39cb68ce581490010df99168fd0Thierry Reding const struct ethoc_bd *bd) 252a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 253a1702857724fb39cb68ce581490010df99168fd0Thierry Reding loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd)); 254a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, offset + 0, bd->stat); 255a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, offset + 4, bd->addr); 256a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 257a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 25816dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_enable_irq(struct ethoc *dev, u32 mask) 259a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 260a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 imask = ethoc_read(dev, INT_MASK); 261a1702857724fb39cb68ce581490010df99168fd0Thierry Reding imask |= mask; 262a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, INT_MASK, imask); 263a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 264a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 26516dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_disable_irq(struct ethoc *dev, u32 mask) 266a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 267a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 imask = ethoc_read(dev, INT_MASK); 268a1702857724fb39cb68ce581490010df99168fd0Thierry Reding imask &= ~mask; 269a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, INT_MASK, imask); 270a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 271a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 27216dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_ack_irq(struct ethoc *dev, u32 mask) 273a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 274a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, INT_SOURCE, mask); 275a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 276a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 27716dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_enable_rx_and_tx(struct ethoc *dev) 278a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 279a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 mode = ethoc_read(dev, MODER); 280a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode |= MODER_RXEN | MODER_TXEN; 281a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, MODER, mode); 282a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 283a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 28416dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_disable_rx_and_tx(struct ethoc *dev) 285a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 286a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 mode = ethoc_read(dev, MODER); 287a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode &= ~(MODER_RXEN | MODER_TXEN); 288a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, MODER, mode); 289a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 290a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 2915cf3e03457aa905f17f9765702850316b69aad1eDavid S. Millerstatic int ethoc_init_ring(struct ethoc *dev, unsigned long mem_start) 292a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 293a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc_bd bd; 294a1702857724fb39cb68ce581490010df99168fd0Thierry Reding int i; 295f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn void* vma; 296a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 297a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev->cur_tx = 0; 298a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev->dty_tx = 0; 299a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev->cur_rx = 0; 300a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 301ee4f56b990391f0ea333121ebc0e9fba28619b52Jonas Bonn ethoc_write(dev, TX_BD_NUM, dev->num_tx); 302ee4f56b990391f0ea333121ebc0e9fba28619b52Jonas Bonn 303a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* setup transmission buffers */ 304f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn bd.addr = mem_start; 305a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat = TX_BD_IRQ | TX_BD_CRC; 306f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn vma = dev->membase; 307a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 308a1702857724fb39cb68ce581490010df99168fd0Thierry Reding for (i = 0; i < dev->num_tx; i++) { 309a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (i == dev->num_tx - 1) 310a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat |= TX_BD_WRAP; 311a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 312a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write_bd(dev, i, &bd); 313a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.addr += ETHOC_BUFSIZ; 314f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn 315f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn dev->vma[i] = vma; 316f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn vma += ETHOC_BUFSIZ; 317a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 318a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 319a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat = RX_BD_EMPTY | RX_BD_IRQ; 320a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 321a1702857724fb39cb68ce581490010df99168fd0Thierry Reding for (i = 0; i < dev->num_rx; i++) { 322a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (i == dev->num_rx - 1) 323a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat |= RX_BD_WRAP; 324a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 325a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write_bd(dev, dev->num_tx + i, &bd); 326a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.addr += ETHOC_BUFSIZ; 327f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn 328f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn dev->vma[dev->num_tx + i] = vma; 329f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn vma += ETHOC_BUFSIZ; 330a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 331a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 332a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 333a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 334a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 335a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_reset(struct ethoc *dev) 336a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 337a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 mode; 338a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 339a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* TODO: reset controller? */ 340a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 341a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_disable_rx_and_tx(dev); 342a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 343a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* TODO: setup registers */ 344a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 345a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* enable FCS generation and automatic padding */ 346a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode = ethoc_read(dev, MODER); 347a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode |= MODER_CRC | MODER_PAD; 348a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, MODER, mode); 349a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 350a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* set full-duplex mode */ 351a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode = ethoc_read(dev, MODER); 352a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode |= MODER_FULLD; 353a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, MODER, mode); 354a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(dev, IPGT, 0x15); 355a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 356a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_ack_irq(dev, INT_MASK_ALL); 357a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_enable_irq(dev, INT_MASK_ALL); 358a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_enable_rx_and_tx(dev); 359a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 360a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 361a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 362a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic unsigned int ethoc_update_rx_stats(struct ethoc *dev, 363a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc_bd *bd) 364a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 365a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct net_device *netdev = dev->netdev; 366a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int ret = 0; 367a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 368a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & RX_BD_TL) { 369a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "RX: frame too long\n"); 37057616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.rx_length_errors++; 371a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret++; 372a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 373a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 374a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & RX_BD_SF) { 375a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "RX: frame too short\n"); 37657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.rx_length_errors++; 377a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret++; 378a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 379a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 380a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & RX_BD_DN) { 381a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "RX: dribble nibble\n"); 38257616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.rx_frame_errors++; 383a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 384a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 385a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & RX_BD_CRC) { 386a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "RX: wrong CRC\n"); 38757616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.rx_crc_errors++; 388a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret++; 389a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 390a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 391a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & RX_BD_OR) { 392a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "RX: overrun\n"); 39357616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.rx_over_errors++; 394a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret++; 395a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 396a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 397a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & RX_BD_MISS) 39857616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.rx_missed_errors++; 399a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 400a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & RX_BD_LC) { 401a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "RX: late collision\n"); 40257616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.collisions++; 403a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret++; 404a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 405a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 406a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return ret; 407a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 408a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 409a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_rx(struct net_device *dev, int limit) 410a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 411a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 412a1702857724fb39cb68ce581490010df99168fd0Thierry Reding int count; 413a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 414a1702857724fb39cb68ce581490010df99168fd0Thierry Reding for (count = 0; count < limit; ++count) { 415a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int entry; 416a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc_bd bd; 417a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 4186a632625c7da7594d059b88dae0e9c591af147baJonas Bonn entry = priv->num_tx + priv->cur_rx; 419a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_read_bd(priv, entry, &bd); 42020f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn if (bd.stat & RX_BD_EMPTY) { 42120f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn ethoc_ack_irq(priv, INT_MASK_RX); 42220f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn /* If packet (interrupt) came in between checking 42320f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn * BD_EMTPY and clearing the interrupt source, then we 42420f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn * risk missing the packet as the RX interrupt won't 42520f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn * trigger right away when we reenable it; hence, check 42620f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn * BD_EMTPY here again to make sure there isn't such a 42720f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn * packet waiting for us... 42820f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn */ 42920f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn ethoc_read_bd(priv, entry, &bd); 43020f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn if (bd.stat & RX_BD_EMPTY) 43120f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn break; 43220f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn } 433a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 434a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (ethoc_update_rx_stats(priv, &bd) == 0) { 435a1702857724fb39cb68ce581490010df99168fd0Thierry Reding int size = bd.stat >> 16; 43689d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet struct sk_buff *skb; 437050f91dcd9a45a14449dded5180f633692b588d2Thomas Chou 438050f91dcd9a45a14449dded5180f633692b588d2Thomas Chou size -= 4; /* strip the CRC */ 43989d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet skb = netdev_alloc_skb_ip_align(dev, size); 440050f91dcd9a45a14449dded5180f633692b588d2Thomas Chou 441a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (likely(skb)) { 442f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn void *src = priv->vma[entry]; 443a1702857724fb39cb68ce581490010df99168fd0Thierry Reding memcpy_fromio(skb_put(skb, size), src, size); 444a1702857724fb39cb68ce581490010df99168fd0Thierry Reding skb->protocol = eth_type_trans(skb, dev); 44557616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy dev->stats.rx_packets++; 44657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy dev->stats.rx_bytes += size; 447a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netif_receive_skb(skb); 448a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } else { 449a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (net_ratelimit()) 450a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_warn(&dev->dev, "low on memory - " 451a1702857724fb39cb68ce581490010df99168fd0Thierry Reding "packet dropped\n"); 452a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 45357616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy dev->stats.rx_dropped++; 454a1702857724fb39cb68ce581490010df99168fd0Thierry Reding break; 455a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 456a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 457a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 458a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* clear the buffer descriptor so it can be reused */ 459a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat &= ~RX_BD_STATS; 460a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat |= RX_BD_EMPTY; 461a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write_bd(priv, entry, &bd); 4626a632625c7da7594d059b88dae0e9c591af147baJonas Bonn if (++priv->cur_rx == priv->num_rx) 4636a632625c7da7594d059b88dae0e9c591af147baJonas Bonn priv->cur_rx = 0; 464a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 465a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 466a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return count; 467a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 468a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 4694f64bcb2fc093a3a9d7d41220004491ce88e4dd3Jonas Bonnstatic void ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd) 470a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 471a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct net_device *netdev = dev->netdev; 472a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 473a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & TX_BD_LC) { 474a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "TX: late collision\n"); 47557616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.tx_window_errors++; 476a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 477a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 478a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & TX_BD_RL) { 479a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "TX: retransmit limit\n"); 48057616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.tx_aborted_errors++; 481a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 482a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 483a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & TX_BD_UR) { 484a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "TX: underrun\n"); 48557616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.tx_fifo_errors++; 486a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 487a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 488a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & TX_BD_CS) { 489a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "TX: carrier sense lost\n"); 49057616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.tx_carrier_errors++; 491a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 492a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 493a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (bd->stat & TX_BD_STATS) 49457616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.tx_errors++; 495a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 49657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.collisions += (bd->stat >> 4) & 0xf; 49757616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.tx_bytes += bd->stat >> 16; 49857616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy netdev->stats.tx_packets++; 499a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 500a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 501fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonnstatic int ethoc_tx(struct net_device *dev, int limit) 502a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 503a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 504fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn int count; 505fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn struct ethoc_bd bd; 506a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 507fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn for (count = 0; count < limit; ++count) { 508fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn unsigned int entry; 509a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 5106a632625c7da7594d059b88dae0e9c591af147baJonas Bonn entry = priv->dty_tx & (priv->num_tx-1); 511a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 512a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_read_bd(priv, entry, &bd); 513a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 514fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn if (bd.stat & TX_BD_READY || (priv->dty_tx == priv->cur_tx)) { 515fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn ethoc_ack_irq(priv, INT_MASK_TX); 516fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn /* If interrupt came in between reading in the BD 517fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * and clearing the interrupt source, then we risk 518fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * missing the event as the TX interrupt won't trigger 519fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * right away when we reenable it; hence, check 520fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * BD_EMPTY here again to make sure there isn't such an 521fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * event pending... 522fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn */ 523fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn ethoc_read_bd(priv, entry, &bd); 524fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn if (bd.stat & TX_BD_READY || 525fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn (priv->dty_tx == priv->cur_tx)) 526fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn break; 527fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn } 528fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn 5294f64bcb2fc093a3a9d7d41220004491ce88e4dd3Jonas Bonn ethoc_update_tx_stats(priv, &bd); 530fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn priv->dty_tx++; 531a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 532a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 533a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if ((priv->cur_tx - priv->dty_tx) <= (priv->num_tx / 2)) 534a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netif_wake_queue(dev); 535a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 536fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn return count; 537a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 538a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 539a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic irqreturn_t ethoc_interrupt(int irq, void *dev_id) 540a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 54157616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy struct net_device *dev = dev_id; 542a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 543a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 pending; 544fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn u32 mask; 545fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn 546fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn /* Figure out what triggered the interrupt... 547fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * The tricky bit here is that the interrupt source bits get 54825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * set in INT_SOURCE for an event regardless of whether that 549fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * event is masked or not. Thus, in order to figure out what 550fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * triggered the interrupt, we need to remove the sources 551fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * for all events that are currently masked. This behaviour 552fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn * is not particularly well documented but reasonable... 553fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn */ 554fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn mask = ethoc_read(priv, INT_MASK); 555a1702857724fb39cb68ce581490010df99168fd0Thierry Reding pending = ethoc_read(priv, INT_SOURCE); 556fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn pending &= mask; 557fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn 558a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (unlikely(pending == 0)) { 559a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return IRQ_NONE; 560a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 561a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 56250c54a57dfbd392e17f1473717b8e125afcb01a3Thomas Chou ethoc_ack_irq(priv, pending); 563a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 564fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn /* We always handle the dropped packet interrupt */ 565a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (pending & INT_MASK_BUSY) { 566a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&dev->dev, "packet dropped\n"); 56757616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy dev->stats.rx_dropped++; 568a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 569a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 570fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn /* Handle receive/transmit event by switching to polling */ 571fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn if (pending & (INT_MASK_TX | INT_MASK_RX)) { 572fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX); 573fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn napi_schedule(&priv->napi); 574a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 575a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 576a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return IRQ_HANDLED; 577a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 578a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 579a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_get_mac_address(struct net_device *dev, void *addr) 580a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 581a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 582a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u8 *mac = (u8 *)addr; 583a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 reg; 584a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 585a1702857724fb39cb68ce581490010df99168fd0Thierry Reding reg = ethoc_read(priv, MAC_ADDR0); 586a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mac[2] = (reg >> 24) & 0xff; 587a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mac[3] = (reg >> 16) & 0xff; 588a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mac[4] = (reg >> 8) & 0xff; 589a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mac[5] = (reg >> 0) & 0xff; 590a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 591a1702857724fb39cb68ce581490010df99168fd0Thierry Reding reg = ethoc_read(priv, MAC_ADDR1); 592a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mac[0] = (reg >> 8) & 0xff; 593a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mac[1] = (reg >> 0) & 0xff; 594a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 595a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 596a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 597a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 598a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_poll(struct napi_struct *napi, int budget) 599a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 600a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = container_of(napi, struct ethoc, napi); 601fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn int rx_work_done = 0; 602fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn int tx_work_done = 0; 603fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn 604fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn rx_work_done = ethoc_rx(priv->netdev, budget); 605fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn tx_work_done = ethoc_tx(priv->netdev, budget); 606a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 607fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn if (rx_work_done < budget && tx_work_done < budget) { 608a1702857724fb39cb68ce581490010df99168fd0Thierry Reding napi_complete(napi); 609fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX); 610a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 611a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 612fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn return rx_work_done; 613a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 614a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 615a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg) 616a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 617a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = bus->priv; 6188dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn int i; 619a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 620a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg)); 621a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ); 622a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 6238dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn for (i=0; i < 5; i++) { 624a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 status = ethoc_read(priv, MIISTATUS); 625a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!(status & MIISTATUS_BUSY)) { 626a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 data = ethoc_read(priv, MIIRX_DATA); 627a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* reset MII command register */ 628a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MIICOMMAND, 0); 629a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return data; 630a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 6318dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn usleep_range(100,200); 632a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 633a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 634a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -EBUSY; 635a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 636a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 637a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 638a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 639a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = bus->priv; 6408dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn int i; 641a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 642a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg)); 643a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MIITX_DATA, val); 644a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE); 645a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 6468dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn for (i=0; i < 5; i++) { 647a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 stat = ethoc_read(priv, MIISTATUS); 648b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn if (!(stat & MIISTATUS_BUSY)) { 649b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn /* reset MII command register */ 650b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn ethoc_write(priv, MIICOMMAND, 0); 651a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 652b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn } 6538dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn usleep_range(100,200); 654a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 655a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 656a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -EBUSY; 657a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 658a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 659a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_mdio_reset(struct mii_bus *bus) 660a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 661a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 662a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 663a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 664a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic void ethoc_mdio_poll(struct net_device *dev) 665a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 666a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 667a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 668f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonnstatic int __devinit ethoc_mdio_probe(struct net_device *dev) 669a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 670a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 671a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct phy_device *phy; 672637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn int err; 673a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 674637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn if (priv->phy_id != -1) { 675637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn phy = priv->mdio->phy_map[priv->phy_id]; 676637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn } else { 677637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn phy = phy_find_first(priv->mdio); 678a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 679a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 680a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!phy) { 681a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&dev->dev, "no PHY found\n"); 682a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -ENXIO; 683a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 684a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 685637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0, 686a1702857724fb39cb68ce581490010df99168fd0Thierry Reding PHY_INTERFACE_MODE_GMII); 687637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn if (err) { 688a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&dev->dev, "could not attach to PHY\n"); 689637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn return err; 690a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 691a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 692a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->phy = phy; 693a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 694a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 695a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 696a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_open(struct net_device *dev) 697a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 698a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 699a1702857724fb39cb68ce581490010df99168fd0Thierry Reding int ret; 700a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 701a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = request_irq(dev->irq, ethoc_interrupt, IRQF_SHARED, 702a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev->name, dev); 703a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (ret) 704a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return ret; 705a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 7065cf3e03457aa905f17f9765702850316b69aad1eDavid S. Miller ethoc_init_ring(priv, dev->mem_start); 707a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_reset(priv); 708a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 709a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (netif_queue_stopped(dev)) { 710a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_dbg(&dev->dev, " resuming queue\n"); 711a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netif_wake_queue(dev); 712a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } else { 713a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_dbg(&dev->dev, " starting queue\n"); 714a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netif_start_queue(dev); 715a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 716a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 717a1702857724fb39cb68ce581490010df99168fd0Thierry Reding phy_start(priv->phy); 718a1702857724fb39cb68ce581490010df99168fd0Thierry Reding napi_enable(&priv->napi); 719a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 720a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (netif_msg_ifup(priv)) { 721a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n", 722a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev->base_addr, dev->mem_start, dev->mem_end); 723a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 724a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 725a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 726a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 727a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 728a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_stop(struct net_device *dev) 729a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 730a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 731a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 732a1702857724fb39cb68ce581490010df99168fd0Thierry Reding napi_disable(&priv->napi); 733a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 734a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (priv->phy) 735a1702857724fb39cb68ce581490010df99168fd0Thierry Reding phy_stop(priv->phy); 736a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 737a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_disable_rx_and_tx(priv); 738a1702857724fb39cb68ce581490010df99168fd0Thierry Reding free_irq(dev->irq, dev); 739a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 740a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!netif_queue_stopped(dev)) 741a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netif_stop_queue(dev); 742a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 743a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 744a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 745a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 746a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 747a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 748a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 749a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct mii_ioctl_data *mdio = if_mii(ifr); 750a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct phy_device *phy = NULL; 751a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 752a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!netif_running(dev)) 753a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -EINVAL; 754a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 755a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (cmd != SIOCGMIIPHY) { 756a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (mdio->phy_id >= PHY_MAX_ADDR) 757a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -ERANGE; 758a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 759a1702857724fb39cb68ce581490010df99168fd0Thierry Reding phy = priv->mdio->phy_map[mdio->phy_id]; 760a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!phy) 761a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -ENODEV; 762a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } else { 763a1702857724fb39cb68ce581490010df99168fd0Thierry Reding phy = priv->phy; 764a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 765a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 76628b041139e344ecd0f144d6205b004ae354cfa1eRichard Cochran return phy_mii_ioctl(phy, ifr, cmd); 767a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 768a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 769a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_config(struct net_device *dev, struct ifmap *map) 770a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 771a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -ENOSYS; 772a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 773a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 774a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_set_mac_address(struct net_device *dev, void *addr) 775a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 776a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 777a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u8 *mac = (u8 *)addr; 778a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 779939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka if (!is_valid_ether_addr(mac)) 780939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka return -EADDRNOTAVAIL; 781939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka 782a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) | 783a1702857724fb39cb68ce581490010df99168fd0Thierry Reding (mac[4] << 8) | (mac[5] << 0)); 784a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0)); 785a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 786939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka memcpy(dev->dev_addr, mac, ETH_ALEN); 787939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka dev->addr_assign_type &= ~NET_ADDR_RANDOM; 788939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka 789a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 790a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 791a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 792a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic void ethoc_set_multicast_list(struct net_device *dev) 793a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 794a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 795a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 mode = ethoc_read(priv, MODER); 79622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 797a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 hash[2] = { 0, 0 }; 798a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 799a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* set loopback mode if requested */ 800a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (dev->flags & IFF_LOOPBACK) 801a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode |= MODER_LOOP; 802a1702857724fb39cb68ce581490010df99168fd0Thierry Reding else 803a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode &= ~MODER_LOOP; 804a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 805a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* receive broadcast frames if requested */ 806a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (dev->flags & IFF_BROADCAST) 807a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode &= ~MODER_BRO; 808a1702857724fb39cb68ce581490010df99168fd0Thierry Reding else 809a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode |= MODER_BRO; 810a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 811a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* enable promiscuous mode if requested */ 812a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (dev->flags & IFF_PROMISC) 813a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode |= MODER_PRO; 814a1702857724fb39cb68ce581490010df99168fd0Thierry Reding else 815a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mode &= ~MODER_PRO; 816a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 817a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, MODER, mode); 818a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 819a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* receive multicast frames */ 820a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (dev->flags & IFF_ALLMULTI) { 821a1702857724fb39cb68ce581490010df99168fd0Thierry Reding hash[0] = 0xffffffff; 822a1702857724fb39cb68ce581490010df99168fd0Thierry Reding hash[1] = 0xffffffff; 823a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } else { 82422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) { 82522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko u32 crc = ether_crc(ETH_ALEN, ha->addr); 826a1702857724fb39cb68ce581490010df99168fd0Thierry Reding int bit = (crc >> 26) & 0x3f; 827a1702857724fb39cb68ce581490010df99168fd0Thierry Reding hash[bit >> 5] |= 1 << (bit & 0x1f); 828a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 829a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 830a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 831a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, ETH_HASH0, hash[0]); 832a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write(priv, ETH_HASH1, hash[1]); 833a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 834a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 835a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_change_mtu(struct net_device *dev, int new_mtu) 836a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 837a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -ENOSYS; 838a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 839a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 840a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic void ethoc_tx_timeout(struct net_device *dev) 841a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 842a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 843a1702857724fb39cb68ce581490010df99168fd0Thierry Reding u32 pending = ethoc_read(priv, INT_SOURCE); 844a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (likely(pending)) 845a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_interrupt(dev->irq, dev); 846a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 847a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 84861357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) 849a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 850a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(dev); 851a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc_bd bd; 852a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int entry; 853a1702857724fb39cb68ce581490010df99168fd0Thierry Reding void *dest; 854a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 855a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (unlikely(skb->len > ETHOC_BUFSIZ)) { 85657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy dev->stats.tx_errors++; 8573790c8cdb99f23824b23cb16df608281b335ee91Patrick McHardy goto out; 858a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 859a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 860a1702857724fb39cb68ce581490010df99168fd0Thierry Reding entry = priv->cur_tx % priv->num_tx; 861a1702857724fb39cb68ce581490010df99168fd0Thierry Reding spin_lock_irq(&priv->lock); 862a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->cur_tx++; 863a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 864a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_read_bd(priv, entry, &bd); 865a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (unlikely(skb->len < ETHOC_ZLEN)) 866a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat |= TX_BD_PAD; 867a1702857724fb39cb68ce581490010df99168fd0Thierry Reding else 868a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat &= ~TX_BD_PAD; 869a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 870f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn dest = priv->vma[entry]; 871a1702857724fb39cb68ce581490010df99168fd0Thierry Reding memcpy_toio(dest, skb->data, skb->len); 872a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 873a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK); 874a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat |= TX_BD_LEN(skb->len); 875a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write_bd(priv, entry, &bd); 876a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 877a1702857724fb39cb68ce581490010df99168fd0Thierry Reding bd.stat |= TX_BD_READY; 878a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_write_bd(priv, entry, &bd); 879a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 880a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (priv->cur_tx == (priv->dty_tx + priv->num_tx)) { 881a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_dbg(&dev->dev, "stopping queue\n"); 882a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netif_stop_queue(dev); 883a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 884a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 885a1702857724fb39cb68ce581490010df99168fd0Thierry Reding spin_unlock_irq(&priv->lock); 88668f51394073b30ef8648f8516d5a7d40c68b1f8aRichard Cochran skb_tx_timestamp(skb); 8873790c8cdb99f23824b23cb16df608281b335ee91Patrick McHardyout: 8883790c8cdb99f23824b23cb16df608281b335ee91Patrick McHardy dev_kfree_skb(skb); 889a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return NETDEV_TX_OK; 890a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 891a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 892a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic const struct net_device_ops ethoc_netdev_ops = { 893a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_open = ethoc_open, 894a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_stop = ethoc_stop, 895a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_do_ioctl = ethoc_ioctl, 896a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_set_config = ethoc_config, 897a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_set_mac_address = ethoc_set_mac_address, 898afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = ethoc_set_multicast_list, 899a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_change_mtu = ethoc_change_mtu, 900a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_tx_timeout = ethoc_tx_timeout, 901a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .ndo_start_xmit = ethoc_start_xmit, 902a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}; 903a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 904a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/** 905a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * ethoc_probe() - initialize OpenCores ethernet MAC 906a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * pdev: platform device 907a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */ 908f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonnstatic int __devinit ethoc_probe(struct platform_device *pdev) 909a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 910a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct net_device *netdev = NULL; 911a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct resource *res = NULL; 912a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct resource *mmio = NULL; 913a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct resource *mem = NULL; 914a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = NULL; 915a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unsigned int phy; 916c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn int num_bd; 917a1702857724fb39cb68ce581490010df99168fd0Thierry Reding int ret = 0; 918939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka bool random_mac = false; 919a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 920a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* allocate networking device */ 921a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netdev = alloc_etherdev(sizeof(struct ethoc)); 922a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!netdev) { 923a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = -ENOMEM; 924a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto out; 925a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 926a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 927a1702857724fb39cb68ce581490010df99168fd0Thierry Reding SET_NETDEV_DEV(netdev, &pdev->dev); 928a1702857724fb39cb68ce581490010df99168fd0Thierry Reding platform_set_drvdata(pdev, netdev); 929a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 930a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* obtain I/O memory space */ 931a1702857724fb39cb68ce581490010df99168fd0Thierry Reding res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 932a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!res) { 933a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&pdev->dev, "cannot obtain I/O memory space\n"); 934a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = -ENXIO; 935a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto free; 936a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 937a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 938a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mmio = devm_request_mem_region(&pdev->dev, res->start, 939d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser resource_size(res), res->name); 940463889e27e6f4f097374a6c9de5611f520766dadJulia Lawall if (!mmio) { 941a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&pdev->dev, "cannot request I/O memory space\n"); 942a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = -ENXIO; 943a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto free; 944a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 945a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 946a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netdev->base_addr = mmio->start; 947a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 948a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* obtain buffer memory space */ 949a1702857724fb39cb68ce581490010df99168fd0Thierry Reding res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 9500baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou if (res) { 9510baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou mem = devm_request_mem_region(&pdev->dev, res->start, 952d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser resource_size(res), res->name); 9530baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou if (!mem) { 9540baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou dev_err(&pdev->dev, "cannot request memory space\n"); 9550baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou ret = -ENXIO; 9560baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou goto free; 9570baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou } 9580baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou 9590baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou netdev->mem_start = mem->start; 9600baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou netdev->mem_end = mem->end; 961a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 962a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 963a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 964a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* obtain device IRQ number */ 965a1702857724fb39cb68ce581490010df99168fd0Thierry Reding res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 966a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!res) { 967a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&pdev->dev, "cannot obtain IRQ\n"); 968a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = -ENXIO; 969a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto free; 970a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 971a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 972a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netdev->irq = res->start; 973a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 974a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* setup driver-private data */ 975a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv = netdev_priv(netdev); 976a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->netdev = netdev; 9770baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou priv->dma_alloc = 0; 97828f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches priv->io_region_size = resource_size(mmio); 979a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 980a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, 981d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser resource_size(mmio)); 982a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!priv->iobase) { 983a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&pdev->dev, "cannot remap I/O memory space\n"); 984a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = -ENXIO; 985a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto error; 986a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 987a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 9880baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou if (netdev->mem_end) { 9890baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou priv->membase = devm_ioremap_nocache(&pdev->dev, 990d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser netdev->mem_start, resource_size(mem)); 9910baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou if (!priv->membase) { 9920baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou dev_err(&pdev->dev, "cannot remap memory space\n"); 9930baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou ret = -ENXIO; 9940baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou goto error; 9950baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou } 9960baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou } else { 9970baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou /* Allocate buffer memory */ 998a71fba97295db924c0b90266e9833e5059fead24Jonas Bonn priv->membase = dmam_alloc_coherent(&pdev->dev, 9990baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou buffer_size, (void *)&netdev->mem_start, 10000baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou GFP_KERNEL); 10010baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou if (!priv->membase) { 10020baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou dev_err(&pdev->dev, "cannot allocate %dB buffer\n", 10030baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou buffer_size); 10040baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou ret = -ENOMEM; 10050baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou goto error; 10060baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou } 10070baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou netdev->mem_end = netdev->mem_start + buffer_size; 10080baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou priv->dma_alloc = buffer_size; 1009a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1010a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1011c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn /* calculate the number of TX/RX buffers, maximum 128 supported */ 1012c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn num_bd = min_t(unsigned int, 1013c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn 128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ); 10146a632625c7da7594d059b88dae0e9c591af147baJonas Bonn if (num_bd < 4) { 10156a632625c7da7594d059b88dae0e9c591af147baJonas Bonn ret = -ENODEV; 10166a632625c7da7594d059b88dae0e9c591af147baJonas Bonn goto error; 10176a632625c7da7594d059b88dae0e9c591af147baJonas Bonn } 10186a632625c7da7594d059b88dae0e9c591af147baJonas Bonn /* num_tx must be a power of two */ 10196a632625c7da7594d059b88dae0e9c591af147baJonas Bonn priv->num_tx = rounddown_pow_of_two(num_bd >> 1); 1020c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn priv->num_rx = num_bd - priv->num_tx; 1021c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn 10226a632625c7da7594d059b88dae0e9c591af147baJonas Bonn dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n", 10236a632625c7da7594d059b88dae0e9c591af147baJonas Bonn priv->num_tx, priv->num_rx); 10246a632625c7da7594d059b88dae0e9c591af147baJonas Bonn 1025f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL); 1026f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn if (!priv->vma) { 1027f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn ret = -ENOMEM; 1028f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn goto error; 1029f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn } 1030f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn 1031a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* Allow the platform setup code to pass in a MAC address. */ 1032a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (pdev->dev.platform_data) { 1033e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn struct ethoc_platform_data *pdata = pdev->dev.platform_data; 1034a1702857724fb39cb68ce581490010df99168fd0Thierry Reding memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN); 1035a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->phy_id = pdata->phy_id; 1036e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn } else { 1037e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn priv->phy_id = -1; 1038e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn 1039e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn#ifdef CONFIG_OF 1040e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn { 1041e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn const uint8_t* mac; 1042e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn 1043e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn mac = of_get_property(pdev->dev.of_node, 1044e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn "local-mac-address", 1045e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn NULL); 1046e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn if (mac) 1047e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn memcpy(netdev->dev_addr, mac, IFHWADDRLEN); 1048e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn } 1049e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn#endif 1050a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1051a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1052a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* Check that the given MAC address is valid. If it isn't, read the 1053a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * current MAC from the controller. */ 1054a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!is_valid_ether_addr(netdev->dev_addr)) 1055a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ethoc_get_mac_address(netdev, netdev->dev_addr); 1056a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1057a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* Check the MAC again for validity, if it still isn't choose and 1058a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * program a random one. */ 1059939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka if (!is_valid_ether_addr(netdev->dev_addr)) { 1060a1702857724fb39cb68ce581490010df99168fd0Thierry Reding random_ether_addr(netdev->dev_addr); 1061939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka random_mac = true; 1062939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka } 1063939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka 1064939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka ret = ethoc_set_mac_address(netdev, netdev->dev_addr); 1065939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka if (ret) { 1066939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka dev_err(&netdev->dev, "failed to set MAC address\n"); 1067939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka goto error; 1068939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka } 1069a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1070939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka if (random_mac) 1071939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka netdev->addr_assign_type |= NET_ADDR_RANDOM; 1072a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1073a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* register MII bus */ 1074a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio = mdiobus_alloc(); 1075a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!priv->mdio) { 1076a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = -ENOMEM; 1077a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto free; 1078a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1079a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1080a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->name = "ethoc-mdio"; 1081a1702857724fb39cb68ce581490010df99168fd0Thierry Reding snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "%s-%d", 1082a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->name, pdev->id); 1083a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->read = ethoc_mdio_read; 1084a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->write = ethoc_mdio_write; 1085a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->reset = ethoc_mdio_reset; 1086a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->priv = priv; 1087a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1088a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 1089a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (!priv->mdio->irq) { 1090a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = -ENOMEM; 1091a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto free_mdio; 1092a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1093a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1094a1702857724fb39cb68ce581490010df99168fd0Thierry Reding for (phy = 0; phy < PHY_MAX_ADDR; phy++) 1095a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->mdio->irq[phy] = PHY_POLL; 1096a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1097a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = mdiobus_register(priv->mdio); 1098a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (ret) { 1099a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "failed to register MDIO bus\n"); 1100a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto free_mdio; 1101a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1102a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1103a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = ethoc_mdio_probe(netdev); 1104a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (ret) { 1105a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "failed to probe MDIO bus\n"); 1106a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto error; 1107a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1108a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1109a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ether_setup(netdev); 1110a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1111a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* setup the net_device structure */ 1112a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netdev->netdev_ops = ðoc_netdev_ops; 1113a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netdev->watchdog_timeo = ETHOC_TIMEOUT; 1114a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netdev->features |= 0; 1115a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1116a1702857724fb39cb68ce581490010df99168fd0Thierry Reding /* setup NAPI */ 1117a1702857724fb39cb68ce581490010df99168fd0Thierry Reding netif_napi_add(netdev, &priv->napi, ethoc_poll, 64); 1118a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1119a1702857724fb39cb68ce581490010df99168fd0Thierry Reding spin_lock_init(&priv->lock); 1120a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1121a1702857724fb39cb68ce581490010df99168fd0Thierry Reding ret = register_netdev(netdev); 1122a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (ret < 0) { 1123a1702857724fb39cb68ce581490010df99168fd0Thierry Reding dev_err(&netdev->dev, "failed to register interface\n"); 1124ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou goto error2; 1125a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1126a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1127a1702857724fb39cb68ce581490010df99168fd0Thierry Reding goto out; 1128a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1129ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chouerror2: 1130ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou netif_napi_del(&priv->napi); 1131a1702857724fb39cb68ce581490010df99168fd0Thierry Redingerror: 1132a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mdiobus_unregister(priv->mdio); 1133a1702857724fb39cb68ce581490010df99168fd0Thierry Redingfree_mdio: 1134a1702857724fb39cb68ce581490010df99168fd0Thierry Reding kfree(priv->mdio->irq); 1135a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mdiobus_free(priv->mdio); 1136a1702857724fb39cb68ce581490010df99168fd0Thierry Redingfree: 1137a1702857724fb39cb68ce581490010df99168fd0Thierry Reding free_netdev(netdev); 1138a1702857724fb39cb68ce581490010df99168fd0Thierry Redingout: 1139a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return ret; 1140a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 1141a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1142a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/** 1143a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * ethoc_remove() - shutdown OpenCores ethernet MAC 1144a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @pdev: platform device 1145a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */ 1146f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonnstatic int __devexit ethoc_remove(struct platform_device *pdev) 1147a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 1148a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct net_device *netdev = platform_get_drvdata(pdev); 1149a1702857724fb39cb68ce581490010df99168fd0Thierry Reding struct ethoc *priv = netdev_priv(netdev); 1150a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1151a1702857724fb39cb68ce581490010df99168fd0Thierry Reding platform_set_drvdata(pdev, NULL); 1152a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1153a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (netdev) { 1154ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou netif_napi_del(&priv->napi); 1155a1702857724fb39cb68ce581490010df99168fd0Thierry Reding phy_disconnect(priv->phy); 1156a1702857724fb39cb68ce581490010df99168fd0Thierry Reding priv->phy = NULL; 1157a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1158a1702857724fb39cb68ce581490010df99168fd0Thierry Reding if (priv->mdio) { 1159a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mdiobus_unregister(priv->mdio); 1160a1702857724fb39cb68ce581490010df99168fd0Thierry Reding kfree(priv->mdio->irq); 1161a1702857724fb39cb68ce581490010df99168fd0Thierry Reding mdiobus_free(priv->mdio); 1162a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1163a1702857724fb39cb68ce581490010df99168fd0Thierry Reding unregister_netdev(netdev); 1164a1702857724fb39cb68ce581490010df99168fd0Thierry Reding free_netdev(netdev); 1165a1702857724fb39cb68ce581490010df99168fd0Thierry Reding } 1166a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1167a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return 0; 1168a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 1169a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1170a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#ifdef CONFIG_PM 1171a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_suspend(struct platform_device *pdev, pm_message_t state) 1172a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 1173a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -ENOSYS; 1174a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 1175a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1176a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_resume(struct platform_device *pdev) 1177a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{ 1178a1702857724fb39cb68ce581490010df99168fd0Thierry Reding return -ENOSYS; 1179a1702857724fb39cb68ce581490010df99168fd0Thierry Reding} 1180a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#else 1181a1702857724fb39cb68ce581490010df99168fd0Thierry Reding# define ethoc_suspend NULL 1182a1702857724fb39cb68ce581490010df99168fd0Thierry Reding# define ethoc_resume NULL 1183a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#endif 1184a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1185e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonnstatic struct of_device_id ethoc_match[] = { 1186c9e358dfc4a8cb2227172ef77908c2e0ee17bcb9Grant Likely { .compatible = "opencores,ethoc", }, 1187e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn {}, 1188e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn}; 1189e0f4258be2515afce8ef1e6fb22312525c281798Jonas BonnMODULE_DEVICE_TABLE(of, ethoc_match); 1190e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn 1191a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic struct platform_driver ethoc_driver = { 1192a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .probe = ethoc_probe, 1193f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonn .remove = __devexit_p(ethoc_remove), 1194a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .suspend = ethoc_suspend, 1195a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .resume = ethoc_resume, 1196a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .driver = { 1197a1702857724fb39cb68ce581490010df99168fd0Thierry Reding .name = "ethoc", 1198e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn .owner = THIS_MODULE, 1199e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn .of_match_table = ethoc_match, 1200a1702857724fb39cb68ce581490010df99168fd0Thierry Reding }, 1201a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}; 1202a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1203db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(ethoc_driver); 1204a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1205a1702857724fb39cb68ce581490010df99168fd0Thierry RedingMODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 1206a1702857724fb39cb68ce581490010df99168fd0Thierry RedingMODULE_DESCRIPTION("OpenCores Ethernet MAC driver"); 1207a1702857724fb39cb68ce581490010df99168fd0Thierry RedingMODULE_LICENSE("GPL v2"); 1208a1702857724fb39cb68ce581490010df99168fd0Thierry Reding 1209