18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Davicom DM9000 Fast Ethernet driver for Linux. 48c2ecf20Sopenharmony_ci * Copyright (C) 1997 Sten Wang 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * (C) Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Additional updates, Copyright: 98c2ecf20Sopenharmony_ci * Ben Dooks <ben@simtec.co.uk> 108c2ecf20Sopenharmony_ci * Sascha Hauer <s.hauer@pengutronix.de> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/ioport.h> 158c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 168c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 198c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 208c2ecf20Sopenharmony_ci#include <linux/crc32.h> 218c2ecf20Sopenharmony_ci#include <linux/mii.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/of_net.h> 248c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 258c2ecf20Sopenharmony_ci#include <linux/dm9000.h> 268c2ecf20Sopenharmony_ci#include <linux/delay.h> 278c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 288c2ecf20Sopenharmony_ci#include <linux/irq.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 318c2ecf20Sopenharmony_ci#include <linux/gpio.h> 328c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <asm/delay.h> 358c2ecf20Sopenharmony_ci#include <asm/irq.h> 368c2ecf20Sopenharmony_ci#include <asm/io.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "dm9000.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Board/System/Debug information/definition ---------------- */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define DM9000_PHY 0x40 /* PHY address 0x01 */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define CARDNAME "dm9000" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * Transmit timeout, default 5 seconds. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_cistatic int watchdog = 5000; 508c2ecf20Sopenharmony_cimodule_param(watchdog, int, 0400); 518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Debug messages level 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic int debug; 578c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "dm9000 debug level (0-6)"); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* DM9000 register address locking. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * The DM9000 uses an address register to control where data written 638c2ecf20Sopenharmony_ci * to the data register goes. This means that the address register 648c2ecf20Sopenharmony_ci * must be preserved over interrupts or similar calls. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * During interrupt and other critical calls, a spinlock is used to 678c2ecf20Sopenharmony_ci * protect the system, but the calls themselves save the address 688c2ecf20Sopenharmony_ci * in the address register in case they are interrupting another 698c2ecf20Sopenharmony_ci * access to the device. 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * For general accesses a lock is provided so that calls which are 728c2ecf20Sopenharmony_ci * allowed to sleep are serialised so that the address register does 738c2ecf20Sopenharmony_ci * not need to be saved. This lock also serves to serialise access 748c2ecf20Sopenharmony_ci * to the EEPROM and PHY access registers which are shared between 758c2ecf20Sopenharmony_ci * these two devices. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* The driver supports the original DM9000E, and now the two newer 798c2ecf20Sopenharmony_ci * devices, DM9000A and DM9000B. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cienum dm9000_type { 838c2ecf20Sopenharmony_ci TYPE_DM9000E, /* original DM9000 */ 848c2ecf20Sopenharmony_ci TYPE_DM9000A, 858c2ecf20Sopenharmony_ci TYPE_DM9000B 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* Structure/enum declaration ------------------------------- */ 898c2ecf20Sopenharmony_cistruct board_info { 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci void __iomem *io_addr; /* Register I/O base address */ 928c2ecf20Sopenharmony_ci void __iomem *io_data; /* Data I/O address */ 938c2ecf20Sopenharmony_ci u16 irq; /* IRQ */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci u16 tx_pkt_cnt; 968c2ecf20Sopenharmony_ci u16 queue_pkt_len; 978c2ecf20Sopenharmony_ci u16 queue_start_addr; 988c2ecf20Sopenharmony_ci u16 queue_ip_summed; 998c2ecf20Sopenharmony_ci u16 dbug_cnt; 1008c2ecf20Sopenharmony_ci u8 io_mode; /* 0:word, 2:byte */ 1018c2ecf20Sopenharmony_ci u8 phy_addr; 1028c2ecf20Sopenharmony_ci u8 imr_all; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci unsigned int flags; 1058c2ecf20Sopenharmony_ci unsigned int in_timeout:1; 1068c2ecf20Sopenharmony_ci unsigned int in_suspend:1; 1078c2ecf20Sopenharmony_ci unsigned int wake_supported:1; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci enum dm9000_type type; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci void (*inblk)(void __iomem *port, void *data, int length); 1128c2ecf20Sopenharmony_ci void (*outblk)(void __iomem *port, void *data, int length); 1138c2ecf20Sopenharmony_ci void (*dumpblk)(void __iomem *port, int length); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci struct device *dev; /* parent device */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci struct resource *addr_res; /* resources found */ 1188c2ecf20Sopenharmony_ci struct resource *data_res; 1198c2ecf20Sopenharmony_ci struct resource *addr_req; /* resources requested */ 1208c2ecf20Sopenharmony_ci struct resource *data_req; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci int irq_wake; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci struct mutex addr_lock; /* phy and eeprom access lock */ 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci struct delayed_work phy_poll; 1278c2ecf20Sopenharmony_ci struct net_device *ndev; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci spinlock_t lock; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci struct mii_if_info mii; 1328c2ecf20Sopenharmony_ci u32 msg_enable; 1338c2ecf20Sopenharmony_ci u32 wake_state; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci int ip_summed; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci struct regulator *power_supply; 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* debug code */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#define dm9000_dbg(db, lev, msg...) do { \ 1438c2ecf20Sopenharmony_ci if ((lev) < debug) { \ 1448c2ecf20Sopenharmony_ci dev_dbg(db->dev, msg); \ 1458c2ecf20Sopenharmony_ci } \ 1468c2ecf20Sopenharmony_ci} while (0) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic inline struct board_info *to_dm9000_board(struct net_device *dev) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci return netdev_priv(dev); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* DM9000 network board routine ---------------------------- */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* 1568c2ecf20Sopenharmony_ci * Read a byte from I/O port 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic u8 1598c2ecf20Sopenharmony_ciior(struct board_info *db, int reg) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci writeb(reg, db->io_addr); 1628c2ecf20Sopenharmony_ci return readb(db->io_data); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * Write a byte to I/O port 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void 1708c2ecf20Sopenharmony_ciiow(struct board_info *db, int reg, int value) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci writeb(reg, db->io_addr); 1738c2ecf20Sopenharmony_ci writeb(value, db->io_data); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void 1778c2ecf20Sopenharmony_cidm9000_reset(struct board_info *db) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci dev_dbg(db->dev, "resetting device\n"); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 1828c2ecf20Sopenharmony_ci * The essential point is that we have to do a double reset, and the 1838c2ecf20Sopenharmony_ci * instruction is to set LBK into MAC internal loopback mode. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); 1868c2ecf20Sopenharmony_ci udelay(100); /* Application note says at least 20 us */ 1878c2ecf20Sopenharmony_ci if (ior(db, DM9000_NCR) & 1) 1888c2ecf20Sopenharmony_ci dev_err(db->dev, "dm9000 did not respond to first reset\n"); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci iow(db, DM9000_NCR, 0); 1918c2ecf20Sopenharmony_ci iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); 1928c2ecf20Sopenharmony_ci udelay(100); 1938c2ecf20Sopenharmony_ci if (ior(db, DM9000_NCR) & 1) 1948c2ecf20Sopenharmony_ci dev_err(db->dev, "dm9000 did not respond to second reset\n"); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* routines for sending block to chip */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void dm9000_outblk_8bit(void __iomem *reg, void *data, int count) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci iowrite8_rep(reg, data, count); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void dm9000_outblk_16bit(void __iomem *reg, void *data, int count) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci iowrite16_rep(reg, data, (count+1) >> 1); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void dm9000_outblk_32bit(void __iomem *reg, void *data, int count) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci iowrite32_rep(reg, data, (count+3) >> 2); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* input block from chip to memory */ 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void dm9000_inblk_8bit(void __iomem *reg, void *data, int count) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci ioread8_rep(reg, data, count); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void dm9000_inblk_16bit(void __iomem *reg, void *data, int count) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci ioread16_rep(reg, data, (count+1) >> 1); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void dm9000_inblk_32bit(void __iomem *reg, void *data, int count) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci ioread32_rep(reg, data, (count+3) >> 2); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/* dump block from chip to null */ 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void dm9000_dumpblk_8bit(void __iomem *reg, int count) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int i; 2378c2ecf20Sopenharmony_ci int tmp; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 2408c2ecf20Sopenharmony_ci tmp = readb(reg); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void dm9000_dumpblk_16bit(void __iomem *reg, int count) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int i; 2468c2ecf20Sopenharmony_ci int tmp; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci count = (count + 1) >> 1; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 2518c2ecf20Sopenharmony_ci tmp = readw(reg); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void dm9000_dumpblk_32bit(void __iomem *reg, int count) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci int i; 2578c2ecf20Sopenharmony_ci int tmp; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci count = (count + 3) >> 2; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 2628c2ecf20Sopenharmony_ci tmp = readl(reg); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci/* 2668c2ecf20Sopenharmony_ci * Sleep, either by using msleep() or if we are suspending, then 2678c2ecf20Sopenharmony_ci * use mdelay() to sleep. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_cistatic void dm9000_msleep(struct board_info *db, unsigned int ms) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci if (db->in_suspend || db->in_timeout) 2728c2ecf20Sopenharmony_ci mdelay(ms); 2738c2ecf20Sopenharmony_ci else 2748c2ecf20Sopenharmony_ci msleep(ms); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/* Read a word from phyxcer */ 2788c2ecf20Sopenharmony_cistatic int 2798c2ecf20Sopenharmony_cidm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 2828c2ecf20Sopenharmony_ci unsigned long flags; 2838c2ecf20Sopenharmony_ci unsigned int reg_save; 2848c2ecf20Sopenharmony_ci int ret; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci mutex_lock(&db->addr_lock); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Save previous register address */ 2918c2ecf20Sopenharmony_ci reg_save = readb(db->io_addr); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Fill the phyxcer register into REG_0C */ 2948c2ecf20Sopenharmony_ci iow(db, DM9000_EPAR, DM9000_PHY | reg); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Issue phyxcer read command */ 2978c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci writeb(reg_save, db->io_addr); 3008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci dm9000_msleep(db, 1); /* Wait read complete */ 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 3058c2ecf20Sopenharmony_ci reg_save = readb(db->io_addr); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* The read data keeps on REG_0D & REG_0E */ 3108c2ecf20Sopenharmony_ci ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* restore the previous address */ 3138c2ecf20Sopenharmony_ci writeb(reg_save, db->io_addr); 3148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci mutex_unlock(&db->addr_lock); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret); 3198c2ecf20Sopenharmony_ci return ret; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* Write a word to phyxcer */ 3238c2ecf20Sopenharmony_cistatic void 3248c2ecf20Sopenharmony_cidm9000_phy_write(struct net_device *dev, 3258c2ecf20Sopenharmony_ci int phyaddr_unused, int reg, int value) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 3288c2ecf20Sopenharmony_ci unsigned long flags; 3298c2ecf20Sopenharmony_ci unsigned long reg_save; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); 3328c2ecf20Sopenharmony_ci if (!db->in_timeout) 3338c2ecf20Sopenharmony_ci mutex_lock(&db->addr_lock); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Save previous register address */ 3388c2ecf20Sopenharmony_ci reg_save = readb(db->io_addr); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Fill the phyxcer register into REG_0C */ 3418c2ecf20Sopenharmony_ci iow(db, DM9000_EPAR, DM9000_PHY | reg); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Fill the written data into REG_0D & REG_0E */ 3448c2ecf20Sopenharmony_ci iow(db, DM9000_EPDRL, value); 3458c2ecf20Sopenharmony_ci iow(db, DM9000_EPDRH, value >> 8); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Issue phyxcer write command */ 3488c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci writeb(reg_save, db->io_addr); 3518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci dm9000_msleep(db, 1); /* Wait write complete */ 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 3568c2ecf20Sopenharmony_ci reg_save = readb(db->io_addr); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* restore the previous address */ 3618c2ecf20Sopenharmony_ci writeb(reg_save, db->io_addr); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 3648c2ecf20Sopenharmony_ci if (!db->in_timeout) 3658c2ecf20Sopenharmony_ci mutex_unlock(&db->addr_lock); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/* dm9000_set_io 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * select the specified set of io routines to use with the 3718c2ecf20Sopenharmony_ci * device 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic void dm9000_set_io(struct board_info *db, int byte_width) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci /* use the size of the data resource to work out what IO 3778c2ecf20Sopenharmony_ci * routines we want to use 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci switch (byte_width) { 3818c2ecf20Sopenharmony_ci case 1: 3828c2ecf20Sopenharmony_ci db->dumpblk = dm9000_dumpblk_8bit; 3838c2ecf20Sopenharmony_ci db->outblk = dm9000_outblk_8bit; 3848c2ecf20Sopenharmony_ci db->inblk = dm9000_inblk_8bit; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci case 3: 3898c2ecf20Sopenharmony_ci dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n"); 3908c2ecf20Sopenharmony_ci fallthrough; 3918c2ecf20Sopenharmony_ci case 2: 3928c2ecf20Sopenharmony_ci db->dumpblk = dm9000_dumpblk_16bit; 3938c2ecf20Sopenharmony_ci db->outblk = dm9000_outblk_16bit; 3948c2ecf20Sopenharmony_ci db->inblk = dm9000_inblk_16bit; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci case 4: 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci db->dumpblk = dm9000_dumpblk_32bit; 4008c2ecf20Sopenharmony_ci db->outblk = dm9000_outblk_32bit; 4018c2ecf20Sopenharmony_ci db->inblk = dm9000_inblk_32bit; 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void dm9000_schedule_poll(struct board_info *db) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci if (db->type == TYPE_DM9000E) 4098c2ecf20Sopenharmony_ci schedule_delayed_work(&db->phy_poll, HZ * 2); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (!netif_running(dev)) 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic unsigned int 4238c2ecf20Sopenharmony_cidm9000_read_locked(struct board_info *db, int reg) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci unsigned long flags; 4268c2ecf20Sopenharmony_ci unsigned int ret; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 4298c2ecf20Sopenharmony_ci ret = ior(db, reg); 4308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int dm9000_wait_eeprom(struct board_info *db) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci unsigned int status; 4388c2ecf20Sopenharmony_ci int timeout = 8; /* wait max 8msec */ 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* The DM9000 data sheets say we should be able to 4418c2ecf20Sopenharmony_ci * poll the ERRE bit in EPCR to wait for the EEPROM 4428c2ecf20Sopenharmony_ci * operation. From testing several chips, this bit 4438c2ecf20Sopenharmony_ci * does not seem to work. 4448c2ecf20Sopenharmony_ci * 4458c2ecf20Sopenharmony_ci * We attempt to use the bit, but fall back to the 4468c2ecf20Sopenharmony_ci * timeout (which is why we do not return an error 4478c2ecf20Sopenharmony_ci * on expiry) to say that the EEPROM operation has 4488c2ecf20Sopenharmony_ci * completed. 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci while (1) { 4528c2ecf20Sopenharmony_ci status = dm9000_read_locked(db, DM9000_EPCR); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if ((status & EPCR_ERRE) == 0) 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci msleep(1); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (timeout-- < 0) { 4608c2ecf20Sopenharmony_ci dev_dbg(db->dev, "timeout waiting EEPROM\n"); 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/* 4698c2ecf20Sopenharmony_ci * Read a word data from EEPROM 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_cistatic void 4728c2ecf20Sopenharmony_cidm9000_read_eeprom(struct board_info *db, int offset, u8 *to) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci unsigned long flags; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (db->flags & DM9000_PLATF_NO_EEPROM) { 4778c2ecf20Sopenharmony_ci to[0] = 0xff; 4788c2ecf20Sopenharmony_ci to[1] = 0xff; 4798c2ecf20Sopenharmony_ci return; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci mutex_lock(&db->addr_lock); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci iow(db, DM9000_EPAR, offset); 4878c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_ERPRR); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci dm9000_wait_eeprom(db); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* delay for at-least 150uS */ 4948c2ecf20Sopenharmony_ci msleep(1); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, 0x0); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci to[0] = ior(db, DM9000_EPDRL); 5018c2ecf20Sopenharmony_ci to[1] = ior(db, DM9000_EPDRH); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci mutex_unlock(&db->addr_lock); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/* 5098c2ecf20Sopenharmony_ci * Write a word data to SROM 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_cistatic void 5128c2ecf20Sopenharmony_cidm9000_write_eeprom(struct board_info *db, int offset, u8 *data) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci unsigned long flags; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (db->flags & DM9000_PLATF_NO_EEPROM) 5178c2ecf20Sopenharmony_ci return; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci mutex_lock(&db->addr_lock); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 5228c2ecf20Sopenharmony_ci iow(db, DM9000_EPAR, offset); 5238c2ecf20Sopenharmony_ci iow(db, DM9000_EPDRH, data[1]); 5248c2ecf20Sopenharmony_ci iow(db, DM9000_EPDRL, data[0]); 5258c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); 5268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci dm9000_wait_eeprom(db); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci mdelay(1); /* wait at least 150uS to clear */ 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 5338c2ecf20Sopenharmony_ci iow(db, DM9000_EPCR, 0); 5348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci mutex_unlock(&db->addr_lock); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci/* ethtool ops */ 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic void dm9000_get_drvinfo(struct net_device *dev, 5428c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci strlcpy(info->driver, CARDNAME, sizeof(info->driver)); 5478c2ecf20Sopenharmony_ci strlcpy(info->bus_info, to_platform_device(dm->dev)->name, 5488c2ecf20Sopenharmony_ci sizeof(info->bus_info)); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic u32 dm9000_get_msglevel(struct net_device *dev) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return dm->msg_enable; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic void dm9000_set_msglevel(struct net_device *dev, u32 value) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci dm->msg_enable = value; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int dm9000_get_link_ksettings(struct net_device *dev, 5668c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci mii_ethtool_get_link_ksettings(&dm->mii, cmd); 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int dm9000_set_link_ksettings(struct net_device *dev, 5758c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return mii_ethtool_set_link_ksettings(&dm->mii, cmd); 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic int dm9000_nway_reset(struct net_device *dev) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 5858c2ecf20Sopenharmony_ci return mii_nway_restart(&dm->mii); 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic int dm9000_set_features(struct net_device *dev, 5898c2ecf20Sopenharmony_ci netdev_features_t features) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 5928c2ecf20Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 5938c2ecf20Sopenharmony_ci unsigned long flags; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (!(changed & NETIF_F_RXCSUM)) 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci spin_lock_irqsave(&dm->lock, flags); 5998c2ecf20Sopenharmony_ci iow(dm, DM9000_RCSR, (features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); 6008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dm->lock, flags); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic u32 dm9000_get_link(struct net_device *dev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 6088c2ecf20Sopenharmony_ci u32 ret; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (dm->flags & DM9000_PLATF_EXT_PHY) 6118c2ecf20Sopenharmony_ci ret = mii_link_ok(&dm->mii); 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci ret = dm9000_read_locked(dm, DM9000_NSR) & NSR_LINKST ? 1 : 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return ret; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci#define DM_EEPROM_MAGIC (0x444D394B) 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int dm9000_get_eeprom_len(struct net_device *dev) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci return 128; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int dm9000_get_eeprom(struct net_device *dev, 6268c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 6298c2ecf20Sopenharmony_ci int offset = ee->offset; 6308c2ecf20Sopenharmony_ci int len = ee->len; 6318c2ecf20Sopenharmony_ci int i; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* EEPROM access is aligned to two bytes */ 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if ((len & 1) != 0 || (offset & 1) != 0) 6368c2ecf20Sopenharmony_ci return -EINVAL; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (dm->flags & DM9000_PLATF_NO_EEPROM) 6398c2ecf20Sopenharmony_ci return -ENOENT; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci ee->magic = DM_EEPROM_MAGIC; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci for (i = 0; i < len; i += 2) 6448c2ecf20Sopenharmony_ci dm9000_read_eeprom(dm, (offset + i) / 2, data + i); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return 0; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic int dm9000_set_eeprom(struct net_device *dev, 6508c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 6538c2ecf20Sopenharmony_ci int offset = ee->offset; 6548c2ecf20Sopenharmony_ci int len = ee->len; 6558c2ecf20Sopenharmony_ci int done; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* EEPROM access is aligned to two bytes */ 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (dm->flags & DM9000_PLATF_NO_EEPROM) 6608c2ecf20Sopenharmony_ci return -ENOENT; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (ee->magic != DM_EEPROM_MAGIC) 6638c2ecf20Sopenharmony_ci return -EINVAL; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci while (len > 0) { 6668c2ecf20Sopenharmony_ci if (len & 1 || offset & 1) { 6678c2ecf20Sopenharmony_ci int which = offset & 1; 6688c2ecf20Sopenharmony_ci u8 tmp[2]; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci dm9000_read_eeprom(dm, offset / 2, tmp); 6718c2ecf20Sopenharmony_ci tmp[which] = *data; 6728c2ecf20Sopenharmony_ci dm9000_write_eeprom(dm, offset / 2, tmp); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci done = 1; 6758c2ecf20Sopenharmony_ci } else { 6768c2ecf20Sopenharmony_ci dm9000_write_eeprom(dm, offset / 2, data); 6778c2ecf20Sopenharmony_ci done = 2; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci data += done; 6818c2ecf20Sopenharmony_ci offset += done; 6828c2ecf20Sopenharmony_ci len -= done; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic void dm9000_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci memset(w, 0, sizeof(struct ethtool_wolinfo)); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* note, we could probably support wake-phy too */ 6958c2ecf20Sopenharmony_ci w->supported = dm->wake_supported ? WAKE_MAGIC : 0; 6968c2ecf20Sopenharmony_ci w->wolopts = dm->wake_state; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 7028c2ecf20Sopenharmony_ci unsigned long flags; 7038c2ecf20Sopenharmony_ci u32 opts = w->wolopts; 7048c2ecf20Sopenharmony_ci u32 wcr = 0; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (!dm->wake_supported) 7078c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (opts & ~WAKE_MAGIC) 7108c2ecf20Sopenharmony_ci return -EINVAL; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (opts & WAKE_MAGIC) 7138c2ecf20Sopenharmony_ci wcr |= WCR_MAGICEN; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci mutex_lock(&dm->addr_lock); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci spin_lock_irqsave(&dm->lock, flags); 7188c2ecf20Sopenharmony_ci iow(dm, DM9000_WCR, wcr); 7198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dm->lock, flags); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci mutex_unlock(&dm->addr_lock); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (dm->wake_state != opts) { 7248c2ecf20Sopenharmony_ci /* change in wol state, update IRQ state */ 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (!dm->wake_state) 7278c2ecf20Sopenharmony_ci irq_set_irq_wake(dm->irq_wake, 1); 7288c2ecf20Sopenharmony_ci else if (dm->wake_state && !opts) 7298c2ecf20Sopenharmony_ci irq_set_irq_wake(dm->irq_wake, 0); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci dm->wake_state = opts; 7338c2ecf20Sopenharmony_ci return 0; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic const struct ethtool_ops dm9000_ethtool_ops = { 7378c2ecf20Sopenharmony_ci .get_drvinfo = dm9000_get_drvinfo, 7388c2ecf20Sopenharmony_ci .get_msglevel = dm9000_get_msglevel, 7398c2ecf20Sopenharmony_ci .set_msglevel = dm9000_set_msglevel, 7408c2ecf20Sopenharmony_ci .nway_reset = dm9000_nway_reset, 7418c2ecf20Sopenharmony_ci .get_link = dm9000_get_link, 7428c2ecf20Sopenharmony_ci .get_wol = dm9000_get_wol, 7438c2ecf20Sopenharmony_ci .set_wol = dm9000_set_wol, 7448c2ecf20Sopenharmony_ci .get_eeprom_len = dm9000_get_eeprom_len, 7458c2ecf20Sopenharmony_ci .get_eeprom = dm9000_get_eeprom, 7468c2ecf20Sopenharmony_ci .set_eeprom = dm9000_set_eeprom, 7478c2ecf20Sopenharmony_ci .get_link_ksettings = dm9000_get_link_ksettings, 7488c2ecf20Sopenharmony_ci .set_link_ksettings = dm9000_set_link_ksettings, 7498c2ecf20Sopenharmony_ci}; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic void dm9000_show_carrier(struct board_info *db, 7528c2ecf20Sopenharmony_ci unsigned carrier, unsigned nsr) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci int lpa; 7558c2ecf20Sopenharmony_ci struct net_device *ndev = db->ndev; 7568c2ecf20Sopenharmony_ci struct mii_if_info *mii = &db->mii; 7578c2ecf20Sopenharmony_ci unsigned ncr = dm9000_read_locked(db, DM9000_NCR); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (carrier) { 7608c2ecf20Sopenharmony_ci lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA); 7618c2ecf20Sopenharmony_ci dev_info(db->dev, 7628c2ecf20Sopenharmony_ci "%s: link up, %dMbps, %s-duplex, lpa 0x%04X\n", 7638c2ecf20Sopenharmony_ci ndev->name, (nsr & NSR_SPEED) ? 10 : 100, 7648c2ecf20Sopenharmony_ci (ncr & NCR_FDX) ? "full" : "half", lpa); 7658c2ecf20Sopenharmony_ci } else { 7668c2ecf20Sopenharmony_ci dev_info(db->dev, "%s: link down\n", ndev->name); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic void 7718c2ecf20Sopenharmony_cidm9000_poll_work(struct work_struct *w) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct delayed_work *dw = to_delayed_work(w); 7748c2ecf20Sopenharmony_ci struct board_info *db = container_of(dw, struct board_info, phy_poll); 7758c2ecf20Sopenharmony_ci struct net_device *ndev = db->ndev; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (db->flags & DM9000_PLATF_SIMPLE_PHY && 7788c2ecf20Sopenharmony_ci !(db->flags & DM9000_PLATF_EXT_PHY)) { 7798c2ecf20Sopenharmony_ci unsigned nsr = dm9000_read_locked(db, DM9000_NSR); 7808c2ecf20Sopenharmony_ci unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0; 7818c2ecf20Sopenharmony_ci unsigned new_carrier; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci new_carrier = (nsr & NSR_LINKST) ? 1 : 0; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (old_carrier != new_carrier) { 7868c2ecf20Sopenharmony_ci if (netif_msg_link(db)) 7878c2ecf20Sopenharmony_ci dm9000_show_carrier(db, new_carrier, nsr); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (!new_carrier) 7908c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 7918c2ecf20Sopenharmony_ci else 7928c2ecf20Sopenharmony_ci netif_carrier_on(ndev); 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci } else 7958c2ecf20Sopenharmony_ci mii_check_media(&db->mii, netif_msg_link(db), 0); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (netif_running(ndev)) 7988c2ecf20Sopenharmony_ci dm9000_schedule_poll(db); 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci/* dm9000_release_board 8028c2ecf20Sopenharmony_ci * 8038c2ecf20Sopenharmony_ci * release a board, and any mapped resources 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic void 8078c2ecf20Sopenharmony_cidm9000_release_board(struct platform_device *pdev, struct board_info *db) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci /* unmap our resources */ 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci iounmap(db->io_addr); 8128c2ecf20Sopenharmony_ci iounmap(db->io_data); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* release the resources */ 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (db->data_req) 8178c2ecf20Sopenharmony_ci release_resource(db->data_req); 8188c2ecf20Sopenharmony_ci kfree(db->data_req); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (db->addr_req) 8218c2ecf20Sopenharmony_ci release_resource(db->addr_req); 8228c2ecf20Sopenharmony_ci kfree(db->addr_req); 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic unsigned char dm9000_type_to_char(enum dm9000_type type) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci switch (type) { 8288c2ecf20Sopenharmony_ci case TYPE_DM9000E: return 'e'; 8298c2ecf20Sopenharmony_ci case TYPE_DM9000A: return 'a'; 8308c2ecf20Sopenharmony_ci case TYPE_DM9000B: return 'b'; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return '?'; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/* 8378c2ecf20Sopenharmony_ci * Set DM9000 multicast address 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_cistatic void 8408c2ecf20Sopenharmony_cidm9000_hash_table_unlocked(struct net_device *dev) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 8438c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 8448c2ecf20Sopenharmony_ci int i, oft; 8458c2ecf20Sopenharmony_ci u32 hash_val; 8468c2ecf20Sopenharmony_ci u16 hash_table[4] = { 0, 0, 0, 0x8000 }; /* broadcast address */ 8478c2ecf20Sopenharmony_ci u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci dm9000_dbg(db, 1, "entering %s\n", __func__); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) 8528c2ecf20Sopenharmony_ci iow(db, oft, dev->dev_addr[i]); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) 8558c2ecf20Sopenharmony_ci rcr |= RCR_PRMSC; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) 8588c2ecf20Sopenharmony_ci rcr |= RCR_ALL; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* the multicast address in Hash Table : 64 bits */ 8618c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 8628c2ecf20Sopenharmony_ci hash_val = ether_crc_le(6, ha->addr) & 0x3f; 8638c2ecf20Sopenharmony_ci hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Write the hash table to MAC MD table */ 8678c2ecf20Sopenharmony_ci for (i = 0, oft = DM9000_MAR; i < 4; i++) { 8688c2ecf20Sopenharmony_ci iow(db, oft++, hash_table[i]); 8698c2ecf20Sopenharmony_ci iow(db, oft++, hash_table[i] >> 8); 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci iow(db, DM9000_RCR, rcr); 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic void 8768c2ecf20Sopenharmony_cidm9000_hash_table(struct net_device *dev) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 8798c2ecf20Sopenharmony_ci unsigned long flags; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 8828c2ecf20Sopenharmony_ci dm9000_hash_table_unlocked(dev); 8838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic void 8878c2ecf20Sopenharmony_cidm9000_mask_interrupts(struct board_info *db) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci iow(db, DM9000_IMR, IMR_PAR); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic void 8938c2ecf20Sopenharmony_cidm9000_unmask_interrupts(struct board_info *db) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci iow(db, DM9000_IMR, db->imr_all); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/* 8998c2ecf20Sopenharmony_ci * Initialize dm9000 board 9008c2ecf20Sopenharmony_ci */ 9018c2ecf20Sopenharmony_cistatic void 9028c2ecf20Sopenharmony_cidm9000_init_dm9000(struct net_device *dev) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 9058c2ecf20Sopenharmony_ci unsigned int imr; 9068c2ecf20Sopenharmony_ci unsigned int ncr; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci dm9000_dbg(db, 1, "entering %s\n", __func__); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci dm9000_reset(db); 9118c2ecf20Sopenharmony_ci dm9000_mask_interrupts(db); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* I/O mode */ 9148c2ecf20Sopenharmony_ci db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* Checksum mode */ 9178c2ecf20Sopenharmony_ci if (dev->hw_features & NETIF_F_RXCSUM) 9188c2ecf20Sopenharmony_ci iow(db, DM9000_RCSR, 9198c2ecf20Sopenharmony_ci (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ 9228c2ecf20Sopenharmony_ci iow(db, DM9000_GPR, 0); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* If we are dealing with DM9000B, some extra steps are required: a 9258c2ecf20Sopenharmony_ci * manual phy reset, and setting init params. 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci if (db->type == TYPE_DM9000B) { 9288c2ecf20Sopenharmony_ci dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); 9298c2ecf20Sopenharmony_ci dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* if wol is needed, then always set NCR_WAKEEN otherwise we end 9358c2ecf20Sopenharmony_ci * up dumping the wake events if we disable this. There is already 9368c2ecf20Sopenharmony_ci * a wake-mask in DM9000_WCR */ 9378c2ecf20Sopenharmony_ci if (db->wake_supported) 9388c2ecf20Sopenharmony_ci ncr |= NCR_WAKEEN; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci iow(db, DM9000_NCR, ncr); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* Program operating register */ 9438c2ecf20Sopenharmony_ci iow(db, DM9000_TCR, 0); /* TX Polling clear */ 9448c2ecf20Sopenharmony_ci iow(db, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */ 9458c2ecf20Sopenharmony_ci iow(db, DM9000_FCR, 0xff); /* Flow Control */ 9468c2ecf20Sopenharmony_ci iow(db, DM9000_SMCR, 0); /* Special Mode */ 9478c2ecf20Sopenharmony_ci /* clear TX status */ 9488c2ecf20Sopenharmony_ci iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); 9498c2ecf20Sopenharmony_ci iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */ 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* Set address filter table */ 9528c2ecf20Sopenharmony_ci dm9000_hash_table_unlocked(dev); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci imr = IMR_PAR | IMR_PTM | IMR_PRM; 9558c2ecf20Sopenharmony_ci if (db->type != TYPE_DM9000E) 9568c2ecf20Sopenharmony_ci imr |= IMR_LNKCHNG; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci db->imr_all = imr; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* Init Driver variable */ 9618c2ecf20Sopenharmony_ci db->tx_pkt_cnt = 0; 9628c2ecf20Sopenharmony_ci db->queue_pkt_len = 0; 9638c2ecf20Sopenharmony_ci netif_trans_update(dev); 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci/* Our watchdog timed out. Called by the networking layer */ 9678c2ecf20Sopenharmony_cistatic void dm9000_timeout(struct net_device *dev, unsigned int txqueue) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 9708c2ecf20Sopenharmony_ci u8 reg_save; 9718c2ecf20Sopenharmony_ci unsigned long flags; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* Save previous register address */ 9748c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 9758c2ecf20Sopenharmony_ci db->in_timeout = 1; 9768c2ecf20Sopenharmony_ci reg_save = readb(db->io_addr); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci netif_stop_queue(dev); 9798c2ecf20Sopenharmony_ci dm9000_init_dm9000(dev); 9808c2ecf20Sopenharmony_ci dm9000_unmask_interrupts(db); 9818c2ecf20Sopenharmony_ci /* We can accept TX packets again */ 9828c2ecf20Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 9838c2ecf20Sopenharmony_ci netif_wake_queue(dev); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* Restore previous register address */ 9868c2ecf20Sopenharmony_ci writeb(reg_save, db->io_addr); 9878c2ecf20Sopenharmony_ci db->in_timeout = 0; 9888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic void dm9000_send_packet(struct net_device *dev, 9928c2ecf20Sopenharmony_ci int ip_summed, 9938c2ecf20Sopenharmony_ci u16 pkt_len) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* The DM9000 is not smart enough to leave fragmented packets alone. */ 9988c2ecf20Sopenharmony_ci if (dm->ip_summed != ip_summed) { 9998c2ecf20Sopenharmony_ci if (ip_summed == CHECKSUM_NONE) 10008c2ecf20Sopenharmony_ci iow(dm, DM9000_TCCR, 0); 10018c2ecf20Sopenharmony_ci else 10028c2ecf20Sopenharmony_ci iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP); 10038c2ecf20Sopenharmony_ci dm->ip_summed = ip_summed; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* Set TX length to DM9000 */ 10078c2ecf20Sopenharmony_ci iow(dm, DM9000_TXPLL, pkt_len); 10088c2ecf20Sopenharmony_ci iow(dm, DM9000_TXPLH, pkt_len >> 8); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* Issue TX polling command */ 10118c2ecf20Sopenharmony_ci iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/* 10158c2ecf20Sopenharmony_ci * Hardware start transmission. 10168c2ecf20Sopenharmony_ci * Send a packet to media from the upper layer. 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_cistatic int 10198c2ecf20Sopenharmony_cidm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci unsigned long flags; 10228c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci dm9000_dbg(db, 3, "%s:\n", __func__); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (db->tx_pkt_cnt > 1) 10278c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* Move data to DM9000 TX RAM */ 10328c2ecf20Sopenharmony_ci writeb(DM9000_MWCMD, db->io_addr); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci (db->outblk)(db->io_data, skb->data, skb->len); 10358c2ecf20Sopenharmony_ci dev->stats.tx_bytes += skb->len; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci db->tx_pkt_cnt++; 10388c2ecf20Sopenharmony_ci /* TX control: First packet immediately send, second packet queue */ 10398c2ecf20Sopenharmony_ci if (db->tx_pkt_cnt == 1) { 10408c2ecf20Sopenharmony_ci dm9000_send_packet(dev, skb->ip_summed, skb->len); 10418c2ecf20Sopenharmony_ci } else { 10428c2ecf20Sopenharmony_ci /* Second packet */ 10438c2ecf20Sopenharmony_ci db->queue_pkt_len = skb->len; 10448c2ecf20Sopenharmony_ci db->queue_ip_summed = skb->ip_summed; 10458c2ecf20Sopenharmony_ci netif_stop_queue(dev); 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* free this SKB */ 10518c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci/* 10578c2ecf20Sopenharmony_ci * DM9000 interrupt handler 10588c2ecf20Sopenharmony_ci * receive the packet to upper layer, free the transmitted packet 10598c2ecf20Sopenharmony_ci */ 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic void dm9000_tx_done(struct net_device *dev, struct board_info *db) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci int tx_status = ior(db, DM9000_NSR); /* Got TX status */ 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (tx_status & (NSR_TX2END | NSR_TX1END)) { 10668c2ecf20Sopenharmony_ci /* One packet sent complete */ 10678c2ecf20Sopenharmony_ci db->tx_pkt_cnt--; 10688c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (netif_msg_tx_done(db)) 10718c2ecf20Sopenharmony_ci dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Queue packet check & send */ 10748c2ecf20Sopenharmony_ci if (db->tx_pkt_cnt > 0) 10758c2ecf20Sopenharmony_ci dm9000_send_packet(dev, db->queue_ip_summed, 10768c2ecf20Sopenharmony_ci db->queue_pkt_len); 10778c2ecf20Sopenharmony_ci netif_wake_queue(dev); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistruct dm9000_rxhdr { 10828c2ecf20Sopenharmony_ci u8 RxPktReady; 10838c2ecf20Sopenharmony_ci u8 RxStatus; 10848c2ecf20Sopenharmony_ci __le16 RxLen; 10858c2ecf20Sopenharmony_ci} __packed; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci/* 10888c2ecf20Sopenharmony_ci * Received a packet and pass to upper layer 10898c2ecf20Sopenharmony_ci */ 10908c2ecf20Sopenharmony_cistatic void 10918c2ecf20Sopenharmony_cidm9000_rx(struct net_device *dev) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 10948c2ecf20Sopenharmony_ci struct dm9000_rxhdr rxhdr; 10958c2ecf20Sopenharmony_ci struct sk_buff *skb; 10968c2ecf20Sopenharmony_ci u8 rxbyte, *rdptr; 10978c2ecf20Sopenharmony_ci bool GoodPacket; 10988c2ecf20Sopenharmony_ci int RxLen; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* Check packet ready or not */ 11018c2ecf20Sopenharmony_ci do { 11028c2ecf20Sopenharmony_ci ior(db, DM9000_MRCMDX); /* Dummy read */ 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* Get most updated data */ 11058c2ecf20Sopenharmony_ci rxbyte = readb(db->io_data); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* Status check: this byte must be 0 or 1 */ 11088c2ecf20Sopenharmony_ci if (rxbyte & DM9000_PKT_ERR) { 11098c2ecf20Sopenharmony_ci dev_warn(db->dev, "status check fail: %d\n", rxbyte); 11108c2ecf20Sopenharmony_ci iow(db, DM9000_RCR, 0x00); /* Stop Device */ 11118c2ecf20Sopenharmony_ci return; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (!(rxbyte & DM9000_PKT_RDY)) 11158c2ecf20Sopenharmony_ci return; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* A packet ready now & Get status/length */ 11188c2ecf20Sopenharmony_ci GoodPacket = true; 11198c2ecf20Sopenharmony_ci writeb(DM9000_MRCMD, db->io_addr); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci RxLen = le16_to_cpu(rxhdr.RxLen); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (netif_msg_rx_status(db)) 11268c2ecf20Sopenharmony_ci dev_dbg(db->dev, "RX: status %02x, length %04x\n", 11278c2ecf20Sopenharmony_ci rxhdr.RxStatus, RxLen); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* Packet Status check */ 11308c2ecf20Sopenharmony_ci if (RxLen < 0x40) { 11318c2ecf20Sopenharmony_ci GoodPacket = false; 11328c2ecf20Sopenharmony_ci if (netif_msg_rx_err(db)) 11338c2ecf20Sopenharmony_ci dev_dbg(db->dev, "RX: Bad Packet (runt)\n"); 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (RxLen > DM9000_PKT_MAX) { 11378c2ecf20Sopenharmony_ci dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen); 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci /* rxhdr.RxStatus is identical to RSR register. */ 11418c2ecf20Sopenharmony_ci if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE | 11428c2ecf20Sopenharmony_ci RSR_PLE | RSR_RWTO | 11438c2ecf20Sopenharmony_ci RSR_LCS | RSR_RF)) { 11448c2ecf20Sopenharmony_ci GoodPacket = false; 11458c2ecf20Sopenharmony_ci if (rxhdr.RxStatus & RSR_FOE) { 11468c2ecf20Sopenharmony_ci if (netif_msg_rx_err(db)) 11478c2ecf20Sopenharmony_ci dev_dbg(db->dev, "fifo error\n"); 11488c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci if (rxhdr.RxStatus & RSR_CE) { 11518c2ecf20Sopenharmony_ci if (netif_msg_rx_err(db)) 11528c2ecf20Sopenharmony_ci dev_dbg(db->dev, "crc error\n"); 11538c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci if (rxhdr.RxStatus & RSR_RF) { 11568c2ecf20Sopenharmony_ci if (netif_msg_rx_err(db)) 11578c2ecf20Sopenharmony_ci dev_dbg(db->dev, "length error\n"); 11588c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* Move data from DM9000 */ 11638c2ecf20Sopenharmony_ci if (GoodPacket && 11648c2ecf20Sopenharmony_ci ((skb = netdev_alloc_skb(dev, RxLen + 4)) != NULL)) { 11658c2ecf20Sopenharmony_ci skb_reserve(skb, 2); 11668c2ecf20Sopenharmony_ci rdptr = skb_put(skb, RxLen - 4); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* Read received packet from RX SRAM */ 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci (db->inblk)(db->io_data, rdptr, RxLen); 11718c2ecf20Sopenharmony_ci dev->stats.rx_bytes += RxLen; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* Pass to upper layer */ 11748c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 11758c2ecf20Sopenharmony_ci if (dev->features & NETIF_F_RXCSUM) { 11768c2ecf20Sopenharmony_ci if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) 11778c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 11788c2ecf20Sopenharmony_ci else 11798c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci netif_rx(skb); 11828c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci } else { 11858c2ecf20Sopenharmony_ci /* need to dump the packet's data */ 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci (db->dumpblk)(db->io_data, RxLen); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci } while (rxbyte & DM9000_PKT_RDY); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic irqreturn_t dm9000_interrupt(int irq, void *dev_id) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 11958c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 11968c2ecf20Sopenharmony_ci int int_status; 11978c2ecf20Sopenharmony_ci unsigned long flags; 11988c2ecf20Sopenharmony_ci u8 reg_save; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci dm9000_dbg(db, 3, "entering %s\n", __func__); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* A real interrupt coming */ 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* holders of db->lock must always block IRQs */ 12058c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci /* Save previous register address */ 12088c2ecf20Sopenharmony_ci reg_save = readb(db->io_addr); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci dm9000_mask_interrupts(db); 12118c2ecf20Sopenharmony_ci /* Got DM9000 interrupt status */ 12128c2ecf20Sopenharmony_ci int_status = ior(db, DM9000_ISR); /* Got ISR */ 12138c2ecf20Sopenharmony_ci iow(db, DM9000_ISR, int_status); /* Clear ISR status */ 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (netif_msg_intr(db)) 12168c2ecf20Sopenharmony_ci dev_dbg(db->dev, "interrupt status %02x\n", int_status); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* Received the coming packet */ 12198c2ecf20Sopenharmony_ci if (int_status & ISR_PRS) 12208c2ecf20Sopenharmony_ci dm9000_rx(dev); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci /* Transmit Interrupt check */ 12238c2ecf20Sopenharmony_ci if (int_status & ISR_PTS) 12248c2ecf20Sopenharmony_ci dm9000_tx_done(dev, db); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (db->type != TYPE_DM9000E) { 12278c2ecf20Sopenharmony_ci if (int_status & ISR_LNKCHNG) { 12288c2ecf20Sopenharmony_ci /* fire a link-change request */ 12298c2ecf20Sopenharmony_ci schedule_delayed_work(&db->phy_poll, 1); 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci dm9000_unmask_interrupts(db); 12348c2ecf20Sopenharmony_ci /* Restore previous register address */ 12358c2ecf20Sopenharmony_ci writeb(reg_save, db->io_addr); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cistatic irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 12458c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 12468c2ecf20Sopenharmony_ci unsigned long flags; 12478c2ecf20Sopenharmony_ci unsigned nsr, wcr; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci nsr = ior(db, DM9000_NSR); 12528c2ecf20Sopenharmony_ci wcr = ior(db, DM9000_WCR); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci dev_dbg(db->dev, "%s: NSR=0x%02x, WCR=0x%02x\n", __func__, nsr, wcr); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (nsr & NSR_WAKEST) { 12578c2ecf20Sopenharmony_ci /* clear, so we can avoid */ 12588c2ecf20Sopenharmony_ci iow(db, DM9000_NSR, NSR_WAKEST); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (wcr & WCR_LINKST) 12618c2ecf20Sopenharmony_ci dev_info(db->dev, "wake by link status change\n"); 12628c2ecf20Sopenharmony_ci if (wcr & WCR_SAMPLEST) 12638c2ecf20Sopenharmony_ci dev_info(db->dev, "wake by sample packet\n"); 12648c2ecf20Sopenharmony_ci if (wcr & WCR_MAGICST) 12658c2ecf20Sopenharmony_ci dev_info(db->dev, "wake by magic packet\n"); 12668c2ecf20Sopenharmony_ci if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST))) 12678c2ecf20Sopenharmony_ci dev_err(db->dev, "wake signalled with no reason? " 12688c2ecf20Sopenharmony_ci "NSR=0x%02x, WSR=0x%02x\n", nsr, wcr); 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return (nsr & NSR_WAKEST) ? IRQ_HANDLED : IRQ_NONE; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 12778c2ecf20Sopenharmony_ci/* 12788c2ecf20Sopenharmony_ci *Used by netconsole 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_cistatic void dm9000_poll_controller(struct net_device *dev) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci disable_irq(dev->irq); 12838c2ecf20Sopenharmony_ci dm9000_interrupt(dev->irq, dev); 12848c2ecf20Sopenharmony_ci enable_irq(dev->irq); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci#endif 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci/* 12898c2ecf20Sopenharmony_ci * Open the interface. 12908c2ecf20Sopenharmony_ci * The interface is opened whenever "ifconfig" actives it. 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_cistatic int 12938c2ecf20Sopenharmony_cidm9000_open(struct net_device *dev) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 12968c2ecf20Sopenharmony_ci unsigned int irq_flags = irq_get_trigger_type(dev->irq); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (netif_msg_ifup(db)) 12998c2ecf20Sopenharmony_ci dev_dbg(db->dev, "enabling %s\n", dev->name); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci /* If there is no IRQ type specified, tell the user that this is a 13028c2ecf20Sopenharmony_ci * problem 13038c2ecf20Sopenharmony_ci */ 13048c2ecf20Sopenharmony_ci if (irq_flags == IRQF_TRIGGER_NONE) 13058c2ecf20Sopenharmony_ci dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci irq_flags |= IRQF_SHARED; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */ 13108c2ecf20Sopenharmony_ci iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ 13118c2ecf20Sopenharmony_ci mdelay(1); /* delay needs by DM9000B */ 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* Initialize DM9000 board */ 13148c2ecf20Sopenharmony_ci dm9000_init_dm9000(dev); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (request_irq(dev->irq, dm9000_interrupt, irq_flags, dev->name, dev)) 13178c2ecf20Sopenharmony_ci return -EAGAIN; 13188c2ecf20Sopenharmony_ci /* Now that we have an interrupt handler hooked up we can unmask 13198c2ecf20Sopenharmony_ci * our interrupts 13208c2ecf20Sopenharmony_ci */ 13218c2ecf20Sopenharmony_ci dm9000_unmask_interrupts(db); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* Init driver variable */ 13248c2ecf20Sopenharmony_ci db->dbug_cnt = 0; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci mii_check_media(&db->mii, netif_msg_link(db), 1); 13278c2ecf20Sopenharmony_ci netif_start_queue(dev); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci /* Poll initial link status */ 13308c2ecf20Sopenharmony_ci schedule_delayed_work(&db->phy_poll, 1); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci return 0; 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic void 13368c2ecf20Sopenharmony_cidm9000_shutdown(struct net_device *dev) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(dev); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* RESET device */ 13418c2ecf20Sopenharmony_ci dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ 13428c2ecf20Sopenharmony_ci iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */ 13438c2ecf20Sopenharmony_ci dm9000_mask_interrupts(db); 13448c2ecf20Sopenharmony_ci iow(db, DM9000_RCR, 0x00); /* Disable RX */ 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci/* 13488c2ecf20Sopenharmony_ci * Stop the interface. 13498c2ecf20Sopenharmony_ci * The interface is stopped when it is brought. 13508c2ecf20Sopenharmony_ci */ 13518c2ecf20Sopenharmony_cistatic int 13528c2ecf20Sopenharmony_cidm9000_stop(struct net_device *ndev) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(ndev); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (netif_msg_ifdown(db)) 13578c2ecf20Sopenharmony_ci dev_dbg(db->dev, "shutting down %s\n", ndev->name); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&db->phy_poll); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 13628c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* free interrupt */ 13658c2ecf20Sopenharmony_ci free_irq(ndev->irq, ndev); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci dm9000_shutdown(ndev); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci return 0; 13708c2ecf20Sopenharmony_ci} 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_cistatic const struct net_device_ops dm9000_netdev_ops = { 13738c2ecf20Sopenharmony_ci .ndo_open = dm9000_open, 13748c2ecf20Sopenharmony_ci .ndo_stop = dm9000_stop, 13758c2ecf20Sopenharmony_ci .ndo_start_xmit = dm9000_start_xmit, 13768c2ecf20Sopenharmony_ci .ndo_tx_timeout = dm9000_timeout, 13778c2ecf20Sopenharmony_ci .ndo_set_rx_mode = dm9000_hash_table, 13788c2ecf20Sopenharmony_ci .ndo_do_ioctl = dm9000_ioctl, 13798c2ecf20Sopenharmony_ci .ndo_set_features = dm9000_set_features, 13808c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 13818c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 13828c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 13838c2ecf20Sopenharmony_ci .ndo_poll_controller = dm9000_poll_controller, 13848c2ecf20Sopenharmony_ci#endif 13858c2ecf20Sopenharmony_ci}; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic struct dm9000_plat_data *dm9000_parse_dt(struct device *dev) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct dm9000_plat_data *pdata; 13908c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 13918c2ecf20Sopenharmony_ci const void *mac_addr; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_OF) || !np) 13948c2ecf20Sopenharmony_ci return ERR_PTR(-ENXIO); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 13978c2ecf20Sopenharmony_ci if (!pdata) 13988c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (of_find_property(np, "davicom,ext-phy", NULL)) 14018c2ecf20Sopenharmony_ci pdata->flags |= DM9000_PLATF_EXT_PHY; 14028c2ecf20Sopenharmony_ci if (of_find_property(np, "davicom,no-eeprom", NULL)) 14038c2ecf20Sopenharmony_ci pdata->flags |= DM9000_PLATF_NO_EEPROM; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci mac_addr = of_get_mac_address(np); 14068c2ecf20Sopenharmony_ci if (!IS_ERR(mac_addr)) 14078c2ecf20Sopenharmony_ci ether_addr_copy(pdata->dev_addr, mac_addr); 14088c2ecf20Sopenharmony_ci else if (PTR_ERR(mac_addr) == -EPROBE_DEFER) 14098c2ecf20Sopenharmony_ci return ERR_CAST(mac_addr); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci return pdata; 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci/* 14158c2ecf20Sopenharmony_ci * Search DM9000 board, allocate space and register it 14168c2ecf20Sopenharmony_ci */ 14178c2ecf20Sopenharmony_cistatic int 14188c2ecf20Sopenharmony_cidm9000_probe(struct platform_device *pdev) 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci struct dm9000_plat_data *pdata = dev_get_platdata(&pdev->dev); 14218c2ecf20Sopenharmony_ci struct board_info *db; /* Point a board information structure */ 14228c2ecf20Sopenharmony_ci struct net_device *ndev; 14238c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 14248c2ecf20Sopenharmony_ci const unsigned char *mac_src; 14258c2ecf20Sopenharmony_ci int ret = 0; 14268c2ecf20Sopenharmony_ci int iosize; 14278c2ecf20Sopenharmony_ci int i; 14288c2ecf20Sopenharmony_ci u32 id_val; 14298c2ecf20Sopenharmony_ci int reset_gpios; 14308c2ecf20Sopenharmony_ci enum of_gpio_flags flags; 14318c2ecf20Sopenharmony_ci struct regulator *power; 14328c2ecf20Sopenharmony_ci bool inv_mac_addr = false; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci power = devm_regulator_get(dev, "vcc"); 14358c2ecf20Sopenharmony_ci if (IS_ERR(power)) { 14368c2ecf20Sopenharmony_ci if (PTR_ERR(power) == -EPROBE_DEFER) 14378c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 14388c2ecf20Sopenharmony_ci dev_dbg(dev, "no regulator provided\n"); 14398c2ecf20Sopenharmony_ci } else { 14408c2ecf20Sopenharmony_ci ret = regulator_enable(power); 14418c2ecf20Sopenharmony_ci if (ret != 0) { 14428c2ecf20Sopenharmony_ci dev_err(dev, 14438c2ecf20Sopenharmony_ci "Failed to enable power regulator: %d\n", ret); 14448c2ecf20Sopenharmony_ci return ret; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci dev_dbg(dev, "regulator enabled\n"); 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci reset_gpios = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0, 14508c2ecf20Sopenharmony_ci &flags); 14518c2ecf20Sopenharmony_ci if (gpio_is_valid(reset_gpios)) { 14528c2ecf20Sopenharmony_ci ret = devm_gpio_request_one(dev, reset_gpios, flags, 14538c2ecf20Sopenharmony_ci "dm9000_reset"); 14548c2ecf20Sopenharmony_ci if (ret) { 14558c2ecf20Sopenharmony_ci dev_err(dev, "failed to request reset gpio %d: %d\n", 14568c2ecf20Sopenharmony_ci reset_gpios, ret); 14578c2ecf20Sopenharmony_ci goto out_regulator_disable; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* According to manual PWRST# Low Period Min 1ms */ 14618c2ecf20Sopenharmony_ci msleep(2); 14628c2ecf20Sopenharmony_ci gpio_set_value(reset_gpios, 1); 14638c2ecf20Sopenharmony_ci /* Needs 3ms to read eeprom when PWRST is deasserted */ 14648c2ecf20Sopenharmony_ci msleep(4); 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (!pdata) { 14688c2ecf20Sopenharmony_ci pdata = dm9000_parse_dt(&pdev->dev); 14698c2ecf20Sopenharmony_ci if (IS_ERR(pdata)) { 14708c2ecf20Sopenharmony_ci ret = PTR_ERR(pdata); 14718c2ecf20Sopenharmony_ci goto out_regulator_disable; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* Init network device */ 14768c2ecf20Sopenharmony_ci ndev = alloc_etherdev(sizeof(struct board_info)); 14778c2ecf20Sopenharmony_ci if (!ndev) { 14788c2ecf20Sopenharmony_ci ret = -ENOMEM; 14798c2ecf20Sopenharmony_ci goto out_regulator_disable; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "dm9000_probe()\n"); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* setup board info structure */ 14878c2ecf20Sopenharmony_ci db = netdev_priv(ndev); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci db->dev = &pdev->dev; 14908c2ecf20Sopenharmony_ci db->ndev = ndev; 14918c2ecf20Sopenharmony_ci if (!IS_ERR(power)) 14928c2ecf20Sopenharmony_ci db->power_supply = power; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci spin_lock_init(&db->lock); 14958c2ecf20Sopenharmony_ci mutex_init(&db->addr_lock); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 15008c2ecf20Sopenharmony_ci db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (!db->addr_res || !db->data_res) { 15038c2ecf20Sopenharmony_ci dev_err(db->dev, "insufficient resources addr=%p data=%p\n", 15048c2ecf20Sopenharmony_ci db->addr_res, db->data_res); 15058c2ecf20Sopenharmony_ci ret = -ENOENT; 15068c2ecf20Sopenharmony_ci goto out; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci ndev->irq = platform_get_irq(pdev, 0); 15108c2ecf20Sopenharmony_ci if (ndev->irq < 0) { 15118c2ecf20Sopenharmony_ci ret = ndev->irq; 15128c2ecf20Sopenharmony_ci goto out; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci db->irq_wake = platform_get_irq_optional(pdev, 1); 15168c2ecf20Sopenharmony_ci if (db->irq_wake >= 0) { 15178c2ecf20Sopenharmony_ci dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci ret = request_irq(db->irq_wake, dm9000_wol_interrupt, 15208c2ecf20Sopenharmony_ci IRQF_SHARED, dev_name(db->dev), ndev); 15218c2ecf20Sopenharmony_ci if (ret) { 15228c2ecf20Sopenharmony_ci dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret); 15238c2ecf20Sopenharmony_ci } else { 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci /* test to see if irq is really wakeup capable */ 15268c2ecf20Sopenharmony_ci ret = irq_set_irq_wake(db->irq_wake, 1); 15278c2ecf20Sopenharmony_ci if (ret) { 15288c2ecf20Sopenharmony_ci dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", 15298c2ecf20Sopenharmony_ci db->irq_wake, ret); 15308c2ecf20Sopenharmony_ci ret = 0; 15318c2ecf20Sopenharmony_ci } else { 15328c2ecf20Sopenharmony_ci irq_set_irq_wake(db->irq_wake, 0); 15338c2ecf20Sopenharmony_ci db->wake_supported = 1; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci iosize = resource_size(db->addr_res); 15398c2ecf20Sopenharmony_ci db->addr_req = request_mem_region(db->addr_res->start, iosize, 15408c2ecf20Sopenharmony_ci pdev->name); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (db->addr_req == NULL) { 15438c2ecf20Sopenharmony_ci dev_err(db->dev, "cannot claim address reg area\n"); 15448c2ecf20Sopenharmony_ci ret = -EIO; 15458c2ecf20Sopenharmony_ci goto out; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci db->io_addr = ioremap(db->addr_res->start, iosize); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (db->io_addr == NULL) { 15518c2ecf20Sopenharmony_ci dev_err(db->dev, "failed to ioremap address reg\n"); 15528c2ecf20Sopenharmony_ci ret = -EINVAL; 15538c2ecf20Sopenharmony_ci goto out; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci iosize = resource_size(db->data_res); 15578c2ecf20Sopenharmony_ci db->data_req = request_mem_region(db->data_res->start, iosize, 15588c2ecf20Sopenharmony_ci pdev->name); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (db->data_req == NULL) { 15618c2ecf20Sopenharmony_ci dev_err(db->dev, "cannot claim data reg area\n"); 15628c2ecf20Sopenharmony_ci ret = -EIO; 15638c2ecf20Sopenharmony_ci goto out; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci db->io_data = ioremap(db->data_res->start, iosize); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci if (db->io_data == NULL) { 15698c2ecf20Sopenharmony_ci dev_err(db->dev, "failed to ioremap data reg\n"); 15708c2ecf20Sopenharmony_ci ret = -EINVAL; 15718c2ecf20Sopenharmony_ci goto out; 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci /* fill in parameters for net-dev structure */ 15758c2ecf20Sopenharmony_ci ndev->base_addr = (unsigned long)db->io_addr; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci /* ensure at least we have a default set of IO routines */ 15788c2ecf20Sopenharmony_ci dm9000_set_io(db, iosize); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* check to see if anything is being over-ridden */ 15818c2ecf20Sopenharmony_ci if (pdata != NULL) { 15828c2ecf20Sopenharmony_ci /* check to see if the driver wants to over-ride the 15838c2ecf20Sopenharmony_ci * default IO width */ 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (pdata->flags & DM9000_PLATF_8BITONLY) 15868c2ecf20Sopenharmony_ci dm9000_set_io(db, 1); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (pdata->flags & DM9000_PLATF_16BITONLY) 15898c2ecf20Sopenharmony_ci dm9000_set_io(db, 2); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci if (pdata->flags & DM9000_PLATF_32BITONLY) 15928c2ecf20Sopenharmony_ci dm9000_set_io(db, 4); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci /* check to see if there are any IO routine 15958c2ecf20Sopenharmony_ci * over-rides */ 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (pdata->inblk != NULL) 15988c2ecf20Sopenharmony_ci db->inblk = pdata->inblk; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (pdata->outblk != NULL) 16018c2ecf20Sopenharmony_ci db->outblk = pdata->outblk; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (pdata->dumpblk != NULL) 16048c2ecf20Sopenharmony_ci db->dumpblk = pdata->dumpblk; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci db->flags = pdata->flags; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL 16108c2ecf20Sopenharmony_ci db->flags |= DM9000_PLATF_SIMPLE_PHY; 16118c2ecf20Sopenharmony_ci#endif 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci dm9000_reset(db); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci /* try multiple times, DM9000 sometimes gets the read wrong */ 16168c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 16178c2ecf20Sopenharmony_ci id_val = ior(db, DM9000_VIDL); 16188c2ecf20Sopenharmony_ci id_val |= (u32)ior(db, DM9000_VIDH) << 8; 16198c2ecf20Sopenharmony_ci id_val |= (u32)ior(db, DM9000_PIDL) << 16; 16208c2ecf20Sopenharmony_ci id_val |= (u32)ior(db, DM9000_PIDH) << 24; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (id_val == DM9000_ID) 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci dev_err(db->dev, "read wrong id 0x%08x\n", id_val); 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (id_val != DM9000_ID) { 16288c2ecf20Sopenharmony_ci dev_err(db->dev, "wrong id: 0x%08x\n", id_val); 16298c2ecf20Sopenharmony_ci ret = -ENODEV; 16308c2ecf20Sopenharmony_ci goto out; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci /* Identify what type of DM9000 we are working on */ 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci id_val = ior(db, DM9000_CHIPR); 16368c2ecf20Sopenharmony_ci dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci switch (id_val) { 16398c2ecf20Sopenharmony_ci case CHIPR_DM9000A: 16408c2ecf20Sopenharmony_ci db->type = TYPE_DM9000A; 16418c2ecf20Sopenharmony_ci break; 16428c2ecf20Sopenharmony_ci case CHIPR_DM9000B: 16438c2ecf20Sopenharmony_ci db->type = TYPE_DM9000B; 16448c2ecf20Sopenharmony_ci break; 16458c2ecf20Sopenharmony_ci default: 16468c2ecf20Sopenharmony_ci dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val); 16478c2ecf20Sopenharmony_ci db->type = TYPE_DM9000E; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci /* dm9000a/b are capable of hardware checksum offload */ 16518c2ecf20Sopenharmony_ci if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { 16528c2ecf20Sopenharmony_ci ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; 16538c2ecf20Sopenharmony_ci ndev->features |= ndev->hw_features; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* from this point we assume that we have found a DM9000 */ 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci ndev->netdev_ops = &dm9000_netdev_ops; 16598c2ecf20Sopenharmony_ci ndev->watchdog_timeo = msecs_to_jiffies(watchdog); 16608c2ecf20Sopenharmony_ci ndev->ethtool_ops = &dm9000_ethtool_ops; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci db->msg_enable = NETIF_MSG_LINK; 16638c2ecf20Sopenharmony_ci db->mii.phy_id_mask = 0x1f; 16648c2ecf20Sopenharmony_ci db->mii.reg_num_mask = 0x1f; 16658c2ecf20Sopenharmony_ci db->mii.force_media = 0; 16668c2ecf20Sopenharmony_ci db->mii.full_duplex = 0; 16678c2ecf20Sopenharmony_ci db->mii.dev = ndev; 16688c2ecf20Sopenharmony_ci db->mii.mdio_read = dm9000_phy_read; 16698c2ecf20Sopenharmony_ci db->mii.mdio_write = dm9000_phy_write; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci mac_src = "eeprom"; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci /* try reading the node address from the attached EEPROM */ 16748c2ecf20Sopenharmony_ci for (i = 0; i < 6; i += 2) 16758c2ecf20Sopenharmony_ci dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) { 16788c2ecf20Sopenharmony_ci mac_src = "platform data"; 16798c2ecf20Sopenharmony_ci memcpy(ndev->dev_addr, pdata->dev_addr, ETH_ALEN); 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr)) { 16838c2ecf20Sopenharmony_ci /* try reading from mac */ 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci mac_src = "chip"; 16868c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 16878c2ecf20Sopenharmony_ci ndev->dev_addr[i] = ior(db, i+DM9000_PAR); 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr)) { 16918c2ecf20Sopenharmony_ci inv_mac_addr = true; 16928c2ecf20Sopenharmony_ci eth_hw_addr_random(ndev); 16938c2ecf20Sopenharmony_ci mac_src = "random"; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ndev); 16988c2ecf20Sopenharmony_ci ret = register_netdev(ndev); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci if (ret == 0) { 17018c2ecf20Sopenharmony_ci if (inv_mac_addr) 17028c2ecf20Sopenharmony_ci dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please set using ip\n", 17038c2ecf20Sopenharmony_ci ndev->name); 17048c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n", 17058c2ecf20Sopenharmony_ci ndev->name, dm9000_type_to_char(db->type), 17068c2ecf20Sopenharmony_ci db->io_addr, db->io_data, ndev->irq, 17078c2ecf20Sopenharmony_ci ndev->dev_addr, mac_src); 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci return 0; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ciout: 17128c2ecf20Sopenharmony_ci dev_err(db->dev, "not found (%d).\n", ret); 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci dm9000_release_board(pdev, db); 17158c2ecf20Sopenharmony_ci free_netdev(ndev); 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ciout_regulator_disable: 17188c2ecf20Sopenharmony_ci if (!IS_ERR(power)) 17198c2ecf20Sopenharmony_ci regulator_disable(power); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci return ret; 17228c2ecf20Sopenharmony_ci} 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_cistatic int 17258c2ecf20Sopenharmony_cidm9000_drv_suspend(struct device *dev) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 17288c2ecf20Sopenharmony_ci struct board_info *db; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (ndev) { 17318c2ecf20Sopenharmony_ci db = netdev_priv(ndev); 17328c2ecf20Sopenharmony_ci db->in_suspend = 1; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (!netif_running(ndev)) 17358c2ecf20Sopenharmony_ci return 0; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci netif_device_detach(ndev); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci /* only shutdown if not using WoL */ 17408c2ecf20Sopenharmony_ci if (!db->wake_state) 17418c2ecf20Sopenharmony_ci dm9000_shutdown(ndev); 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci return 0; 17448c2ecf20Sopenharmony_ci} 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_cistatic int 17478c2ecf20Sopenharmony_cidm9000_drv_resume(struct device *dev) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 17508c2ecf20Sopenharmony_ci struct board_info *db = netdev_priv(ndev); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (ndev) { 17538c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 17548c2ecf20Sopenharmony_ci /* reset if we were not in wake mode to ensure if 17558c2ecf20Sopenharmony_ci * the device was powered off it is in a known state */ 17568c2ecf20Sopenharmony_ci if (!db->wake_state) { 17578c2ecf20Sopenharmony_ci dm9000_init_dm9000(ndev); 17588c2ecf20Sopenharmony_ci dm9000_unmask_interrupts(db); 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci netif_device_attach(ndev); 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci db->in_suspend = 0; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci return 0; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dm9000_drv_pm_ops = { 17708c2ecf20Sopenharmony_ci .suspend = dm9000_drv_suspend, 17718c2ecf20Sopenharmony_ci .resume = dm9000_drv_resume, 17728c2ecf20Sopenharmony_ci}; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_cistatic int 17758c2ecf20Sopenharmony_cidm9000_drv_remove(struct platform_device *pdev) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci struct net_device *ndev = platform_get_drvdata(pdev); 17788c2ecf20Sopenharmony_ci struct board_info *dm = to_dm9000_board(ndev); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci unregister_netdev(ndev); 17818c2ecf20Sopenharmony_ci dm9000_release_board(pdev, dm); 17828c2ecf20Sopenharmony_ci free_netdev(ndev); /* free device structure */ 17838c2ecf20Sopenharmony_ci if (dm->power_supply) 17848c2ecf20Sopenharmony_ci regulator_disable(dm->power_supply); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "released and freed device\n"); 17878c2ecf20Sopenharmony_ci return 0; 17888c2ecf20Sopenharmony_ci} 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 17918c2ecf20Sopenharmony_cistatic const struct of_device_id dm9000_of_matches[] = { 17928c2ecf20Sopenharmony_ci { .compatible = "davicom,dm9000", }, 17938c2ecf20Sopenharmony_ci { /* sentinel */ } 17948c2ecf20Sopenharmony_ci}; 17958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, dm9000_of_matches); 17968c2ecf20Sopenharmony_ci#endif 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_cistatic struct platform_driver dm9000_driver = { 17998c2ecf20Sopenharmony_ci .driver = { 18008c2ecf20Sopenharmony_ci .name = "dm9000", 18018c2ecf20Sopenharmony_ci .pm = &dm9000_drv_pm_ops, 18028c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(dm9000_of_matches), 18038c2ecf20Sopenharmony_ci }, 18048c2ecf20Sopenharmony_ci .probe = dm9000_probe, 18058c2ecf20Sopenharmony_ci .remove = dm9000_drv_remove, 18068c2ecf20Sopenharmony_ci}; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cimodule_platform_driver(dm9000_driver); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sascha Hauer, Ben Dooks"); 18118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Davicom DM9000 network driver"); 18128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 18138c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:dm9000"); 1814