162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Davicom DM9000 Fast Ethernet driver for Linux. 462306a36Sopenharmony_ci * Copyright (C) 1997 Sten Wang 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * (C) Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Additional updates, Copyright: 962306a36Sopenharmony_ci * Ben Dooks <ben@simtec.co.uk> 1062306a36Sopenharmony_ci * Sascha Hauer <s.hauer@pengutronix.de> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/ioport.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include <linux/etherdevice.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/skbuff.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <linux/crc32.h> 2162306a36Sopenharmony_ci#include <linux/mii.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <linux/of_net.h> 2462306a36Sopenharmony_ci#include <linux/ethtool.h> 2562306a36Sopenharmony_ci#include <linux/dm9000.h> 2662306a36Sopenharmony_ci#include <linux/delay.h> 2762306a36Sopenharmony_ci#include <linux/platform_device.h> 2862306a36Sopenharmony_ci#include <linux/irq.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 3162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <asm/delay.h> 3462306a36Sopenharmony_ci#include <asm/irq.h> 3562306a36Sopenharmony_ci#include <asm/io.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "dm9000.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Board/System/Debug information/definition ---------------- */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define DM9000_PHY 0x40 /* PHY address 0x01 */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define CARDNAME "dm9000" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * Transmit timeout, default 5 seconds. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic int watchdog = 5000; 4962306a36Sopenharmony_cimodule_param(watchdog, int, 0400); 5062306a36Sopenharmony_ciMODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * Debug messages level 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic int debug; 5662306a36Sopenharmony_cimodule_param(debug, int, 0644); 5762306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "dm9000 debug level (0-6)"); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* DM9000 register address locking. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * The DM9000 uses an address register to control where data written 6262306a36Sopenharmony_ci * to the data register goes. This means that the address register 6362306a36Sopenharmony_ci * must be preserved over interrupts or similar calls. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * During interrupt and other critical calls, a spinlock is used to 6662306a36Sopenharmony_ci * protect the system, but the calls themselves save the address 6762306a36Sopenharmony_ci * in the address register in case they are interrupting another 6862306a36Sopenharmony_ci * access to the device. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * For general accesses a lock is provided so that calls which are 7162306a36Sopenharmony_ci * allowed to sleep are serialised so that the address register does 7262306a36Sopenharmony_ci * not need to be saved. This lock also serves to serialise access 7362306a36Sopenharmony_ci * to the EEPROM and PHY access registers which are shared between 7462306a36Sopenharmony_ci * these two devices. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* The driver supports the original DM9000E, and now the two newer 7862306a36Sopenharmony_ci * devices, DM9000A and DM9000B. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cienum dm9000_type { 8262306a36Sopenharmony_ci TYPE_DM9000E, /* original DM9000 */ 8362306a36Sopenharmony_ci TYPE_DM9000A, 8462306a36Sopenharmony_ci TYPE_DM9000B 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Structure/enum declaration ------------------------------- */ 8862306a36Sopenharmony_cistruct board_info { 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci void __iomem *io_addr; /* Register I/O base address */ 9162306a36Sopenharmony_ci void __iomem *io_data; /* Data I/O address */ 9262306a36Sopenharmony_ci u16 irq; /* IRQ */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci u16 tx_pkt_cnt; 9562306a36Sopenharmony_ci u16 queue_pkt_len; 9662306a36Sopenharmony_ci u16 queue_start_addr; 9762306a36Sopenharmony_ci u16 queue_ip_summed; 9862306a36Sopenharmony_ci u16 dbug_cnt; 9962306a36Sopenharmony_ci u8 io_mode; /* 0:word, 2:byte */ 10062306a36Sopenharmony_ci u8 phy_addr; 10162306a36Sopenharmony_ci u8 imr_all; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci unsigned int flags; 10462306a36Sopenharmony_ci unsigned int in_timeout:1; 10562306a36Sopenharmony_ci unsigned int in_suspend:1; 10662306a36Sopenharmony_ci unsigned int wake_supported:1; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci enum dm9000_type type; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci void (*inblk)(void __iomem *port, void *data, int length); 11162306a36Sopenharmony_ci void (*outblk)(void __iomem *port, void *data, int length); 11262306a36Sopenharmony_ci void (*dumpblk)(void __iomem *port, int length); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci struct device *dev; /* parent device */ 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci struct resource *addr_res; /* resources found */ 11762306a36Sopenharmony_ci struct resource *data_res; 11862306a36Sopenharmony_ci struct resource *addr_req; /* resources requested */ 11962306a36Sopenharmony_ci struct resource *data_req; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci int irq_wake; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci struct mutex addr_lock; /* phy and eeprom access lock */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci struct delayed_work phy_poll; 12662306a36Sopenharmony_ci struct net_device *ndev; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci spinlock_t lock; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci struct mii_if_info mii; 13162306a36Sopenharmony_ci u32 msg_enable; 13262306a36Sopenharmony_ci u32 wake_state; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci int ip_summed; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci struct regulator *power_supply; 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* debug code */ 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#define dm9000_dbg(db, lev, msg...) do { \ 14262306a36Sopenharmony_ci if ((lev) < debug) { \ 14362306a36Sopenharmony_ci dev_dbg(db->dev, msg); \ 14462306a36Sopenharmony_ci } \ 14562306a36Sopenharmony_ci} while (0) 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic inline struct board_info *to_dm9000_board(struct net_device *dev) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci return netdev_priv(dev); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* DM9000 network board routine ---------------------------- */ 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * Read a byte from I/O port 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic u8 15862306a36Sopenharmony_ciior(struct board_info *db, int reg) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci writeb(reg, db->io_addr); 16162306a36Sopenharmony_ci return readb(db->io_data); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * Write a byte to I/O port 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void 16962306a36Sopenharmony_ciiow(struct board_info *db, int reg, int value) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci writeb(reg, db->io_addr); 17262306a36Sopenharmony_ci writeb(value, db->io_data); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic void 17662306a36Sopenharmony_cidm9000_reset(struct board_info *db) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci dev_dbg(db->dev, "resetting device\n"); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 18162306a36Sopenharmony_ci * The essential point is that we have to do a double reset, and the 18262306a36Sopenharmony_ci * instruction is to set LBK into MAC internal loopback mode. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); 18562306a36Sopenharmony_ci udelay(100); /* Application note says at least 20 us */ 18662306a36Sopenharmony_ci if (ior(db, DM9000_NCR) & 1) 18762306a36Sopenharmony_ci dev_err(db->dev, "dm9000 did not respond to first reset\n"); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci iow(db, DM9000_NCR, 0); 19062306a36Sopenharmony_ci iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); 19162306a36Sopenharmony_ci udelay(100); 19262306a36Sopenharmony_ci if (ior(db, DM9000_NCR) & 1) 19362306a36Sopenharmony_ci dev_err(db->dev, "dm9000 did not respond to second reset\n"); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* routines for sending block to chip */ 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void dm9000_outblk_8bit(void __iomem *reg, void *data, int count) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci iowrite8_rep(reg, data, count); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void dm9000_outblk_16bit(void __iomem *reg, void *data, int count) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci iowrite16_rep(reg, data, (count+1) >> 1); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void dm9000_outblk_32bit(void __iomem *reg, void *data, int count) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci iowrite32_rep(reg, data, (count+3) >> 2); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* input block from chip to memory */ 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void dm9000_inblk_8bit(void __iomem *reg, void *data, int count) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci ioread8_rep(reg, data, count); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void dm9000_inblk_16bit(void __iomem *reg, void *data, int count) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci ioread16_rep(reg, data, (count+1) >> 1); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic void dm9000_inblk_32bit(void __iomem *reg, void *data, int count) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci ioread32_rep(reg, data, (count+3) >> 2); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* dump block from chip to null */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void dm9000_dumpblk_8bit(void __iomem *reg, int count) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci int i; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci for (i = 0; i < count; i++) 23862306a36Sopenharmony_ci readb(reg); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void dm9000_dumpblk_16bit(void __iomem *reg, int count) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci int i; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci count = (count + 1) >> 1; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci for (i = 0; i < count; i++) 24862306a36Sopenharmony_ci readw(reg); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void dm9000_dumpblk_32bit(void __iomem *reg, int count) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci int i; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci count = (count + 3) >> 2; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < count; i++) 25862306a36Sopenharmony_ci readl(reg); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* 26262306a36Sopenharmony_ci * Sleep, either by using msleep() or if we are suspending, then 26362306a36Sopenharmony_ci * use mdelay() to sleep. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_cistatic void dm9000_msleep(struct board_info *db, unsigned int ms) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci if (db->in_suspend || db->in_timeout) 26862306a36Sopenharmony_ci mdelay(ms); 26962306a36Sopenharmony_ci else 27062306a36Sopenharmony_ci msleep(ms); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* Read a word from phyxcer */ 27462306a36Sopenharmony_cistatic int 27562306a36Sopenharmony_cidm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 27862306a36Sopenharmony_ci unsigned long flags; 27962306a36Sopenharmony_ci unsigned int reg_save; 28062306a36Sopenharmony_ci int ret; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci mutex_lock(&db->addr_lock); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Save previous register address */ 28762306a36Sopenharmony_ci reg_save = readb(db->io_addr); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Fill the phyxcer register into REG_0C */ 29062306a36Sopenharmony_ci iow(db, DM9000_EPAR, DM9000_PHY | reg); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Issue phyxcer read command */ 29362306a36Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci writeb(reg_save, db->io_addr); 29662306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci dm9000_msleep(db, 1); /* Wait read complete */ 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 30162306a36Sopenharmony_ci reg_save = readb(db->io_addr); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* The read data keeps on REG_0D & REG_0E */ 30662306a36Sopenharmony_ci ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* restore the previous address */ 30962306a36Sopenharmony_ci writeb(reg_save, db->io_addr); 31062306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci mutex_unlock(&db->addr_lock); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret); 31562306a36Sopenharmony_ci return ret; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* Write a word to phyxcer */ 31962306a36Sopenharmony_cistatic void 32062306a36Sopenharmony_cidm9000_phy_write(struct net_device *dev, 32162306a36Sopenharmony_ci int phyaddr_unused, int reg, int value) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 32462306a36Sopenharmony_ci unsigned long flags; 32562306a36Sopenharmony_ci unsigned long reg_save; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); 32862306a36Sopenharmony_ci if (!db->in_timeout) 32962306a36Sopenharmony_ci mutex_lock(&db->addr_lock); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Save previous register address */ 33462306a36Sopenharmony_ci reg_save = readb(db->io_addr); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Fill the phyxcer register into REG_0C */ 33762306a36Sopenharmony_ci iow(db, DM9000_EPAR, DM9000_PHY | reg); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* Fill the written data into REG_0D & REG_0E */ 34062306a36Sopenharmony_ci iow(db, DM9000_EPDRL, value); 34162306a36Sopenharmony_ci iow(db, DM9000_EPDRH, value >> 8); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Issue phyxcer write command */ 34462306a36Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci writeb(reg_save, db->io_addr); 34762306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci dm9000_msleep(db, 1); /* Wait write complete */ 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 35262306a36Sopenharmony_ci reg_save = readb(db->io_addr); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* restore the previous address */ 35762306a36Sopenharmony_ci writeb(reg_save, db->io_addr); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 36062306a36Sopenharmony_ci if (!db->in_timeout) 36162306a36Sopenharmony_ci mutex_unlock(&db->addr_lock); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/* dm9000_set_io 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * select the specified set of io routines to use with the 36762306a36Sopenharmony_ci * device 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void dm9000_set_io(struct board_info *db, int byte_width) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci /* use the size of the data resource to work out what IO 37362306a36Sopenharmony_ci * routines we want to use 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci switch (byte_width) { 37762306a36Sopenharmony_ci case 1: 37862306a36Sopenharmony_ci db->dumpblk = dm9000_dumpblk_8bit; 37962306a36Sopenharmony_ci db->outblk = dm9000_outblk_8bit; 38062306a36Sopenharmony_ci db->inblk = dm9000_inblk_8bit; 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci case 3: 38562306a36Sopenharmony_ci dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n"); 38662306a36Sopenharmony_ci fallthrough; 38762306a36Sopenharmony_ci case 2: 38862306a36Sopenharmony_ci db->dumpblk = dm9000_dumpblk_16bit; 38962306a36Sopenharmony_ci db->outblk = dm9000_outblk_16bit; 39062306a36Sopenharmony_ci db->inblk = dm9000_inblk_16bit; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci case 4: 39462306a36Sopenharmony_ci default: 39562306a36Sopenharmony_ci db->dumpblk = dm9000_dumpblk_32bit; 39662306a36Sopenharmony_ci db->outblk = dm9000_outblk_32bit; 39762306a36Sopenharmony_ci db->inblk = dm9000_inblk_32bit; 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void dm9000_schedule_poll(struct board_info *db) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci if (db->type == TYPE_DM9000E) 40562306a36Sopenharmony_ci schedule_delayed_work(&db->phy_poll, HZ * 2); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!netif_running(dev)) 41362306a36Sopenharmony_ci return -EINVAL; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic unsigned int 41962306a36Sopenharmony_cidm9000_read_locked(struct board_info *db, int reg) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci unsigned long flags; 42262306a36Sopenharmony_ci unsigned int ret; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 42562306a36Sopenharmony_ci ret = ior(db, reg); 42662306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int dm9000_wait_eeprom(struct board_info *db) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci unsigned int status; 43462306a36Sopenharmony_ci int timeout = 8; /* wait max 8msec */ 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* The DM9000 data sheets say we should be able to 43762306a36Sopenharmony_ci * poll the ERRE bit in EPCR to wait for the EEPROM 43862306a36Sopenharmony_ci * operation. From testing several chips, this bit 43962306a36Sopenharmony_ci * does not seem to work. 44062306a36Sopenharmony_ci * 44162306a36Sopenharmony_ci * We attempt to use the bit, but fall back to the 44262306a36Sopenharmony_ci * timeout (which is why we do not return an error 44362306a36Sopenharmony_ci * on expiry) to say that the EEPROM operation has 44462306a36Sopenharmony_ci * completed. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci while (1) { 44862306a36Sopenharmony_ci status = dm9000_read_locked(db, DM9000_EPCR); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if ((status & EPCR_ERRE) == 0) 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci msleep(1); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (timeout-- < 0) { 45662306a36Sopenharmony_ci dev_dbg(db->dev, "timeout waiting EEPROM\n"); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/* 46562306a36Sopenharmony_ci * Read a word data from EEPROM 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_cistatic void 46862306a36Sopenharmony_cidm9000_read_eeprom(struct board_info *db, int offset, u8 *to) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci unsigned long flags; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (db->flags & DM9000_PLATF_NO_EEPROM) { 47362306a36Sopenharmony_ci to[0] = 0xff; 47462306a36Sopenharmony_ci to[1] = 0xff; 47562306a36Sopenharmony_ci return; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mutex_lock(&db->addr_lock); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci iow(db, DM9000_EPAR, offset); 48362306a36Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_ERPRR); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci dm9000_wait_eeprom(db); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* delay for at-least 150uS */ 49062306a36Sopenharmony_ci msleep(1); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci iow(db, DM9000_EPCR, 0x0); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci to[0] = ior(db, DM9000_EPDRL); 49762306a36Sopenharmony_ci to[1] = ior(db, DM9000_EPDRH); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci mutex_unlock(&db->addr_lock); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* 50562306a36Sopenharmony_ci * Write a word data to SROM 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_cistatic void 50862306a36Sopenharmony_cidm9000_write_eeprom(struct board_info *db, int offset, u8 *data) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci unsigned long flags; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (db->flags & DM9000_PLATF_NO_EEPROM) 51362306a36Sopenharmony_ci return; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci mutex_lock(&db->addr_lock); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 51862306a36Sopenharmony_ci iow(db, DM9000_EPAR, offset); 51962306a36Sopenharmony_ci iow(db, DM9000_EPDRH, data[1]); 52062306a36Sopenharmony_ci iow(db, DM9000_EPDRL, data[0]); 52162306a36Sopenharmony_ci iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); 52262306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci dm9000_wait_eeprom(db); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci mdelay(1); /* wait at least 150uS to clear */ 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 52962306a36Sopenharmony_ci iow(db, DM9000_EPCR, 0); 53062306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci mutex_unlock(&db->addr_lock); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* ethtool ops */ 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void dm9000_get_drvinfo(struct net_device *dev, 53862306a36Sopenharmony_ci struct ethtool_drvinfo *info) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci strscpy(info->driver, CARDNAME, sizeof(info->driver)); 54362306a36Sopenharmony_ci strscpy(info->bus_info, to_platform_device(dm->dev)->name, 54462306a36Sopenharmony_ci sizeof(info->bus_info)); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic u32 dm9000_get_msglevel(struct net_device *dev) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return dm->msg_enable; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void dm9000_set_msglevel(struct net_device *dev, u32 value) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci dm->msg_enable = value; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int dm9000_get_link_ksettings(struct net_device *dev, 56262306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci mii_ethtool_get_link_ksettings(&dm->mii, cmd); 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int dm9000_set_link_ksettings(struct net_device *dev, 57162306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return mii_ethtool_set_link_ksettings(&dm->mii, cmd); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int dm9000_nway_reset(struct net_device *dev) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 58162306a36Sopenharmony_ci return mii_nway_restart(&dm->mii); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int dm9000_set_features(struct net_device *dev, 58562306a36Sopenharmony_ci netdev_features_t features) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 58862306a36Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 58962306a36Sopenharmony_ci unsigned long flags; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!(changed & NETIF_F_RXCSUM)) 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci spin_lock_irqsave(&dm->lock, flags); 59562306a36Sopenharmony_ci iow(dm, DM9000_RCSR, (features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); 59662306a36Sopenharmony_ci spin_unlock_irqrestore(&dm->lock, flags); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic u32 dm9000_get_link(struct net_device *dev) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 60462306a36Sopenharmony_ci u32 ret; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (dm->flags & DM9000_PLATF_EXT_PHY) 60762306a36Sopenharmony_ci ret = mii_link_ok(&dm->mii); 60862306a36Sopenharmony_ci else 60962306a36Sopenharmony_ci ret = dm9000_read_locked(dm, DM9000_NSR) & NSR_LINKST ? 1 : 0; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return ret; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci#define DM_EEPROM_MAGIC (0x444D394B) 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic int dm9000_get_eeprom_len(struct net_device *dev) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci return 128; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int dm9000_get_eeprom(struct net_device *dev, 62262306a36Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 62562306a36Sopenharmony_ci int offset = ee->offset; 62662306a36Sopenharmony_ci int len = ee->len; 62762306a36Sopenharmony_ci int i; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* EEPROM access is aligned to two bytes */ 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if ((len & 1) != 0 || (offset & 1) != 0) 63262306a36Sopenharmony_ci return -EINVAL; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (dm->flags & DM9000_PLATF_NO_EEPROM) 63562306a36Sopenharmony_ci return -ENOENT; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci ee->magic = DM_EEPROM_MAGIC; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci for (i = 0; i < len; i += 2) 64062306a36Sopenharmony_ci dm9000_read_eeprom(dm, (offset + i) / 2, data + i); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic int dm9000_set_eeprom(struct net_device *dev, 64662306a36Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 64962306a36Sopenharmony_ci int offset = ee->offset; 65062306a36Sopenharmony_ci int len = ee->len; 65162306a36Sopenharmony_ci int done; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* EEPROM access is aligned to two bytes */ 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (dm->flags & DM9000_PLATF_NO_EEPROM) 65662306a36Sopenharmony_ci return -ENOENT; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (ee->magic != DM_EEPROM_MAGIC) 65962306a36Sopenharmony_ci return -EINVAL; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci while (len > 0) { 66262306a36Sopenharmony_ci if (len & 1 || offset & 1) { 66362306a36Sopenharmony_ci int which = offset & 1; 66462306a36Sopenharmony_ci u8 tmp[2]; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci dm9000_read_eeprom(dm, offset / 2, tmp); 66762306a36Sopenharmony_ci tmp[which] = *data; 66862306a36Sopenharmony_ci dm9000_write_eeprom(dm, offset / 2, tmp); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci done = 1; 67162306a36Sopenharmony_ci } else { 67262306a36Sopenharmony_ci dm9000_write_eeprom(dm, offset / 2, data); 67362306a36Sopenharmony_ci done = 2; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci data += done; 67762306a36Sopenharmony_ci offset += done; 67862306a36Sopenharmony_ci len -= done; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci return 0; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic void dm9000_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci memset(w, 0, sizeof(struct ethtool_wolinfo)); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* note, we could probably support wake-phy too */ 69162306a36Sopenharmony_ci w->supported = dm->wake_supported ? WAKE_MAGIC : 0; 69262306a36Sopenharmony_ci w->wolopts = dm->wake_state; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 69862306a36Sopenharmony_ci unsigned long flags; 69962306a36Sopenharmony_ci u32 opts = w->wolopts; 70062306a36Sopenharmony_ci u32 wcr = 0; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (!dm->wake_supported) 70362306a36Sopenharmony_ci return -EOPNOTSUPP; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (opts & ~WAKE_MAGIC) 70662306a36Sopenharmony_ci return -EINVAL; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (opts & WAKE_MAGIC) 70962306a36Sopenharmony_ci wcr |= WCR_MAGICEN; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci mutex_lock(&dm->addr_lock); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci spin_lock_irqsave(&dm->lock, flags); 71462306a36Sopenharmony_ci iow(dm, DM9000_WCR, wcr); 71562306a36Sopenharmony_ci spin_unlock_irqrestore(&dm->lock, flags); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci mutex_unlock(&dm->addr_lock); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (dm->wake_state != opts) { 72062306a36Sopenharmony_ci /* change in wol state, update IRQ state */ 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (!dm->wake_state) 72362306a36Sopenharmony_ci irq_set_irq_wake(dm->irq_wake, 1); 72462306a36Sopenharmony_ci else if (dm->wake_state && !opts) 72562306a36Sopenharmony_ci irq_set_irq_wake(dm->irq_wake, 0); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci dm->wake_state = opts; 72962306a36Sopenharmony_ci return 0; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic const struct ethtool_ops dm9000_ethtool_ops = { 73362306a36Sopenharmony_ci .get_drvinfo = dm9000_get_drvinfo, 73462306a36Sopenharmony_ci .get_msglevel = dm9000_get_msglevel, 73562306a36Sopenharmony_ci .set_msglevel = dm9000_set_msglevel, 73662306a36Sopenharmony_ci .nway_reset = dm9000_nway_reset, 73762306a36Sopenharmony_ci .get_link = dm9000_get_link, 73862306a36Sopenharmony_ci .get_wol = dm9000_get_wol, 73962306a36Sopenharmony_ci .set_wol = dm9000_set_wol, 74062306a36Sopenharmony_ci .get_eeprom_len = dm9000_get_eeprom_len, 74162306a36Sopenharmony_ci .get_eeprom = dm9000_get_eeprom, 74262306a36Sopenharmony_ci .set_eeprom = dm9000_set_eeprom, 74362306a36Sopenharmony_ci .get_link_ksettings = dm9000_get_link_ksettings, 74462306a36Sopenharmony_ci .set_link_ksettings = dm9000_set_link_ksettings, 74562306a36Sopenharmony_ci}; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic void dm9000_show_carrier(struct board_info *db, 74862306a36Sopenharmony_ci unsigned carrier, unsigned nsr) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci int lpa; 75162306a36Sopenharmony_ci struct net_device *ndev = db->ndev; 75262306a36Sopenharmony_ci struct mii_if_info *mii = &db->mii; 75362306a36Sopenharmony_ci unsigned ncr = dm9000_read_locked(db, DM9000_NCR); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (carrier) { 75662306a36Sopenharmony_ci lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA); 75762306a36Sopenharmony_ci dev_info(db->dev, 75862306a36Sopenharmony_ci "%s: link up, %dMbps, %s-duplex, lpa 0x%04X\n", 75962306a36Sopenharmony_ci ndev->name, (nsr & NSR_SPEED) ? 10 : 100, 76062306a36Sopenharmony_ci (ncr & NCR_FDX) ? "full" : "half", lpa); 76162306a36Sopenharmony_ci } else { 76262306a36Sopenharmony_ci dev_info(db->dev, "%s: link down\n", ndev->name); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic void 76762306a36Sopenharmony_cidm9000_poll_work(struct work_struct *w) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci struct delayed_work *dw = to_delayed_work(w); 77062306a36Sopenharmony_ci struct board_info *db = container_of(dw, struct board_info, phy_poll); 77162306a36Sopenharmony_ci struct net_device *ndev = db->ndev; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (db->flags & DM9000_PLATF_SIMPLE_PHY && 77462306a36Sopenharmony_ci !(db->flags & DM9000_PLATF_EXT_PHY)) { 77562306a36Sopenharmony_ci unsigned nsr = dm9000_read_locked(db, DM9000_NSR); 77662306a36Sopenharmony_ci unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0; 77762306a36Sopenharmony_ci unsigned new_carrier; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci new_carrier = (nsr & NSR_LINKST) ? 1 : 0; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (old_carrier != new_carrier) { 78262306a36Sopenharmony_ci if (netif_msg_link(db)) 78362306a36Sopenharmony_ci dm9000_show_carrier(db, new_carrier, nsr); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (!new_carrier) 78662306a36Sopenharmony_ci netif_carrier_off(ndev); 78762306a36Sopenharmony_ci else 78862306a36Sopenharmony_ci netif_carrier_on(ndev); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci } else 79162306a36Sopenharmony_ci mii_check_media(&db->mii, netif_msg_link(db), 0); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (netif_running(ndev)) 79462306a36Sopenharmony_ci dm9000_schedule_poll(db); 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/* dm9000_release_board 79862306a36Sopenharmony_ci * 79962306a36Sopenharmony_ci * release a board, and any mapped resources 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic void 80362306a36Sopenharmony_cidm9000_release_board(struct platform_device *pdev, struct board_info *db) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci /* unmap our resources */ 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci iounmap(db->io_addr); 80862306a36Sopenharmony_ci iounmap(db->io_data); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* release the resources */ 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (db->data_req) 81362306a36Sopenharmony_ci release_resource(db->data_req); 81462306a36Sopenharmony_ci kfree(db->data_req); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (db->addr_req) 81762306a36Sopenharmony_ci release_resource(db->addr_req); 81862306a36Sopenharmony_ci kfree(db->addr_req); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic unsigned char dm9000_type_to_char(enum dm9000_type type) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci switch (type) { 82462306a36Sopenharmony_ci case TYPE_DM9000E: return 'e'; 82562306a36Sopenharmony_ci case TYPE_DM9000A: return 'a'; 82662306a36Sopenharmony_ci case TYPE_DM9000B: return 'b'; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci return '?'; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci/* 83362306a36Sopenharmony_ci * Set DM9000 multicast address 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_cistatic void 83662306a36Sopenharmony_cidm9000_hash_table_unlocked(struct net_device *dev) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 83962306a36Sopenharmony_ci struct netdev_hw_addr *ha; 84062306a36Sopenharmony_ci int i, oft; 84162306a36Sopenharmony_ci u32 hash_val; 84262306a36Sopenharmony_ci u16 hash_table[4] = { 0, 0, 0, 0x8000 }; /* broadcast address */ 84362306a36Sopenharmony_ci u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci dm9000_dbg(db, 1, "entering %s\n", __func__); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) 84862306a36Sopenharmony_ci iow(db, oft, dev->dev_addr[i]); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) 85162306a36Sopenharmony_ci rcr |= RCR_PRMSC; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) 85462306a36Sopenharmony_ci rcr |= RCR_ALL; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* the multicast address in Hash Table : 64 bits */ 85762306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 85862306a36Sopenharmony_ci hash_val = ether_crc_le(6, ha->addr) & 0x3f; 85962306a36Sopenharmony_ci hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* Write the hash table to MAC MD table */ 86362306a36Sopenharmony_ci for (i = 0, oft = DM9000_MAR; i < 4; i++) { 86462306a36Sopenharmony_ci iow(db, oft++, hash_table[i]); 86562306a36Sopenharmony_ci iow(db, oft++, hash_table[i] >> 8); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci iow(db, DM9000_RCR, rcr); 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic void 87262306a36Sopenharmony_cidm9000_hash_table(struct net_device *dev) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 87562306a36Sopenharmony_ci unsigned long flags; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 87862306a36Sopenharmony_ci dm9000_hash_table_unlocked(dev); 87962306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic void 88362306a36Sopenharmony_cidm9000_mask_interrupts(struct board_info *db) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci iow(db, DM9000_IMR, IMR_PAR); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void 88962306a36Sopenharmony_cidm9000_unmask_interrupts(struct board_info *db) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci iow(db, DM9000_IMR, db->imr_all); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci/* 89562306a36Sopenharmony_ci * Initialize dm9000 board 89662306a36Sopenharmony_ci */ 89762306a36Sopenharmony_cistatic void 89862306a36Sopenharmony_cidm9000_init_dm9000(struct net_device *dev) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 90162306a36Sopenharmony_ci unsigned int imr; 90262306a36Sopenharmony_ci unsigned int ncr; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci dm9000_dbg(db, 1, "entering %s\n", __func__); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci dm9000_reset(db); 90762306a36Sopenharmony_ci dm9000_mask_interrupts(db); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci /* I/O mode */ 91062306a36Sopenharmony_ci db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* Checksum mode */ 91362306a36Sopenharmony_ci if (dev->hw_features & NETIF_F_RXCSUM) 91462306a36Sopenharmony_ci iow(db, DM9000_RCSR, 91562306a36Sopenharmony_ci (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ 91862306a36Sopenharmony_ci iow(db, DM9000_GPR, 0); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* If we are dealing with DM9000B, some extra steps are required: a 92162306a36Sopenharmony_ci * manual phy reset, and setting init params. 92262306a36Sopenharmony_ci */ 92362306a36Sopenharmony_ci if (db->type == TYPE_DM9000B) { 92462306a36Sopenharmony_ci dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); 92562306a36Sopenharmony_ci dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* if wol is needed, then always set NCR_WAKEEN otherwise we end 93162306a36Sopenharmony_ci * up dumping the wake events if we disable this. There is already 93262306a36Sopenharmony_ci * a wake-mask in DM9000_WCR */ 93362306a36Sopenharmony_ci if (db->wake_supported) 93462306a36Sopenharmony_ci ncr |= NCR_WAKEEN; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci iow(db, DM9000_NCR, ncr); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Program operating register */ 93962306a36Sopenharmony_ci iow(db, DM9000_TCR, 0); /* TX Polling clear */ 94062306a36Sopenharmony_ci iow(db, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */ 94162306a36Sopenharmony_ci iow(db, DM9000_FCR, 0xff); /* Flow Control */ 94262306a36Sopenharmony_ci iow(db, DM9000_SMCR, 0); /* Special Mode */ 94362306a36Sopenharmony_ci /* clear TX status */ 94462306a36Sopenharmony_ci iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); 94562306a36Sopenharmony_ci iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */ 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* Set address filter table */ 94862306a36Sopenharmony_ci dm9000_hash_table_unlocked(dev); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci imr = IMR_PAR | IMR_PTM | IMR_PRM; 95162306a36Sopenharmony_ci if (db->type != TYPE_DM9000E) 95262306a36Sopenharmony_ci imr |= IMR_LNKCHNG; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci db->imr_all = imr; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Init Driver variable */ 95762306a36Sopenharmony_ci db->tx_pkt_cnt = 0; 95862306a36Sopenharmony_ci db->queue_pkt_len = 0; 95962306a36Sopenharmony_ci netif_trans_update(dev); 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci/* Our watchdog timed out. Called by the networking layer */ 96362306a36Sopenharmony_cistatic void dm9000_timeout(struct net_device *dev, unsigned int txqueue) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 96662306a36Sopenharmony_ci u8 reg_save; 96762306a36Sopenharmony_ci unsigned long flags; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* Save previous register address */ 97062306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 97162306a36Sopenharmony_ci db->in_timeout = 1; 97262306a36Sopenharmony_ci reg_save = readb(db->io_addr); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci netif_stop_queue(dev); 97562306a36Sopenharmony_ci dm9000_init_dm9000(dev); 97662306a36Sopenharmony_ci dm9000_unmask_interrupts(db); 97762306a36Sopenharmony_ci /* We can accept TX packets again */ 97862306a36Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 97962306a36Sopenharmony_ci netif_wake_queue(dev); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Restore previous register address */ 98262306a36Sopenharmony_ci writeb(reg_save, db->io_addr); 98362306a36Sopenharmony_ci db->in_timeout = 0; 98462306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic void dm9000_send_packet(struct net_device *dev, 98862306a36Sopenharmony_ci int ip_summed, 98962306a36Sopenharmony_ci u16 pkt_len) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(dev); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* The DM9000 is not smart enough to leave fragmented packets alone. */ 99462306a36Sopenharmony_ci if (dm->ip_summed != ip_summed) { 99562306a36Sopenharmony_ci if (ip_summed == CHECKSUM_NONE) 99662306a36Sopenharmony_ci iow(dm, DM9000_TCCR, 0); 99762306a36Sopenharmony_ci else 99862306a36Sopenharmony_ci iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP); 99962306a36Sopenharmony_ci dm->ip_summed = ip_summed; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci /* Set TX length to DM9000 */ 100362306a36Sopenharmony_ci iow(dm, DM9000_TXPLL, pkt_len); 100462306a36Sopenharmony_ci iow(dm, DM9000_TXPLH, pkt_len >> 8); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci /* Issue TX polling command */ 100762306a36Sopenharmony_ci iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci/* 101162306a36Sopenharmony_ci * Hardware start transmission. 101262306a36Sopenharmony_ci * Send a packet to media from the upper layer. 101362306a36Sopenharmony_ci */ 101462306a36Sopenharmony_cistatic netdev_tx_t 101562306a36Sopenharmony_cidm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci unsigned long flags; 101862306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci dm9000_dbg(db, 3, "%s:\n", __func__); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (db->tx_pkt_cnt > 1) 102362306a36Sopenharmony_ci return NETDEV_TX_BUSY; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* Move data to DM9000 TX RAM */ 102862306a36Sopenharmony_ci writeb(DM9000_MWCMD, db->io_addr); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci (db->outblk)(db->io_data, skb->data, skb->len); 103162306a36Sopenharmony_ci dev->stats.tx_bytes += skb->len; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci db->tx_pkt_cnt++; 103462306a36Sopenharmony_ci /* TX control: First packet immediately send, second packet queue */ 103562306a36Sopenharmony_ci if (db->tx_pkt_cnt == 1) { 103662306a36Sopenharmony_ci dm9000_send_packet(dev, skb->ip_summed, skb->len); 103762306a36Sopenharmony_ci } else { 103862306a36Sopenharmony_ci /* Second packet */ 103962306a36Sopenharmony_ci db->queue_pkt_len = skb->len; 104062306a36Sopenharmony_ci db->queue_ip_summed = skb->ip_summed; 104162306a36Sopenharmony_ci netif_stop_queue(dev); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* free this SKB */ 104762306a36Sopenharmony_ci dev_consume_skb_any(skb); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci return NETDEV_TX_OK; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci/* 105362306a36Sopenharmony_ci * DM9000 interrupt handler 105462306a36Sopenharmony_ci * receive the packet to upper layer, free the transmitted packet 105562306a36Sopenharmony_ci */ 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic void dm9000_tx_done(struct net_device *dev, struct board_info *db) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci int tx_status = ior(db, DM9000_NSR); /* Got TX status */ 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (tx_status & (NSR_TX2END | NSR_TX1END)) { 106262306a36Sopenharmony_ci /* One packet sent complete */ 106362306a36Sopenharmony_ci db->tx_pkt_cnt--; 106462306a36Sopenharmony_ci dev->stats.tx_packets++; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (netif_msg_tx_done(db)) 106762306a36Sopenharmony_ci dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci /* Queue packet check & send */ 107062306a36Sopenharmony_ci if (db->tx_pkt_cnt > 0) 107162306a36Sopenharmony_ci dm9000_send_packet(dev, db->queue_ip_summed, 107262306a36Sopenharmony_ci db->queue_pkt_len); 107362306a36Sopenharmony_ci netif_wake_queue(dev); 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistruct dm9000_rxhdr { 107862306a36Sopenharmony_ci u8 RxPktReady; 107962306a36Sopenharmony_ci u8 RxStatus; 108062306a36Sopenharmony_ci __le16 RxLen; 108162306a36Sopenharmony_ci} __packed; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci/* 108462306a36Sopenharmony_ci * Received a packet and pass to upper layer 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_cistatic void 108762306a36Sopenharmony_cidm9000_rx(struct net_device *dev) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 109062306a36Sopenharmony_ci struct dm9000_rxhdr rxhdr; 109162306a36Sopenharmony_ci struct sk_buff *skb; 109262306a36Sopenharmony_ci u8 rxbyte, *rdptr; 109362306a36Sopenharmony_ci bool GoodPacket; 109462306a36Sopenharmony_ci int RxLen; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* Check packet ready or not */ 109762306a36Sopenharmony_ci do { 109862306a36Sopenharmony_ci ior(db, DM9000_MRCMDX); /* Dummy read */ 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* Get most updated data */ 110162306a36Sopenharmony_ci rxbyte = readb(db->io_data); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* Status check: this byte must be 0 or 1 */ 110462306a36Sopenharmony_ci if (rxbyte & DM9000_PKT_ERR) { 110562306a36Sopenharmony_ci dev_warn(db->dev, "status check fail: %d\n", rxbyte); 110662306a36Sopenharmony_ci iow(db, DM9000_RCR, 0x00); /* Stop Device */ 110762306a36Sopenharmony_ci return; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (!(rxbyte & DM9000_PKT_RDY)) 111162306a36Sopenharmony_ci return; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* A packet ready now & Get status/length */ 111462306a36Sopenharmony_ci GoodPacket = true; 111562306a36Sopenharmony_ci writeb(DM9000_MRCMD, db->io_addr); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci RxLen = le16_to_cpu(rxhdr.RxLen); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (netif_msg_rx_status(db)) 112262306a36Sopenharmony_ci dev_dbg(db->dev, "RX: status %02x, length %04x\n", 112362306a36Sopenharmony_ci rxhdr.RxStatus, RxLen); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* Packet Status check */ 112662306a36Sopenharmony_ci if (RxLen < 0x40) { 112762306a36Sopenharmony_ci GoodPacket = false; 112862306a36Sopenharmony_ci if (netif_msg_rx_err(db)) 112962306a36Sopenharmony_ci dev_dbg(db->dev, "RX: Bad Packet (runt)\n"); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (RxLen > DM9000_PKT_MAX) { 113362306a36Sopenharmony_ci dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen); 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* rxhdr.RxStatus is identical to RSR register. */ 113762306a36Sopenharmony_ci if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE | 113862306a36Sopenharmony_ci RSR_PLE | RSR_RWTO | 113962306a36Sopenharmony_ci RSR_LCS | RSR_RF)) { 114062306a36Sopenharmony_ci GoodPacket = false; 114162306a36Sopenharmony_ci if (rxhdr.RxStatus & RSR_FOE) { 114262306a36Sopenharmony_ci if (netif_msg_rx_err(db)) 114362306a36Sopenharmony_ci dev_dbg(db->dev, "fifo error\n"); 114462306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci if (rxhdr.RxStatus & RSR_CE) { 114762306a36Sopenharmony_ci if (netif_msg_rx_err(db)) 114862306a36Sopenharmony_ci dev_dbg(db->dev, "crc error\n"); 114962306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci if (rxhdr.RxStatus & RSR_RF) { 115262306a36Sopenharmony_ci if (netif_msg_rx_err(db)) 115362306a36Sopenharmony_ci dev_dbg(db->dev, "length error\n"); 115462306a36Sopenharmony_ci dev->stats.rx_length_errors++; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* Move data from DM9000 */ 115962306a36Sopenharmony_ci if (GoodPacket && 116062306a36Sopenharmony_ci ((skb = netdev_alloc_skb(dev, RxLen + 4)) != NULL)) { 116162306a36Sopenharmony_ci skb_reserve(skb, 2); 116262306a36Sopenharmony_ci rdptr = skb_put(skb, RxLen - 4); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Read received packet from RX SRAM */ 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci (db->inblk)(db->io_data, rdptr, RxLen); 116762306a36Sopenharmony_ci dev->stats.rx_bytes += RxLen; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* Pass to upper layer */ 117062306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 117162306a36Sopenharmony_ci if (dev->features & NETIF_F_RXCSUM) { 117262306a36Sopenharmony_ci if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) 117362306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 117462306a36Sopenharmony_ci else 117562306a36Sopenharmony_ci skb_checksum_none_assert(skb); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci netif_rx(skb); 117862306a36Sopenharmony_ci dev->stats.rx_packets++; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci } else { 118162306a36Sopenharmony_ci /* need to dump the packet's data */ 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci (db->dumpblk)(db->io_data, RxLen); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci } while (rxbyte & DM9000_PKT_RDY); 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic irqreturn_t dm9000_interrupt(int irq, void *dev_id) 118962306a36Sopenharmony_ci{ 119062306a36Sopenharmony_ci struct net_device *dev = dev_id; 119162306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 119262306a36Sopenharmony_ci int int_status; 119362306a36Sopenharmony_ci unsigned long flags; 119462306a36Sopenharmony_ci u8 reg_save; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci dm9000_dbg(db, 3, "entering %s\n", __func__); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci /* A real interrupt coming */ 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* holders of db->lock must always block IRQs */ 120162306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* Save previous register address */ 120462306a36Sopenharmony_ci reg_save = readb(db->io_addr); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci dm9000_mask_interrupts(db); 120762306a36Sopenharmony_ci /* Got DM9000 interrupt status */ 120862306a36Sopenharmony_ci int_status = ior(db, DM9000_ISR); /* Got ISR */ 120962306a36Sopenharmony_ci iow(db, DM9000_ISR, int_status); /* Clear ISR status */ 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (netif_msg_intr(db)) 121262306a36Sopenharmony_ci dev_dbg(db->dev, "interrupt status %02x\n", int_status); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* Received the coming packet */ 121562306a36Sopenharmony_ci if (int_status & ISR_PRS) 121662306a36Sopenharmony_ci dm9000_rx(dev); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci /* Transmit Interrupt check */ 121962306a36Sopenharmony_ci if (int_status & ISR_PTS) 122062306a36Sopenharmony_ci dm9000_tx_done(dev, db); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (db->type != TYPE_DM9000E) { 122362306a36Sopenharmony_ci if (int_status & ISR_LNKCHNG) { 122462306a36Sopenharmony_ci /* fire a link-change request */ 122562306a36Sopenharmony_ci schedule_delayed_work(&db->phy_poll, 1); 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci dm9000_unmask_interrupts(db); 123062306a36Sopenharmony_ci /* Restore previous register address */ 123162306a36Sopenharmony_ci writeb(reg_save, db->io_addr); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return IRQ_HANDLED; 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct net_device *dev = dev_id; 124162306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 124262306a36Sopenharmony_ci unsigned long flags; 124362306a36Sopenharmony_ci unsigned nsr, wcr; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci spin_lock_irqsave(&db->lock, flags); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci nsr = ior(db, DM9000_NSR); 124862306a36Sopenharmony_ci wcr = ior(db, DM9000_WCR); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci dev_dbg(db->dev, "%s: NSR=0x%02x, WCR=0x%02x\n", __func__, nsr, wcr); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (nsr & NSR_WAKEST) { 125362306a36Sopenharmony_ci /* clear, so we can avoid */ 125462306a36Sopenharmony_ci iow(db, DM9000_NSR, NSR_WAKEST); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci if (wcr & WCR_LINKST) 125762306a36Sopenharmony_ci dev_info(db->dev, "wake by link status change\n"); 125862306a36Sopenharmony_ci if (wcr & WCR_SAMPLEST) 125962306a36Sopenharmony_ci dev_info(db->dev, "wake by sample packet\n"); 126062306a36Sopenharmony_ci if (wcr & WCR_MAGICST) 126162306a36Sopenharmony_ci dev_info(db->dev, "wake by magic packet\n"); 126262306a36Sopenharmony_ci if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST))) 126362306a36Sopenharmony_ci dev_err(db->dev, "wake signalled with no reason? " 126462306a36Sopenharmony_ci "NSR=0x%02x, WSR=0x%02x\n", nsr, wcr); 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci spin_unlock_irqrestore(&db->lock, flags); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci return (nsr & NSR_WAKEST) ? IRQ_HANDLED : IRQ_NONE; 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 127362306a36Sopenharmony_ci/* 127462306a36Sopenharmony_ci *Used by netconsole 127562306a36Sopenharmony_ci */ 127662306a36Sopenharmony_cistatic void dm9000_poll_controller(struct net_device *dev) 127762306a36Sopenharmony_ci{ 127862306a36Sopenharmony_ci disable_irq(dev->irq); 127962306a36Sopenharmony_ci dm9000_interrupt(dev->irq, dev); 128062306a36Sopenharmony_ci enable_irq(dev->irq); 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci#endif 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci/* 128562306a36Sopenharmony_ci * Open the interface. 128662306a36Sopenharmony_ci * The interface is opened whenever "ifconfig" actives it. 128762306a36Sopenharmony_ci */ 128862306a36Sopenharmony_cistatic int 128962306a36Sopenharmony_cidm9000_open(struct net_device *dev) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 129262306a36Sopenharmony_ci unsigned int irq_flags = irq_get_trigger_type(dev->irq); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (netif_msg_ifup(db)) 129562306a36Sopenharmony_ci dev_dbg(db->dev, "enabling %s\n", dev->name); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci /* If there is no IRQ type specified, tell the user that this is a 129862306a36Sopenharmony_ci * problem 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci if (irq_flags == IRQF_TRIGGER_NONE) 130162306a36Sopenharmony_ci dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci irq_flags |= IRQF_SHARED; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */ 130662306a36Sopenharmony_ci iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ 130762306a36Sopenharmony_ci mdelay(1); /* delay needs by DM9000B */ 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* Initialize DM9000 board */ 131062306a36Sopenharmony_ci dm9000_init_dm9000(dev); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci if (request_irq(dev->irq, dm9000_interrupt, irq_flags, dev->name, dev)) 131362306a36Sopenharmony_ci return -EAGAIN; 131462306a36Sopenharmony_ci /* Now that we have an interrupt handler hooked up we can unmask 131562306a36Sopenharmony_ci * our interrupts 131662306a36Sopenharmony_ci */ 131762306a36Sopenharmony_ci dm9000_unmask_interrupts(db); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci /* Init driver variable */ 132062306a36Sopenharmony_ci db->dbug_cnt = 0; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci mii_check_media(&db->mii, netif_msg_link(db), 1); 132362306a36Sopenharmony_ci netif_start_queue(dev); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* Poll initial link status */ 132662306a36Sopenharmony_ci schedule_delayed_work(&db->phy_poll, 1); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci return 0; 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic void 133262306a36Sopenharmony_cidm9000_shutdown(struct net_device *dev) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci struct board_info *db = netdev_priv(dev); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* RESET device */ 133762306a36Sopenharmony_ci dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ 133862306a36Sopenharmony_ci iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */ 133962306a36Sopenharmony_ci dm9000_mask_interrupts(db); 134062306a36Sopenharmony_ci iow(db, DM9000_RCR, 0x00); /* Disable RX */ 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci/* 134462306a36Sopenharmony_ci * Stop the interface. 134562306a36Sopenharmony_ci * The interface is stopped when it is brought. 134662306a36Sopenharmony_ci */ 134762306a36Sopenharmony_cistatic int 134862306a36Sopenharmony_cidm9000_stop(struct net_device *ndev) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci struct board_info *db = netdev_priv(ndev); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (netif_msg_ifdown(db)) 135362306a36Sopenharmony_ci dev_dbg(db->dev, "shutting down %s\n", ndev->name); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci cancel_delayed_work_sync(&db->phy_poll); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci netif_stop_queue(ndev); 135862306a36Sopenharmony_ci netif_carrier_off(ndev); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci /* free interrupt */ 136162306a36Sopenharmony_ci free_irq(ndev->irq, ndev); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci dm9000_shutdown(ndev); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci return 0; 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_cistatic const struct net_device_ops dm9000_netdev_ops = { 136962306a36Sopenharmony_ci .ndo_open = dm9000_open, 137062306a36Sopenharmony_ci .ndo_stop = dm9000_stop, 137162306a36Sopenharmony_ci .ndo_start_xmit = dm9000_start_xmit, 137262306a36Sopenharmony_ci .ndo_tx_timeout = dm9000_timeout, 137362306a36Sopenharmony_ci .ndo_set_rx_mode = dm9000_hash_table, 137462306a36Sopenharmony_ci .ndo_eth_ioctl = dm9000_ioctl, 137562306a36Sopenharmony_ci .ndo_set_features = dm9000_set_features, 137662306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 137762306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 137862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 137962306a36Sopenharmony_ci .ndo_poll_controller = dm9000_poll_controller, 138062306a36Sopenharmony_ci#endif 138162306a36Sopenharmony_ci}; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic struct dm9000_plat_data *dm9000_parse_dt(struct device *dev) 138462306a36Sopenharmony_ci{ 138562306a36Sopenharmony_ci struct dm9000_plat_data *pdata; 138662306a36Sopenharmony_ci struct device_node *np = dev->of_node; 138762306a36Sopenharmony_ci int ret; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_OF) || !np) 139062306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 139362306a36Sopenharmony_ci if (!pdata) 139462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (of_property_read_bool(np, "davicom,ext-phy")) 139762306a36Sopenharmony_ci pdata->flags |= DM9000_PLATF_EXT_PHY; 139862306a36Sopenharmony_ci if (of_property_read_bool(np, "davicom,no-eeprom")) 139962306a36Sopenharmony_ci pdata->flags |= DM9000_PLATF_NO_EEPROM; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci ret = of_get_mac_address(np, pdata->dev_addr); 140262306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 140362306a36Sopenharmony_ci return ERR_PTR(ret); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci return pdata; 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci/* 140962306a36Sopenharmony_ci * Search DM9000 board, allocate space and register it 141062306a36Sopenharmony_ci */ 141162306a36Sopenharmony_cistatic int 141262306a36Sopenharmony_cidm9000_probe(struct platform_device *pdev) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci struct dm9000_plat_data *pdata = dev_get_platdata(&pdev->dev); 141562306a36Sopenharmony_ci struct board_info *db; /* Point a board information structure */ 141662306a36Sopenharmony_ci struct net_device *ndev; 141762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 141862306a36Sopenharmony_ci const unsigned char *mac_src; 141962306a36Sopenharmony_ci int ret = 0; 142062306a36Sopenharmony_ci int iosize; 142162306a36Sopenharmony_ci int i; 142262306a36Sopenharmony_ci u32 id_val; 142362306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 142462306a36Sopenharmony_ci struct regulator *power; 142562306a36Sopenharmony_ci bool inv_mac_addr = false; 142662306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci power = devm_regulator_get(dev, "vcc"); 142962306a36Sopenharmony_ci if (IS_ERR(power)) { 143062306a36Sopenharmony_ci if (PTR_ERR(power) == -EPROBE_DEFER) 143162306a36Sopenharmony_ci return -EPROBE_DEFER; 143262306a36Sopenharmony_ci dev_dbg(dev, "no regulator provided\n"); 143362306a36Sopenharmony_ci } else { 143462306a36Sopenharmony_ci ret = regulator_enable(power); 143562306a36Sopenharmony_ci if (ret != 0) { 143662306a36Sopenharmony_ci dev_err(dev, 143762306a36Sopenharmony_ci "Failed to enable power regulator: %d\n", ret); 143862306a36Sopenharmony_ci return ret; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci dev_dbg(dev, "regulator enabled\n"); 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 144462306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(reset_gpio); 144562306a36Sopenharmony_ci if (ret) { 144662306a36Sopenharmony_ci dev_err(dev, "failed to request reset gpio: %d\n", ret); 144762306a36Sopenharmony_ci goto out_regulator_disable; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (reset_gpio) { 145162306a36Sopenharmony_ci ret = gpiod_set_consumer_name(reset_gpio, "dm9000_reset"); 145262306a36Sopenharmony_ci if (ret) { 145362306a36Sopenharmony_ci dev_err(dev, "failed to set reset gpio name: %d\n", 145462306a36Sopenharmony_ci ret); 145562306a36Sopenharmony_ci goto out_regulator_disable; 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci /* According to manual PWRST# Low Period Min 1ms */ 145962306a36Sopenharmony_ci msleep(2); 146062306a36Sopenharmony_ci gpiod_set_value_cansleep(reset_gpio, 0); 146162306a36Sopenharmony_ci /* Needs 3ms to read eeprom when PWRST is deasserted */ 146262306a36Sopenharmony_ci msleep(4); 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (!pdata) { 146662306a36Sopenharmony_ci pdata = dm9000_parse_dt(&pdev->dev); 146762306a36Sopenharmony_ci if (IS_ERR(pdata)) { 146862306a36Sopenharmony_ci ret = PTR_ERR(pdata); 146962306a36Sopenharmony_ci goto out_regulator_disable; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* Init network device */ 147462306a36Sopenharmony_ci ndev = alloc_etherdev(sizeof(struct board_info)); 147562306a36Sopenharmony_ci if (!ndev) { 147662306a36Sopenharmony_ci ret = -ENOMEM; 147762306a36Sopenharmony_ci goto out_regulator_disable; 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci dev_dbg(&pdev->dev, "dm9000_probe()\n"); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci /* setup board info structure */ 148562306a36Sopenharmony_ci db = netdev_priv(ndev); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci db->dev = &pdev->dev; 148862306a36Sopenharmony_ci db->ndev = ndev; 148962306a36Sopenharmony_ci if (!IS_ERR(power)) 149062306a36Sopenharmony_ci db->power_supply = power; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci spin_lock_init(&db->lock); 149362306a36Sopenharmony_ci mutex_init(&db->addr_lock); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 149862306a36Sopenharmony_ci db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (!db->addr_res || !db->data_res) { 150162306a36Sopenharmony_ci dev_err(db->dev, "insufficient resources addr=%p data=%p\n", 150262306a36Sopenharmony_ci db->addr_res, db->data_res); 150362306a36Sopenharmony_ci ret = -ENOENT; 150462306a36Sopenharmony_ci goto out; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci ndev->irq = platform_get_irq(pdev, 0); 150862306a36Sopenharmony_ci if (ndev->irq < 0) { 150962306a36Sopenharmony_ci ret = ndev->irq; 151062306a36Sopenharmony_ci goto out; 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci db->irq_wake = platform_get_irq_optional(pdev, 1); 151462306a36Sopenharmony_ci if (db->irq_wake >= 0) { 151562306a36Sopenharmony_ci dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci ret = request_irq(db->irq_wake, dm9000_wol_interrupt, 151862306a36Sopenharmony_ci IRQF_SHARED, dev_name(db->dev), ndev); 151962306a36Sopenharmony_ci if (ret) { 152062306a36Sopenharmony_ci dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret); 152162306a36Sopenharmony_ci } else { 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* test to see if irq is really wakeup capable */ 152462306a36Sopenharmony_ci ret = irq_set_irq_wake(db->irq_wake, 1); 152562306a36Sopenharmony_ci if (ret) { 152662306a36Sopenharmony_ci dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", 152762306a36Sopenharmony_ci db->irq_wake, ret); 152862306a36Sopenharmony_ci } else { 152962306a36Sopenharmony_ci irq_set_irq_wake(db->irq_wake, 0); 153062306a36Sopenharmony_ci db->wake_supported = 1; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci iosize = resource_size(db->addr_res); 153662306a36Sopenharmony_ci db->addr_req = request_mem_region(db->addr_res->start, iosize, 153762306a36Sopenharmony_ci pdev->name); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci if (db->addr_req == NULL) { 154062306a36Sopenharmony_ci dev_err(db->dev, "cannot claim address reg area\n"); 154162306a36Sopenharmony_ci ret = -EIO; 154262306a36Sopenharmony_ci goto out; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci db->io_addr = ioremap(db->addr_res->start, iosize); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci if (db->io_addr == NULL) { 154862306a36Sopenharmony_ci dev_err(db->dev, "failed to ioremap address reg\n"); 154962306a36Sopenharmony_ci ret = -EINVAL; 155062306a36Sopenharmony_ci goto out; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci iosize = resource_size(db->data_res); 155462306a36Sopenharmony_ci db->data_req = request_mem_region(db->data_res->start, iosize, 155562306a36Sopenharmony_ci pdev->name); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (db->data_req == NULL) { 155862306a36Sopenharmony_ci dev_err(db->dev, "cannot claim data reg area\n"); 155962306a36Sopenharmony_ci ret = -EIO; 156062306a36Sopenharmony_ci goto out; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci db->io_data = ioremap(db->data_res->start, iosize); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (db->io_data == NULL) { 156662306a36Sopenharmony_ci dev_err(db->dev, "failed to ioremap data reg\n"); 156762306a36Sopenharmony_ci ret = -EINVAL; 156862306a36Sopenharmony_ci goto out; 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* fill in parameters for net-dev structure */ 157262306a36Sopenharmony_ci ndev->base_addr = (unsigned long)db->io_addr; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci /* ensure at least we have a default set of IO routines */ 157562306a36Sopenharmony_ci dm9000_set_io(db, iosize); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci /* check to see if anything is being over-ridden */ 157862306a36Sopenharmony_ci if (pdata != NULL) { 157962306a36Sopenharmony_ci /* check to see if the driver wants to over-ride the 158062306a36Sopenharmony_ci * default IO width */ 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci if (pdata->flags & DM9000_PLATF_8BITONLY) 158362306a36Sopenharmony_ci dm9000_set_io(db, 1); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (pdata->flags & DM9000_PLATF_16BITONLY) 158662306a36Sopenharmony_ci dm9000_set_io(db, 2); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (pdata->flags & DM9000_PLATF_32BITONLY) 158962306a36Sopenharmony_ci dm9000_set_io(db, 4); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* check to see if there are any IO routine 159262306a36Sopenharmony_ci * over-rides */ 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci if (pdata->inblk != NULL) 159562306a36Sopenharmony_ci db->inblk = pdata->inblk; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (pdata->outblk != NULL) 159862306a36Sopenharmony_ci db->outblk = pdata->outblk; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci if (pdata->dumpblk != NULL) 160162306a36Sopenharmony_ci db->dumpblk = pdata->dumpblk; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci db->flags = pdata->flags; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL 160762306a36Sopenharmony_ci db->flags |= DM9000_PLATF_SIMPLE_PHY; 160862306a36Sopenharmony_ci#endif 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci dm9000_reset(db); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* try multiple times, DM9000 sometimes gets the read wrong */ 161362306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 161462306a36Sopenharmony_ci id_val = ior(db, DM9000_VIDL); 161562306a36Sopenharmony_ci id_val |= (u32)ior(db, DM9000_VIDH) << 8; 161662306a36Sopenharmony_ci id_val |= (u32)ior(db, DM9000_PIDL) << 16; 161762306a36Sopenharmony_ci id_val |= (u32)ior(db, DM9000_PIDH) << 24; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (id_val == DM9000_ID) 162062306a36Sopenharmony_ci break; 162162306a36Sopenharmony_ci dev_err(db->dev, "read wrong id 0x%08x\n", id_val); 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci if (id_val != DM9000_ID) { 162562306a36Sopenharmony_ci dev_err(db->dev, "wrong id: 0x%08x\n", id_val); 162662306a36Sopenharmony_ci ret = -ENODEV; 162762306a36Sopenharmony_ci goto out; 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci /* Identify what type of DM9000 we are working on */ 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci id_val = ior(db, DM9000_CHIPR); 163362306a36Sopenharmony_ci dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci switch (id_val) { 163662306a36Sopenharmony_ci case CHIPR_DM9000A: 163762306a36Sopenharmony_ci db->type = TYPE_DM9000A; 163862306a36Sopenharmony_ci break; 163962306a36Sopenharmony_ci case CHIPR_DM9000B: 164062306a36Sopenharmony_ci db->type = TYPE_DM9000B; 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci default: 164362306a36Sopenharmony_ci dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val); 164462306a36Sopenharmony_ci db->type = TYPE_DM9000E; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* dm9000a/b are capable of hardware checksum offload */ 164862306a36Sopenharmony_ci if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { 164962306a36Sopenharmony_ci ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; 165062306a36Sopenharmony_ci ndev->features |= ndev->hw_features; 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci /* from this point we assume that we have found a DM9000 */ 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci ndev->netdev_ops = &dm9000_netdev_ops; 165662306a36Sopenharmony_ci ndev->watchdog_timeo = msecs_to_jiffies(watchdog); 165762306a36Sopenharmony_ci ndev->ethtool_ops = &dm9000_ethtool_ops; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci db->msg_enable = NETIF_MSG_LINK; 166062306a36Sopenharmony_ci db->mii.phy_id_mask = 0x1f; 166162306a36Sopenharmony_ci db->mii.reg_num_mask = 0x1f; 166262306a36Sopenharmony_ci db->mii.force_media = 0; 166362306a36Sopenharmony_ci db->mii.full_duplex = 0; 166462306a36Sopenharmony_ci db->mii.dev = ndev; 166562306a36Sopenharmony_ci db->mii.mdio_read = dm9000_phy_read; 166662306a36Sopenharmony_ci db->mii.mdio_write = dm9000_phy_write; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci mac_src = "eeprom"; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* try reading the node address from the attached EEPROM */ 167162306a36Sopenharmony_ci for (i = 0; i < 6; i += 2) 167262306a36Sopenharmony_ci dm9000_read_eeprom(db, i / 2, addr + i); 167362306a36Sopenharmony_ci eth_hw_addr_set(ndev, addr); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) { 167662306a36Sopenharmony_ci mac_src = "platform data"; 167762306a36Sopenharmony_ci eth_hw_addr_set(ndev, pdata->dev_addr); 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr)) { 168162306a36Sopenharmony_ci /* try reading from mac */ 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci mac_src = "chip"; 168462306a36Sopenharmony_ci for (i = 0; i < 6; i++) 168562306a36Sopenharmony_ci addr[i] = ior(db, i + DM9000_PAR); 168662306a36Sopenharmony_ci eth_hw_addr_set(ndev, pdata->dev_addr); 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr)) { 169062306a36Sopenharmony_ci inv_mac_addr = true; 169162306a36Sopenharmony_ci eth_hw_addr_random(ndev); 169262306a36Sopenharmony_ci mac_src = "random"; 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci platform_set_drvdata(pdev, ndev); 169762306a36Sopenharmony_ci ret = register_netdev(ndev); 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci if (ret == 0) { 170062306a36Sopenharmony_ci if (inv_mac_addr) 170162306a36Sopenharmony_ci dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please set using ip\n", 170262306a36Sopenharmony_ci ndev->name); 170362306a36Sopenharmony_ci printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n", 170462306a36Sopenharmony_ci ndev->name, dm9000_type_to_char(db->type), 170562306a36Sopenharmony_ci db->io_addr, db->io_data, ndev->irq, 170662306a36Sopenharmony_ci ndev->dev_addr, mac_src); 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci return 0; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ciout: 171162306a36Sopenharmony_ci dev_err(db->dev, "not found (%d).\n", ret); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci dm9000_release_board(pdev, db); 171462306a36Sopenharmony_ci free_netdev(ndev); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ciout_regulator_disable: 171762306a36Sopenharmony_ci if (!IS_ERR(power)) 171862306a36Sopenharmony_ci regulator_disable(power); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci return ret; 172162306a36Sopenharmony_ci} 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_cistatic int 172462306a36Sopenharmony_cidm9000_drv_suspend(struct device *dev) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 172762306a36Sopenharmony_ci struct board_info *db; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (ndev) { 173062306a36Sopenharmony_ci db = netdev_priv(ndev); 173162306a36Sopenharmony_ci db->in_suspend = 1; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci if (!netif_running(ndev)) 173462306a36Sopenharmony_ci return 0; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci netif_device_detach(ndev); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci /* only shutdown if not using WoL */ 173962306a36Sopenharmony_ci if (!db->wake_state) 174062306a36Sopenharmony_ci dm9000_shutdown(ndev); 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci return 0; 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cistatic int 174662306a36Sopenharmony_cidm9000_drv_resume(struct device *dev) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 174962306a36Sopenharmony_ci struct board_info *db = netdev_priv(ndev); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci if (ndev) { 175262306a36Sopenharmony_ci if (netif_running(ndev)) { 175362306a36Sopenharmony_ci /* reset if we were not in wake mode to ensure if 175462306a36Sopenharmony_ci * the device was powered off it is in a known state */ 175562306a36Sopenharmony_ci if (!db->wake_state) { 175662306a36Sopenharmony_ci dm9000_init_dm9000(ndev); 175762306a36Sopenharmony_ci dm9000_unmask_interrupts(db); 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci netif_device_attach(ndev); 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci db->in_suspend = 0; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci return 0; 176662306a36Sopenharmony_ci} 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_cistatic const struct dev_pm_ops dm9000_drv_pm_ops = { 176962306a36Sopenharmony_ci .suspend = dm9000_drv_suspend, 177062306a36Sopenharmony_ci .resume = dm9000_drv_resume, 177162306a36Sopenharmony_ci}; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_cistatic int 177462306a36Sopenharmony_cidm9000_drv_remove(struct platform_device *pdev) 177562306a36Sopenharmony_ci{ 177662306a36Sopenharmony_ci struct net_device *ndev = platform_get_drvdata(pdev); 177762306a36Sopenharmony_ci struct board_info *dm = to_dm9000_board(ndev); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci unregister_netdev(ndev); 178062306a36Sopenharmony_ci dm9000_release_board(pdev, dm); 178162306a36Sopenharmony_ci free_netdev(ndev); /* free device structure */ 178262306a36Sopenharmony_ci if (dm->power_supply) 178362306a36Sopenharmony_ci regulator_disable(dm->power_supply); 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci dev_dbg(&pdev->dev, "released and freed device\n"); 178662306a36Sopenharmony_ci return 0; 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci#ifdef CONFIG_OF 179062306a36Sopenharmony_cistatic const struct of_device_id dm9000_of_matches[] = { 179162306a36Sopenharmony_ci { .compatible = "davicom,dm9000", }, 179262306a36Sopenharmony_ci { /* sentinel */ } 179362306a36Sopenharmony_ci}; 179462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, dm9000_of_matches); 179562306a36Sopenharmony_ci#endif 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cistatic struct platform_driver dm9000_driver = { 179862306a36Sopenharmony_ci .driver = { 179962306a36Sopenharmony_ci .name = "dm9000", 180062306a36Sopenharmony_ci .pm = &dm9000_drv_pm_ops, 180162306a36Sopenharmony_ci .of_match_table = of_match_ptr(dm9000_of_matches), 180262306a36Sopenharmony_ci }, 180362306a36Sopenharmony_ci .probe = dm9000_probe, 180462306a36Sopenharmony_ci .remove = dm9000_drv_remove, 180562306a36Sopenharmony_ci}; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_cimodule_platform_driver(dm9000_driver); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ciMODULE_AUTHOR("Sascha Hauer, Ben Dooks"); 181062306a36Sopenharmony_ciMODULE_DESCRIPTION("Davicom DM9000 network driver"); 181162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 181262306a36Sopenharmony_ciMODULE_ALIAS("platform:dm9000"); 1813