162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Microchip ENCX24J600 ethernet driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 Gridpoint 662306a36Sopenharmony_ci * Author: Jon Ringle <jringle@gridpoint.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/errno.h> 1162306a36Sopenharmony_ci#include <linux/etherdevice.h> 1262306a36Sopenharmony_ci#include <linux/ethtool.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/netdevice.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci#include <linux/skbuff.h> 1962306a36Sopenharmony_ci#include <linux/spi/spi.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "encx24j600_hw.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define DRV_NAME "encx24j600" 2462306a36Sopenharmony_ci#define DRV_VERSION "1.0" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) 2762306a36Sopenharmony_cistatic int debug = -1; 2862306a36Sopenharmony_cimodule_param(debug, int, 0000); 2962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* SRAM memory layout: 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * 0x0000-0x05ff TX buffers 1.5KB (1*1536) reside in the GP area in SRAM 3462306a36Sopenharmony_ci * 0x0600-0x5fff RX buffers 22.5KB (15*1536) reside in the RX area in SRAM 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci#define ENC_TX_BUF_START 0x0000U 3762306a36Sopenharmony_ci#define ENC_RX_BUF_START 0x0600U 3862306a36Sopenharmony_ci#define ENC_RX_BUF_END 0x5fffU 3962306a36Sopenharmony_ci#define ENC_SRAM_SIZE 0x6000U 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cienum { 4262306a36Sopenharmony_ci RXFILTER_NORMAL, 4362306a36Sopenharmony_ci RXFILTER_MULTI, 4462306a36Sopenharmony_ci RXFILTER_PROMISC 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct encx24j600_priv { 4862306a36Sopenharmony_ci struct net_device *ndev; 4962306a36Sopenharmony_ci struct mutex lock; /* device access lock */ 5062306a36Sopenharmony_ci struct encx24j600_context ctx; 5162306a36Sopenharmony_ci struct sk_buff *tx_skb; 5262306a36Sopenharmony_ci struct task_struct *kworker_task; 5362306a36Sopenharmony_ci struct kthread_worker kworker; 5462306a36Sopenharmony_ci struct kthread_work tx_work; 5562306a36Sopenharmony_ci struct kthread_work setrx_work; 5662306a36Sopenharmony_ci u16 next_packet; 5762306a36Sopenharmony_ci bool hw_enabled; 5862306a36Sopenharmony_ci bool full_duplex; 5962306a36Sopenharmony_ci bool autoneg; 6062306a36Sopenharmony_ci u16 speed; 6162306a36Sopenharmony_ci int rxfilter; 6262306a36Sopenharmony_ci u32 msg_enable; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void dump_packet(const char *msg, int len, const char *data) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci pr_debug(DRV_NAME ": %s - packet len:%d\n", msg, len); 6862306a36Sopenharmony_ci print_hex_dump_bytes("pk data: ", DUMP_PREFIX_OFFSET, data, len); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void encx24j600_dump_rsv(struct encx24j600_priv *priv, const char *msg, 7262306a36Sopenharmony_ci struct rsv *rsv) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci netdev_info(dev, "RX packet Len:%d\n", rsv->len); 7762306a36Sopenharmony_ci netdev_dbg(dev, "%s - NextPk: 0x%04x\n", msg, 7862306a36Sopenharmony_ci rsv->next_packet); 7962306a36Sopenharmony_ci netdev_dbg(dev, "RxOK: %d, DribbleNibble: %d\n", 8062306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXOK), 8162306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_DRIBBLENIBBLE)); 8262306a36Sopenharmony_ci netdev_dbg(dev, "CRCErr:%d, LenChkErr: %d, LenOutOfRange: %d\n", 8362306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_CRCERROR), 8462306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_LENCHECKERR), 8562306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_LENOUTOFRANGE)); 8662306a36Sopenharmony_ci netdev_dbg(dev, "Multicast: %d, Broadcast: %d, LongDropEvent: %d, CarrierEvent: %d\n", 8762306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXMULTICAST), 8862306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXBROADCAST), 8962306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXLONGEVDROPEV), 9062306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_CARRIEREV)); 9162306a36Sopenharmony_ci netdev_dbg(dev, "ControlFrame: %d, PauseFrame: %d, UnknownOp: %d, VLanTagFrame: %d\n", 9262306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXCONTROLFRAME), 9362306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXPAUSEFRAME), 9462306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXUNKNOWNOPCODE), 9562306a36Sopenharmony_ci RSV_GETBIT(rsv->rxstat, RSV_RXTYPEVLAN)); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic u16 encx24j600_read_reg(struct encx24j600_priv *priv, u8 reg) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 10162306a36Sopenharmony_ci unsigned int val = 0; 10262306a36Sopenharmony_ci int ret = regmap_read(priv->ctx.regmap, reg, &val); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (unlikely(ret)) 10562306a36Sopenharmony_ci netif_err(priv, drv, dev, "%s: error %d reading reg %02x\n", 10662306a36Sopenharmony_ci __func__, ret, reg); 10762306a36Sopenharmony_ci return val; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void encx24j600_write_reg(struct encx24j600_priv *priv, u8 reg, u16 val) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 11362306a36Sopenharmony_ci int ret = regmap_write(priv->ctx.regmap, reg, val); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (unlikely(ret)) 11662306a36Sopenharmony_ci netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n", 11762306a36Sopenharmony_ci __func__, ret, reg, val); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void encx24j600_update_reg(struct encx24j600_priv *priv, u8 reg, 12162306a36Sopenharmony_ci u16 mask, u16 val) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 12462306a36Sopenharmony_ci int ret = regmap_update_bits(priv->ctx.regmap, reg, mask, val); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (unlikely(ret)) 12762306a36Sopenharmony_ci netif_err(priv, drv, dev, "%s: error %d updating reg %02x=%04x~%04x\n", 12862306a36Sopenharmony_ci __func__, ret, reg, val, mask); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic u16 encx24j600_read_phy(struct encx24j600_priv *priv, u8 reg) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 13462306a36Sopenharmony_ci unsigned int val = 0; 13562306a36Sopenharmony_ci int ret = regmap_read(priv->ctx.phymap, reg, &val); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (unlikely(ret)) 13862306a36Sopenharmony_ci netif_err(priv, drv, dev, "%s: error %d reading %02x\n", 13962306a36Sopenharmony_ci __func__, ret, reg); 14062306a36Sopenharmony_ci return val; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void encx24j600_write_phy(struct encx24j600_priv *priv, u8 reg, u16 val) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 14662306a36Sopenharmony_ci int ret = regmap_write(priv->ctx.phymap, reg, val); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (unlikely(ret)) 14962306a36Sopenharmony_ci netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n", 15062306a36Sopenharmony_ci __func__, ret, reg, val); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic void encx24j600_clr_bits(struct encx24j600_priv *priv, u8 reg, u16 mask) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci encx24j600_update_reg(priv, reg, mask, 0); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void encx24j600_set_bits(struct encx24j600_priv *priv, u8 reg, u16 mask) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci encx24j600_update_reg(priv, reg, mask, mask); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic void encx24j600_cmd(struct encx24j600_priv *priv, u8 cmd) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 16662306a36Sopenharmony_ci int ret = regmap_write(priv->ctx.regmap, cmd, 0); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (unlikely(ret)) 16962306a36Sopenharmony_ci netif_err(priv, drv, dev, "%s: error %d with cmd %02x\n", 17062306a36Sopenharmony_ci __func__, ret, cmd); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int encx24j600_raw_read(struct encx24j600_priv *priv, u8 reg, u8 *data, 17462306a36Sopenharmony_ci size_t count) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci int ret; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci mutex_lock(&priv->ctx.mutex); 17962306a36Sopenharmony_ci ret = regmap_encx24j600_spi_read(&priv->ctx, reg, data, count); 18062306a36Sopenharmony_ci mutex_unlock(&priv->ctx.mutex); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return ret; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int encx24j600_raw_write(struct encx24j600_priv *priv, u8 reg, 18662306a36Sopenharmony_ci const u8 *data, size_t count) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci int ret; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci mutex_lock(&priv->ctx.mutex); 19162306a36Sopenharmony_ci ret = regmap_encx24j600_spi_write(&priv->ctx, reg, data, count); 19262306a36Sopenharmony_ci mutex_unlock(&priv->ctx.mutex); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void encx24j600_update_phcon1(struct encx24j600_priv *priv) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci u16 phcon1 = encx24j600_read_phy(priv, PHCON1); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (priv->autoneg == AUTONEG_ENABLE) { 20262306a36Sopenharmony_ci phcon1 |= ANEN | RENEG; 20362306a36Sopenharmony_ci } else { 20462306a36Sopenharmony_ci phcon1 &= ~ANEN; 20562306a36Sopenharmony_ci if (priv->speed == SPEED_100) 20662306a36Sopenharmony_ci phcon1 |= SPD100; 20762306a36Sopenharmony_ci else 20862306a36Sopenharmony_ci phcon1 &= ~SPD100; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (priv->full_duplex) 21162306a36Sopenharmony_ci phcon1 |= PFULDPX; 21262306a36Sopenharmony_ci else 21362306a36Sopenharmony_ci phcon1 &= ~PFULDPX; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci encx24j600_write_phy(priv, PHCON1, phcon1); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* Waits for autonegotiation to complete. */ 21962306a36Sopenharmony_cistatic int encx24j600_wait_for_autoneg(struct encx24j600_priv *priv) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 22262306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(2000); 22362306a36Sopenharmony_ci u16 phstat1; 22462306a36Sopenharmony_ci u16 estat; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci phstat1 = encx24j600_read_phy(priv, PHSTAT1); 22762306a36Sopenharmony_ci while ((phstat1 & ANDONE) == 0) { 22862306a36Sopenharmony_ci if (time_after(jiffies, timeout)) { 22962306a36Sopenharmony_ci u16 phstat3; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci netif_notice(priv, drv, dev, "timeout waiting for autoneg done\n"); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci priv->autoneg = AUTONEG_DISABLE; 23462306a36Sopenharmony_ci phstat3 = encx24j600_read_phy(priv, PHSTAT3); 23562306a36Sopenharmony_ci priv->speed = (phstat3 & PHY3SPD100) 23662306a36Sopenharmony_ci ? SPEED_100 : SPEED_10; 23762306a36Sopenharmony_ci priv->full_duplex = (phstat3 & PHY3DPX) ? 1 : 0; 23862306a36Sopenharmony_ci encx24j600_update_phcon1(priv); 23962306a36Sopenharmony_ci netif_notice(priv, drv, dev, "Using parallel detection: %s/%s", 24062306a36Sopenharmony_ci priv->speed == SPEED_100 ? "100" : "10", 24162306a36Sopenharmony_ci priv->full_duplex ? "Full" : "Half"); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return -ETIMEDOUT; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci cpu_relax(); 24662306a36Sopenharmony_ci phstat1 = encx24j600_read_phy(priv, PHSTAT1); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci estat = encx24j600_read_reg(priv, ESTAT); 25062306a36Sopenharmony_ci if (estat & PHYDPX) { 25162306a36Sopenharmony_ci encx24j600_set_bits(priv, MACON2, FULDPX); 25262306a36Sopenharmony_ci encx24j600_write_reg(priv, MABBIPG, 0x15); 25362306a36Sopenharmony_ci } else { 25462306a36Sopenharmony_ci encx24j600_clr_bits(priv, MACON2, FULDPX); 25562306a36Sopenharmony_ci encx24j600_write_reg(priv, MABBIPG, 0x12); 25662306a36Sopenharmony_ci /* Max retransmittions attempt */ 25762306a36Sopenharmony_ci encx24j600_write_reg(priv, MACLCON, 0x370f); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* Access the PHY to determine link status */ 26462306a36Sopenharmony_cistatic void encx24j600_check_link_status(struct encx24j600_priv *priv) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 26762306a36Sopenharmony_ci u16 estat; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci estat = encx24j600_read_reg(priv, ESTAT); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (estat & PHYLNK) { 27262306a36Sopenharmony_ci if (priv->autoneg == AUTONEG_ENABLE) 27362306a36Sopenharmony_ci encx24j600_wait_for_autoneg(priv); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci netif_carrier_on(dev); 27662306a36Sopenharmony_ci netif_info(priv, ifup, dev, "link up\n"); 27762306a36Sopenharmony_ci } else { 27862306a36Sopenharmony_ci netif_info(priv, ifdown, dev, "link down\n"); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Re-enable autoneg since we won't know what we might be 28162306a36Sopenharmony_ci * connected to when the link is brought back up again. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci priv->autoneg = AUTONEG_ENABLE; 28462306a36Sopenharmony_ci priv->full_duplex = true; 28562306a36Sopenharmony_ci priv->speed = SPEED_100; 28662306a36Sopenharmony_ci netif_carrier_off(dev); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void encx24j600_int_link_handler(struct encx24j600_priv *priv) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci netif_dbg(priv, intr, dev, "%s", __func__); 29562306a36Sopenharmony_ci encx24j600_check_link_status(priv); 29662306a36Sopenharmony_ci encx24j600_clr_bits(priv, EIR, LINKIF); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void encx24j600_tx_complete(struct encx24j600_priv *priv, bool err) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (!priv->tx_skb) { 30462306a36Sopenharmony_ci BUG(); 30562306a36Sopenharmony_ci return; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci mutex_lock(&priv->lock); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (err) 31162306a36Sopenharmony_ci dev->stats.tx_errors++; 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci dev->stats.tx_packets++; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci dev->stats.tx_bytes += priv->tx_skb->len; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci encx24j600_clr_bits(priv, EIR, TXIF | TXABTIF); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci netif_dbg(priv, tx_done, dev, "TX Done%s\n", err ? ": Err" : ""); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci dev_kfree_skb(priv->tx_skb); 32262306a36Sopenharmony_ci priv->tx_skb = NULL; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci netif_wake_queue(dev); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mutex_unlock(&priv->lock); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int encx24j600_receive_packet(struct encx24j600_priv *priv, 33062306a36Sopenharmony_ci struct rsv *rsv) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 33362306a36Sopenharmony_ci struct sk_buff *skb = netdev_alloc_skb(dev, rsv->len + NET_IP_ALIGN); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (!skb) { 33662306a36Sopenharmony_ci pr_err_ratelimited("RX: OOM: packet dropped\n"); 33762306a36Sopenharmony_ci dev->stats.rx_dropped++; 33862306a36Sopenharmony_ci return -ENOMEM; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 34162306a36Sopenharmony_ci encx24j600_raw_read(priv, RRXDATA, skb_put(skb, rsv->len), rsv->len); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (netif_msg_pktdata(priv)) 34462306a36Sopenharmony_ci dump_packet("RX", skb->len, skb->data); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci skb->dev = dev; 34762306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 34862306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* Maintain stats */ 35162306a36Sopenharmony_ci dev->stats.rx_packets++; 35262306a36Sopenharmony_ci dev->stats.rx_bytes += rsv->len; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci netif_rx(skb); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void encx24j600_rx_packets(struct encx24j600_priv *priv, u8 packet_count) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci while (packet_count--) { 36462306a36Sopenharmony_ci struct rsv rsv; 36562306a36Sopenharmony_ci u16 newrxtail; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXRDPT, priv->next_packet); 36862306a36Sopenharmony_ci encx24j600_raw_read(priv, RRXDATA, (u8 *)&rsv, sizeof(rsv)); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (netif_msg_rx_status(priv)) 37162306a36Sopenharmony_ci encx24j600_dump_rsv(priv, __func__, &rsv); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (!RSV_GETBIT(rsv.rxstat, RSV_RXOK) || 37462306a36Sopenharmony_ci (rsv.len > MAX_FRAMELEN)) { 37562306a36Sopenharmony_ci netif_err(priv, rx_err, dev, "RX Error %04x\n", 37662306a36Sopenharmony_ci rsv.rxstat); 37762306a36Sopenharmony_ci dev->stats.rx_errors++; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (RSV_GETBIT(rsv.rxstat, RSV_CRCERROR)) 38062306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 38162306a36Sopenharmony_ci if (RSV_GETBIT(rsv.rxstat, RSV_LENCHECKERR)) 38262306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 38362306a36Sopenharmony_ci if (rsv.len > MAX_FRAMELEN) 38462306a36Sopenharmony_ci dev->stats.rx_over_errors++; 38562306a36Sopenharmony_ci } else { 38662306a36Sopenharmony_ci encx24j600_receive_packet(priv, &rsv); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci priv->next_packet = rsv.next_packet; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci newrxtail = priv->next_packet - 2; 39262306a36Sopenharmony_ci if (newrxtail == ENC_RX_BUF_START) 39362306a36Sopenharmony_ci newrxtail = SRAM_SIZE - 2; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci encx24j600_cmd(priv, SETPKTDEC); 39662306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXTAIL, newrxtail); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic irqreturn_t encx24j600_isr(int irq, void *dev_id) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct encx24j600_priv *priv = dev_id; 40362306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 40462306a36Sopenharmony_ci int eir; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Clear interrupts */ 40762306a36Sopenharmony_ci encx24j600_cmd(priv, CLREIE); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci eir = encx24j600_read_reg(priv, EIR); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (eir & LINKIF) 41262306a36Sopenharmony_ci encx24j600_int_link_handler(priv); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (eir & TXIF) 41562306a36Sopenharmony_ci encx24j600_tx_complete(priv, false); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (eir & TXABTIF) 41862306a36Sopenharmony_ci encx24j600_tx_complete(priv, true); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (eir & RXABTIF) { 42162306a36Sopenharmony_ci if (eir & PCFULIF) { 42262306a36Sopenharmony_ci /* Packet counter is full */ 42362306a36Sopenharmony_ci netif_err(priv, rx_err, dev, "Packet counter full\n"); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci dev->stats.rx_dropped++; 42662306a36Sopenharmony_ci encx24j600_clr_bits(priv, EIR, RXABTIF); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (eir & PKTIF) { 43062306a36Sopenharmony_ci u8 packet_count; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci mutex_lock(&priv->lock); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci packet_count = encx24j600_read_reg(priv, ESTAT) & 0xff; 43562306a36Sopenharmony_ci while (packet_count) { 43662306a36Sopenharmony_ci encx24j600_rx_packets(priv, packet_count); 43762306a36Sopenharmony_ci packet_count = encx24j600_read_reg(priv, ESTAT) & 0xff; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci mutex_unlock(&priv->lock); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Enable interrupts */ 44462306a36Sopenharmony_ci encx24j600_cmd(priv, SETEIE); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return IRQ_HANDLED; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int encx24j600_soft_reset(struct encx24j600_priv *priv) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci int ret = 0; 45262306a36Sopenharmony_ci int timeout; 45362306a36Sopenharmony_ci u16 eudast; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Write and verify a test value to EUDAST */ 45662306a36Sopenharmony_ci regcache_cache_bypass(priv->ctx.regmap, true); 45762306a36Sopenharmony_ci timeout = 10; 45862306a36Sopenharmony_ci do { 45962306a36Sopenharmony_ci encx24j600_write_reg(priv, EUDAST, EUDAST_TEST_VAL); 46062306a36Sopenharmony_ci eudast = encx24j600_read_reg(priv, EUDAST); 46162306a36Sopenharmony_ci usleep_range(25, 100); 46262306a36Sopenharmony_ci } while ((eudast != EUDAST_TEST_VAL) && --timeout); 46362306a36Sopenharmony_ci regcache_cache_bypass(priv->ctx.regmap, false); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (timeout == 0) { 46662306a36Sopenharmony_ci ret = -ETIMEDOUT; 46762306a36Sopenharmony_ci goto err_out; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Wait for CLKRDY to become set */ 47162306a36Sopenharmony_ci timeout = 10; 47262306a36Sopenharmony_ci while (!(encx24j600_read_reg(priv, ESTAT) & CLKRDY) && --timeout) 47362306a36Sopenharmony_ci usleep_range(25, 100); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (timeout == 0) { 47662306a36Sopenharmony_ci ret = -ETIMEDOUT; 47762306a36Sopenharmony_ci goto err_out; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Issue a System Reset command */ 48162306a36Sopenharmony_ci encx24j600_cmd(priv, SETETHRST); 48262306a36Sopenharmony_ci usleep_range(25, 100); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Confirm that EUDAST has 0000h after system reset */ 48562306a36Sopenharmony_ci if (encx24j600_read_reg(priv, EUDAST) != 0) { 48662306a36Sopenharmony_ci ret = -EINVAL; 48762306a36Sopenharmony_ci goto err_out; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Wait for PHY register and status bits to become available */ 49162306a36Sopenharmony_ci usleep_range(256, 1000); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cierr_out: 49462306a36Sopenharmony_ci return ret; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int encx24j600_hw_reset(struct encx24j600_priv *priv) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci int ret; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci mutex_lock(&priv->lock); 50262306a36Sopenharmony_ci ret = encx24j600_soft_reset(priv); 50362306a36Sopenharmony_ci mutex_unlock(&priv->lock); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return ret; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic void encx24j600_reset_hw_tx(struct encx24j600_priv *priv) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci encx24j600_set_bits(priv, ECON2, TXRST); 51162306a36Sopenharmony_ci encx24j600_clr_bits(priv, ECON2, TXRST); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic void encx24j600_hw_init_tx(struct encx24j600_priv *priv) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci /* Reset TX */ 51762306a36Sopenharmony_ci encx24j600_reset_hw_tx(priv); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* Clear the TXIF flag if were previously set */ 52062306a36Sopenharmony_ci encx24j600_clr_bits(priv, EIR, TXIF | TXABTIF); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Write the Tx Buffer pointer */ 52362306a36Sopenharmony_ci encx24j600_write_reg(priv, EGPWRPT, ENC_TX_BUF_START); 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic void encx24j600_hw_init_rx(struct encx24j600_priv *priv) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci encx24j600_cmd(priv, DISABLERX); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Set up RX packet start address in the SRAM */ 53162306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXST, ENC_RX_BUF_START); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Preload the RX Data pointer to the beginning of the RX area */ 53462306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXRDPT, ENC_RX_BUF_START); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci priv->next_packet = ENC_RX_BUF_START; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Set up RX end address in the SRAM */ 53962306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXTAIL, ENC_SRAM_SIZE - 2); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* Reset the user data pointers */ 54262306a36Sopenharmony_ci encx24j600_write_reg(priv, EUDAST, ENC_SRAM_SIZE); 54362306a36Sopenharmony_ci encx24j600_write_reg(priv, EUDAND, ENC_SRAM_SIZE + 1); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* Set Max Frame length */ 54662306a36Sopenharmony_ci encx24j600_write_reg(priv, MAMXFL, MAX_FRAMELEN); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic void encx24j600_dump_config(struct encx24j600_priv *priv, 55062306a36Sopenharmony_ci const char *msg) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci pr_info(DRV_NAME ": %s\n", msg); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* CHIP configuration */ 55562306a36Sopenharmony_ci pr_info(DRV_NAME " ECON1: %04X\n", encx24j600_read_reg(priv, ECON1)); 55662306a36Sopenharmony_ci pr_info(DRV_NAME " ECON2: %04X\n", encx24j600_read_reg(priv, ECON2)); 55762306a36Sopenharmony_ci pr_info(DRV_NAME " ERXFCON: %04X\n", encx24j600_read_reg(priv, 55862306a36Sopenharmony_ci ERXFCON)); 55962306a36Sopenharmony_ci pr_info(DRV_NAME " ESTAT: %04X\n", encx24j600_read_reg(priv, ESTAT)); 56062306a36Sopenharmony_ci pr_info(DRV_NAME " EIR: %04X\n", encx24j600_read_reg(priv, EIR)); 56162306a36Sopenharmony_ci pr_info(DRV_NAME " EIDLED: %04X\n", encx24j600_read_reg(priv, EIDLED)); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* MAC layer configuration */ 56462306a36Sopenharmony_ci pr_info(DRV_NAME " MACON1: %04X\n", encx24j600_read_reg(priv, MACON1)); 56562306a36Sopenharmony_ci pr_info(DRV_NAME " MACON2: %04X\n", encx24j600_read_reg(priv, MACON2)); 56662306a36Sopenharmony_ci pr_info(DRV_NAME " MAIPG: %04X\n", encx24j600_read_reg(priv, MAIPG)); 56762306a36Sopenharmony_ci pr_info(DRV_NAME " MACLCON: %04X\n", encx24j600_read_reg(priv, 56862306a36Sopenharmony_ci MACLCON)); 56962306a36Sopenharmony_ci pr_info(DRV_NAME " MABBIPG: %04X\n", encx24j600_read_reg(priv, 57062306a36Sopenharmony_ci MABBIPG)); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* PHY configuation */ 57362306a36Sopenharmony_ci pr_info(DRV_NAME " PHCON1: %04X\n", encx24j600_read_phy(priv, PHCON1)); 57462306a36Sopenharmony_ci pr_info(DRV_NAME " PHCON2: %04X\n", encx24j600_read_phy(priv, PHCON2)); 57562306a36Sopenharmony_ci pr_info(DRV_NAME " PHANA: %04X\n", encx24j600_read_phy(priv, PHANA)); 57662306a36Sopenharmony_ci pr_info(DRV_NAME " PHANLPA: %04X\n", encx24j600_read_phy(priv, 57762306a36Sopenharmony_ci PHANLPA)); 57862306a36Sopenharmony_ci pr_info(DRV_NAME " PHANE: %04X\n", encx24j600_read_phy(priv, PHANE)); 57962306a36Sopenharmony_ci pr_info(DRV_NAME " PHSTAT1: %04X\n", encx24j600_read_phy(priv, 58062306a36Sopenharmony_ci PHSTAT1)); 58162306a36Sopenharmony_ci pr_info(DRV_NAME " PHSTAT2: %04X\n", encx24j600_read_phy(priv, 58262306a36Sopenharmony_ci PHSTAT2)); 58362306a36Sopenharmony_ci pr_info(DRV_NAME " PHSTAT3: %04X\n", encx24j600_read_phy(priv, 58462306a36Sopenharmony_ci PHSTAT3)); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void encx24j600_set_rxfilter_mode(struct encx24j600_priv *priv) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci switch (priv->rxfilter) { 59062306a36Sopenharmony_ci case RXFILTER_PROMISC: 59162306a36Sopenharmony_ci encx24j600_set_bits(priv, MACON1, PASSALL); 59262306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXFCON, UCEN | MCEN | NOTMEEN); 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci case RXFILTER_MULTI: 59562306a36Sopenharmony_ci encx24j600_clr_bits(priv, MACON1, PASSALL); 59662306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXFCON, UCEN | CRCEN | BCEN | MCEN); 59762306a36Sopenharmony_ci break; 59862306a36Sopenharmony_ci case RXFILTER_NORMAL: 59962306a36Sopenharmony_ci default: 60062306a36Sopenharmony_ci encx24j600_clr_bits(priv, MACON1, PASSALL); 60162306a36Sopenharmony_ci encx24j600_write_reg(priv, ERXFCON, UCEN | CRCEN | BCEN); 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic void encx24j600_hw_init(struct encx24j600_priv *priv) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci u16 macon2; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci priv->hw_enabled = false; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* PHY Leds: link status, 61362306a36Sopenharmony_ci * LEDA: Link State + collision events 61462306a36Sopenharmony_ci * LEDB: Link State + transmit/receive events 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci encx24j600_update_reg(priv, EIDLED, 0xff00, 0xcb00); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* Loopback disabled */ 61962306a36Sopenharmony_ci encx24j600_write_reg(priv, MACON1, 0x9); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* interpacket gap value */ 62262306a36Sopenharmony_ci encx24j600_write_reg(priv, MAIPG, 0x0c12); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Write the auto negotiation pattern */ 62562306a36Sopenharmony_ci encx24j600_write_phy(priv, PHANA, PHANA_DEFAULT); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci encx24j600_update_phcon1(priv); 62862306a36Sopenharmony_ci encx24j600_check_link_status(priv); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci macon2 = MACON2_RSV1 | TXCRCEN | PADCFG0 | PADCFG2 | MACON2_DEFER; 63162306a36Sopenharmony_ci if ((priv->autoneg == AUTONEG_DISABLE) && priv->full_duplex) 63262306a36Sopenharmony_ci macon2 |= FULDPX; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci encx24j600_set_bits(priv, MACON2, macon2); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci priv->rxfilter = RXFILTER_NORMAL; 63762306a36Sopenharmony_ci encx24j600_set_rxfilter_mode(priv); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci /* Program the Maximum frame length */ 64062306a36Sopenharmony_ci encx24j600_write_reg(priv, MAMXFL, MAX_FRAMELEN); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* Init Tx pointers */ 64362306a36Sopenharmony_ci encx24j600_hw_init_tx(priv); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* Init Rx pointers */ 64662306a36Sopenharmony_ci encx24j600_hw_init_rx(priv); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (netif_msg_hw(priv)) 64962306a36Sopenharmony_ci encx24j600_dump_config(priv, "Hw is initialized"); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void encx24j600_hw_enable(struct encx24j600_priv *priv) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci /* Clear the interrupt flags in case was set */ 65562306a36Sopenharmony_ci encx24j600_clr_bits(priv, EIR, (PCFULIF | RXABTIF | TXABTIF | TXIF | 65662306a36Sopenharmony_ci PKTIF | LINKIF)); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* Enable the interrupts */ 65962306a36Sopenharmony_ci encx24j600_write_reg(priv, EIE, (PCFULIE | RXABTIE | TXABTIE | TXIE | 66062306a36Sopenharmony_ci PKTIE | LINKIE | INTIE)); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* Enable RX */ 66362306a36Sopenharmony_ci encx24j600_cmd(priv, ENABLERX); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci priv->hw_enabled = true; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void encx24j600_hw_disable(struct encx24j600_priv *priv) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci /* Disable all interrupts */ 67162306a36Sopenharmony_ci encx24j600_write_reg(priv, EIE, 0); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* Disable RX */ 67462306a36Sopenharmony_ci encx24j600_cmd(priv, DISABLERX); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci priv->hw_enabled = false; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic int encx24j600_setlink(struct net_device *dev, u8 autoneg, u16 speed, 68062306a36Sopenharmony_ci u8 duplex) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 68362306a36Sopenharmony_ci int ret = 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (!priv->hw_enabled) { 68662306a36Sopenharmony_ci /* link is in low power mode now; duplex setting 68762306a36Sopenharmony_ci * will take effect on next encx24j600_hw_init() 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_ci if (speed == SPEED_10 || speed == SPEED_100) { 69062306a36Sopenharmony_ci priv->autoneg = (autoneg == AUTONEG_ENABLE); 69162306a36Sopenharmony_ci priv->full_duplex = (duplex == DUPLEX_FULL); 69262306a36Sopenharmony_ci priv->speed = (speed == SPEED_100); 69362306a36Sopenharmony_ci } else { 69462306a36Sopenharmony_ci netif_warn(priv, link, dev, "unsupported link speed setting\n"); 69562306a36Sopenharmony_ci /*speeds other than SPEED_10 and SPEED_100 */ 69662306a36Sopenharmony_ci /*are not supported by chip */ 69762306a36Sopenharmony_ci ret = -EOPNOTSUPP; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci } else { 70062306a36Sopenharmony_ci netif_warn(priv, link, dev, "Warning: hw must be disabled to set link mode\n"); 70162306a36Sopenharmony_ci ret = -EBUSY; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci return ret; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void encx24j600_hw_get_macaddr(struct encx24j600_priv *priv, 70762306a36Sopenharmony_ci unsigned char *ethaddr) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci unsigned short val; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci val = encx24j600_read_reg(priv, MAADR1); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci ethaddr[0] = val & 0x00ff; 71462306a36Sopenharmony_ci ethaddr[1] = (val & 0xff00) >> 8; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci val = encx24j600_read_reg(priv, MAADR2); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci ethaddr[2] = val & 0x00ffU; 71962306a36Sopenharmony_ci ethaddr[3] = (val & 0xff00U) >> 8; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci val = encx24j600_read_reg(priv, MAADR3); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci ethaddr[4] = val & 0x00ffU; 72462306a36Sopenharmony_ci ethaddr[5] = (val & 0xff00U) >> 8; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/* Program the hardware MAC address from dev->dev_addr.*/ 72862306a36Sopenharmony_cistatic int encx24j600_set_hw_macaddr(struct net_device *dev) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (priv->hw_enabled) { 73362306a36Sopenharmony_ci netif_info(priv, drv, dev, "Hardware must be disabled to set Mac address\n"); 73462306a36Sopenharmony_ci return -EBUSY; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci mutex_lock(&priv->lock); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci netif_info(priv, drv, dev, "%s: Setting MAC address to %pM\n", 74062306a36Sopenharmony_ci dev->name, dev->dev_addr); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci encx24j600_write_reg(priv, MAADR3, (dev->dev_addr[4] | 74362306a36Sopenharmony_ci dev->dev_addr[5] << 8)); 74462306a36Sopenharmony_ci encx24j600_write_reg(priv, MAADR2, (dev->dev_addr[2] | 74562306a36Sopenharmony_ci dev->dev_addr[3] << 8)); 74662306a36Sopenharmony_ci encx24j600_write_reg(priv, MAADR1, (dev->dev_addr[0] | 74762306a36Sopenharmony_ci dev->dev_addr[1] << 8)); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci mutex_unlock(&priv->lock); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return 0; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci/* Store the new hardware address in dev->dev_addr, and update the MAC.*/ 75562306a36Sopenharmony_cistatic int encx24j600_set_mac_address(struct net_device *dev, void *addr) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct sockaddr *address = addr; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (netif_running(dev)) 76062306a36Sopenharmony_ci return -EBUSY; 76162306a36Sopenharmony_ci if (!is_valid_ether_addr(address->sa_data)) 76262306a36Sopenharmony_ci return -EADDRNOTAVAIL; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci eth_hw_addr_set(dev, address->sa_data); 76562306a36Sopenharmony_ci return encx24j600_set_hw_macaddr(dev); 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic int encx24j600_open(struct net_device *dev) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci int ret = request_threaded_irq(priv->ctx.spi->irq, NULL, encx24j600_isr, 77362306a36Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 77462306a36Sopenharmony_ci DRV_NAME, priv); 77562306a36Sopenharmony_ci if (unlikely(ret < 0)) { 77662306a36Sopenharmony_ci netdev_err(dev, "request irq %d failed (ret = %d)\n", 77762306a36Sopenharmony_ci priv->ctx.spi->irq, ret); 77862306a36Sopenharmony_ci return ret; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci encx24j600_hw_disable(priv); 78262306a36Sopenharmony_ci encx24j600_hw_init(priv); 78362306a36Sopenharmony_ci encx24j600_hw_enable(priv); 78462306a36Sopenharmony_ci netif_start_queue(dev); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int encx24j600_stop(struct net_device *dev) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci netif_stop_queue(dev); 79462306a36Sopenharmony_ci free_irq(priv->ctx.spi->irq, priv); 79562306a36Sopenharmony_ci return 0; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void encx24j600_setrx_proc(struct kthread_work *ws) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct encx24j600_priv *priv = 80162306a36Sopenharmony_ci container_of(ws, struct encx24j600_priv, setrx_work); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci mutex_lock(&priv->lock); 80462306a36Sopenharmony_ci encx24j600_set_rxfilter_mode(priv); 80562306a36Sopenharmony_ci mutex_unlock(&priv->lock); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic void encx24j600_set_multicast_list(struct net_device *dev) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 81162306a36Sopenharmony_ci int oldfilter = priv->rxfilter; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 81462306a36Sopenharmony_ci netif_dbg(priv, link, dev, "promiscuous mode\n"); 81562306a36Sopenharmony_ci priv->rxfilter = RXFILTER_PROMISC; 81662306a36Sopenharmony_ci } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { 81762306a36Sopenharmony_ci netif_dbg(priv, link, dev, "%smulticast mode\n", 81862306a36Sopenharmony_ci (dev->flags & IFF_ALLMULTI) ? "all-" : ""); 81962306a36Sopenharmony_ci priv->rxfilter = RXFILTER_MULTI; 82062306a36Sopenharmony_ci } else { 82162306a36Sopenharmony_ci netif_dbg(priv, link, dev, "normal mode\n"); 82262306a36Sopenharmony_ci priv->rxfilter = RXFILTER_NORMAL; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (oldfilter != priv->rxfilter) 82662306a36Sopenharmony_ci kthread_queue_work(&priv->kworker, &priv->setrx_work); 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic void encx24j600_hw_tx(struct encx24j600_priv *priv) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct net_device *dev = priv->ndev; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci netif_info(priv, tx_queued, dev, "TX Packet Len:%d\n", 83462306a36Sopenharmony_ci priv->tx_skb->len); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (netif_msg_pktdata(priv)) 83762306a36Sopenharmony_ci dump_packet("TX", priv->tx_skb->len, priv->tx_skb->data); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (encx24j600_read_reg(priv, EIR) & TXABTIF) 84062306a36Sopenharmony_ci /* Last transmition aborted due to error. Reset TX interface */ 84162306a36Sopenharmony_ci encx24j600_reset_hw_tx(priv); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* Clear the TXIF flag if were previously set */ 84462306a36Sopenharmony_ci encx24j600_clr_bits(priv, EIR, TXIF); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci /* Set the data pointer to the TX buffer address in the SRAM */ 84762306a36Sopenharmony_ci encx24j600_write_reg(priv, EGPWRPT, ENC_TX_BUF_START); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* Copy the packet into the SRAM */ 85062306a36Sopenharmony_ci encx24j600_raw_write(priv, WGPDATA, (u8 *)priv->tx_skb->data, 85162306a36Sopenharmony_ci priv->tx_skb->len); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* Program the Tx buffer start pointer */ 85462306a36Sopenharmony_ci encx24j600_write_reg(priv, ETXST, ENC_TX_BUF_START); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* Program the packet length */ 85762306a36Sopenharmony_ci encx24j600_write_reg(priv, ETXLEN, priv->tx_skb->len); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* Start the transmission */ 86062306a36Sopenharmony_ci encx24j600_cmd(priv, SETTXRTS); 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic void encx24j600_tx_proc(struct kthread_work *ws) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct encx24j600_priv *priv = 86662306a36Sopenharmony_ci container_of(ws, struct encx24j600_priv, tx_work); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci mutex_lock(&priv->lock); 86962306a36Sopenharmony_ci encx24j600_hw_tx(priv); 87062306a36Sopenharmony_ci mutex_unlock(&priv->lock); 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic netdev_tx_t encx24j600_tx(struct sk_buff *skb, struct net_device *dev) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci netif_stop_queue(dev); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* save the timestamp */ 88062306a36Sopenharmony_ci netif_trans_update(dev); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* Remember the skb for deferred processing */ 88362306a36Sopenharmony_ci priv->tx_skb = skb; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci kthread_queue_work(&priv->kworker, &priv->tx_work); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return NETDEV_TX_OK; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/* Deal with a transmit timeout */ 89162306a36Sopenharmony_cistatic void encx24j600_tx_timeout(struct net_device *dev, unsigned int txqueue) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci netif_err(priv, tx_err, dev, "TX timeout at %ld, latency %ld\n", 89662306a36Sopenharmony_ci jiffies, jiffies - dev_trans_start(dev)); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci dev->stats.tx_errors++; 89962306a36Sopenharmony_ci netif_wake_queue(dev); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic int encx24j600_get_regs_len(struct net_device *dev) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci return SFR_REG_COUNT; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic void encx24j600_get_regs(struct net_device *dev, 90862306a36Sopenharmony_ci struct ethtool_regs *regs, void *p) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 91162306a36Sopenharmony_ci u16 *buff = p; 91262306a36Sopenharmony_ci u8 reg; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci regs->version = 1; 91562306a36Sopenharmony_ci mutex_lock(&priv->lock); 91662306a36Sopenharmony_ci for (reg = 0; reg < SFR_REG_COUNT; reg += 2) { 91762306a36Sopenharmony_ci unsigned int val = 0; 91862306a36Sopenharmony_ci /* ignore errors for unreadable registers */ 91962306a36Sopenharmony_ci regmap_read(priv->ctx.regmap, reg, &val); 92062306a36Sopenharmony_ci buff[reg] = val & 0xffff; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci mutex_unlock(&priv->lock); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic void encx24j600_get_drvinfo(struct net_device *dev, 92662306a36Sopenharmony_ci struct ethtool_drvinfo *info) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 92962306a36Sopenharmony_ci strscpy(info->version, DRV_VERSION, sizeof(info->version)); 93062306a36Sopenharmony_ci strscpy(info->bus_info, dev_name(dev->dev.parent), 93162306a36Sopenharmony_ci sizeof(info->bus_info)); 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic int encx24j600_get_link_ksettings(struct net_device *dev, 93562306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 93862306a36Sopenharmony_ci u32 supported; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 94162306a36Sopenharmony_ci SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | 94262306a36Sopenharmony_ci SUPPORTED_Autoneg | SUPPORTED_TP; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 94562306a36Sopenharmony_ci supported); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci cmd->base.speed = priv->speed; 94862306a36Sopenharmony_ci cmd->base.duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; 94962306a36Sopenharmony_ci cmd->base.port = PORT_TP; 95062306a36Sopenharmony_ci cmd->base.autoneg = priv->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return 0; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic int 95662306a36Sopenharmony_ciencx24j600_set_link_ksettings(struct net_device *dev, 95762306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci return encx24j600_setlink(dev, cmd->base.autoneg, 96062306a36Sopenharmony_ci cmd->base.speed, cmd->base.duplex); 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic u32 encx24j600_get_msglevel(struct net_device *dev) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci return priv->msg_enable; 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic void encx24j600_set_msglevel(struct net_device *dev, u32 val) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct encx24j600_priv *priv = netdev_priv(dev); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci priv->msg_enable = val; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic const struct ethtool_ops encx24j600_ethtool_ops = { 97862306a36Sopenharmony_ci .get_drvinfo = encx24j600_get_drvinfo, 97962306a36Sopenharmony_ci .get_msglevel = encx24j600_get_msglevel, 98062306a36Sopenharmony_ci .set_msglevel = encx24j600_set_msglevel, 98162306a36Sopenharmony_ci .get_regs_len = encx24j600_get_regs_len, 98262306a36Sopenharmony_ci .get_regs = encx24j600_get_regs, 98362306a36Sopenharmony_ci .get_link_ksettings = encx24j600_get_link_ksettings, 98462306a36Sopenharmony_ci .set_link_ksettings = encx24j600_set_link_ksettings, 98562306a36Sopenharmony_ci}; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic const struct net_device_ops encx24j600_netdev_ops = { 98862306a36Sopenharmony_ci .ndo_open = encx24j600_open, 98962306a36Sopenharmony_ci .ndo_stop = encx24j600_stop, 99062306a36Sopenharmony_ci .ndo_start_xmit = encx24j600_tx, 99162306a36Sopenharmony_ci .ndo_set_rx_mode = encx24j600_set_multicast_list, 99262306a36Sopenharmony_ci .ndo_set_mac_address = encx24j600_set_mac_address, 99362306a36Sopenharmony_ci .ndo_tx_timeout = encx24j600_tx_timeout, 99462306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 99562306a36Sopenharmony_ci}; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic int encx24j600_spi_probe(struct spi_device *spi) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci int ret; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci struct net_device *ndev; 100262306a36Sopenharmony_ci struct encx24j600_priv *priv; 100362306a36Sopenharmony_ci u16 eidled; 100462306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci ndev = alloc_etherdev(sizeof(struct encx24j600_priv)); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (!ndev) { 100962306a36Sopenharmony_ci ret = -ENOMEM; 101062306a36Sopenharmony_ci goto error_out; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci priv = netdev_priv(ndev); 101462306a36Sopenharmony_ci spi_set_drvdata(spi, priv); 101562306a36Sopenharmony_ci dev_set_drvdata(&spi->dev, priv); 101662306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, &spi->dev); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci priv->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); 101962306a36Sopenharmony_ci priv->ndev = ndev; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* Default configuration PHY configuration */ 102262306a36Sopenharmony_ci priv->full_duplex = true; 102362306a36Sopenharmony_ci priv->autoneg = AUTONEG_ENABLE; 102462306a36Sopenharmony_ci priv->speed = SPEED_100; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci priv->ctx.spi = spi; 102762306a36Sopenharmony_ci ndev->irq = spi->irq; 102862306a36Sopenharmony_ci ndev->netdev_ops = &encx24j600_netdev_ops; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci ret = devm_regmap_init_encx24j600(&spi->dev, &priv->ctx); 103162306a36Sopenharmony_ci if (ret) 103262306a36Sopenharmony_ci goto out_free; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci mutex_init(&priv->lock); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* Reset device and check if it is connected */ 103762306a36Sopenharmony_ci if (encx24j600_hw_reset(priv)) { 103862306a36Sopenharmony_ci netif_err(priv, probe, ndev, 103962306a36Sopenharmony_ci DRV_NAME ": Chip is not detected\n"); 104062306a36Sopenharmony_ci ret = -EIO; 104162306a36Sopenharmony_ci goto out_free; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* Initialize the device HW to the consistent state */ 104562306a36Sopenharmony_ci encx24j600_hw_init(priv); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci kthread_init_worker(&priv->kworker); 104862306a36Sopenharmony_ci kthread_init_work(&priv->tx_work, encx24j600_tx_proc); 104962306a36Sopenharmony_ci kthread_init_work(&priv->setrx_work, encx24j600_setrx_proc); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci priv->kworker_task = kthread_run(kthread_worker_fn, &priv->kworker, 105262306a36Sopenharmony_ci "encx24j600"); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (IS_ERR(priv->kworker_task)) { 105562306a36Sopenharmony_ci ret = PTR_ERR(priv->kworker_task); 105662306a36Sopenharmony_ci goto out_free; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* Get the MAC address from the chip */ 106062306a36Sopenharmony_ci encx24j600_hw_get_macaddr(priv, addr); 106162306a36Sopenharmony_ci eth_hw_addr_set(ndev, addr); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci ndev->ethtool_ops = &encx24j600_ethtool_ops; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci ret = register_netdev(ndev); 106662306a36Sopenharmony_ci if (unlikely(ret)) { 106762306a36Sopenharmony_ci netif_err(priv, probe, ndev, "Error %d initializing card encx24j600 card\n", 106862306a36Sopenharmony_ci ret); 106962306a36Sopenharmony_ci goto out_stop; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci eidled = encx24j600_read_reg(priv, EIDLED); 107362306a36Sopenharmony_ci if (((eidled & DEVID_MASK) >> DEVID_SHIFT) != ENCX24J600_DEV_ID) { 107462306a36Sopenharmony_ci ret = -EINVAL; 107562306a36Sopenharmony_ci goto out_unregister; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci netif_info(priv, probe, ndev, "Silicon rev ID: 0x%02x\n", 107962306a36Sopenharmony_ci (eidled & REVID_MASK) >> REVID_SHIFT); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci netif_info(priv, drv, priv->ndev, "MAC address %pM\n", ndev->dev_addr); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return ret; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ciout_unregister: 108662306a36Sopenharmony_ci unregister_netdev(priv->ndev); 108762306a36Sopenharmony_ciout_stop: 108862306a36Sopenharmony_ci kthread_stop(priv->kworker_task); 108962306a36Sopenharmony_ciout_free: 109062306a36Sopenharmony_ci free_netdev(ndev); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cierror_out: 109362306a36Sopenharmony_ci return ret; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic void encx24j600_spi_remove(struct spi_device *spi) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct encx24j600_priv *priv = dev_get_drvdata(&spi->dev); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci unregister_netdev(priv->ndev); 110162306a36Sopenharmony_ci kthread_stop(priv->kworker_task); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci free_netdev(priv->ndev); 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic const struct spi_device_id encx24j600_spi_id_table[] = { 110762306a36Sopenharmony_ci { .name = "encx24j600" }, 110862306a36Sopenharmony_ci { /* sentinel */ } 110962306a36Sopenharmony_ci}; 111062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, encx24j600_spi_id_table); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic struct spi_driver encx24j600_spi_net_driver = { 111362306a36Sopenharmony_ci .driver = { 111462306a36Sopenharmony_ci .name = DRV_NAME, 111562306a36Sopenharmony_ci .owner = THIS_MODULE, 111662306a36Sopenharmony_ci .bus = &spi_bus_type, 111762306a36Sopenharmony_ci }, 111862306a36Sopenharmony_ci .probe = encx24j600_spi_probe, 111962306a36Sopenharmony_ci .remove = encx24j600_spi_remove, 112062306a36Sopenharmony_ci .id_table = encx24j600_spi_id_table, 112162306a36Sopenharmony_ci}; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_cimodule_spi_driver(encx24j600_spi_net_driver); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_NAME " ethernet driver"); 112662306a36Sopenharmony_ciMODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>"); 112762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1128