18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Microchip ENC28J60 ethernet driver (MAC + PHY) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Eurek srl 68c2ecf20Sopenharmony_ci * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com> 78c2ecf20Sopenharmony_ci * based on enc28j60.c written by David Anders for 2.4 kernel version 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * $Id: enc28j60.c,v 1.22 2007/12/20 10:47:01 claudio Exp $ 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/property.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci#include <linux/errno.h> 208c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 218c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 228c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 238c2ecf20Sopenharmony_ci#include <linux/tcp.h> 248c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 258c2ecf20Sopenharmony_ci#include <linux/delay.h> 268c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "enc28j60_hw.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define DRV_NAME "enc28j60" 318c2ecf20Sopenharmony_ci#define DRV_VERSION "1.02" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define SPI_OPLEN 1 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define ENC28J60_MSG_DEFAULT \ 368c2ecf20Sopenharmony_ci (NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Buffer size required for the largest SPI transfer (i.e., reading a 398c2ecf20Sopenharmony_ci * frame). 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci#define SPI_TRANSFER_BUF_LEN (4 + MAX_FRAMELEN) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define TX_TIMEOUT (4 * HZ) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* Max TX retries in case of collision as suggested by errata datasheet */ 468c2ecf20Sopenharmony_ci#define MAX_TX_RETRYCOUNT 16 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum { 498c2ecf20Sopenharmony_ci RXFILTER_NORMAL, 508c2ecf20Sopenharmony_ci RXFILTER_MULTI, 518c2ecf20Sopenharmony_ci RXFILTER_PROMISC 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Driver local data */ 558c2ecf20Sopenharmony_cistruct enc28j60_net { 568c2ecf20Sopenharmony_ci struct net_device *netdev; 578c2ecf20Sopenharmony_ci struct spi_device *spi; 588c2ecf20Sopenharmony_ci struct mutex lock; 598c2ecf20Sopenharmony_ci struct sk_buff *tx_skb; 608c2ecf20Sopenharmony_ci struct work_struct tx_work; 618c2ecf20Sopenharmony_ci struct work_struct irq_work; 628c2ecf20Sopenharmony_ci struct work_struct setrx_work; 638c2ecf20Sopenharmony_ci struct work_struct restart_work; 648c2ecf20Sopenharmony_ci u8 bank; /* current register bank selected */ 658c2ecf20Sopenharmony_ci u16 next_pk_ptr; /* next packet pointer within FIFO */ 668c2ecf20Sopenharmony_ci u16 max_pk_counter; /* statistics: max packet counter */ 678c2ecf20Sopenharmony_ci u16 tx_retry_count; 688c2ecf20Sopenharmony_ci bool hw_enable; 698c2ecf20Sopenharmony_ci bool full_duplex; 708c2ecf20Sopenharmony_ci int rxfilter; 718c2ecf20Sopenharmony_ci u32 msg_enable; 728c2ecf20Sopenharmony_ci u8 spi_transfer_buf[SPI_TRANSFER_BUF_LEN]; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* use ethtool to change the level for any given device */ 768c2ecf20Sopenharmony_cistatic struct { 778c2ecf20Sopenharmony_ci u32 msg_enable; 788c2ecf20Sopenharmony_ci} debug = { -1 }; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * SPI read buffer 828c2ecf20Sopenharmony_ci * Wait for the SPI transfer and copy received data to destination. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cistatic int 858c2ecf20Sopenharmony_cispi_read_buf(struct enc28j60_net *priv, int len, u8 *data) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 888c2ecf20Sopenharmony_ci u8 *rx_buf = priv->spi_transfer_buf + 4; 898c2ecf20Sopenharmony_ci u8 *tx_buf = priv->spi_transfer_buf; 908c2ecf20Sopenharmony_ci struct spi_transfer tx = { 918c2ecf20Sopenharmony_ci .tx_buf = tx_buf, 928c2ecf20Sopenharmony_ci .len = SPI_OPLEN, 938c2ecf20Sopenharmony_ci }; 948c2ecf20Sopenharmony_ci struct spi_transfer rx = { 958c2ecf20Sopenharmony_ci .rx_buf = rx_buf, 968c2ecf20Sopenharmony_ci .len = len, 978c2ecf20Sopenharmony_ci }; 988c2ecf20Sopenharmony_ci struct spi_message msg; 998c2ecf20Sopenharmony_ci int ret; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci tx_buf[0] = ENC28J60_READ_BUF_MEM; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci spi_message_init(&msg); 1048c2ecf20Sopenharmony_ci spi_message_add_tail(&tx, &msg); 1058c2ecf20Sopenharmony_ci spi_message_add_tail(&rx, &msg); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ret = spi_sync(priv->spi, &msg); 1088c2ecf20Sopenharmony_ci if (ret == 0) { 1098c2ecf20Sopenharmony_ci memcpy(data, rx_buf, len); 1108c2ecf20Sopenharmony_ci ret = msg.status; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci if (ret && netif_msg_drv(priv)) 1138c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() failed: ret = %d\n", 1148c2ecf20Sopenharmony_ci __func__, ret); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return ret; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * SPI write buffer 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic int spi_write_buf(struct enc28j60_net *priv, int len, const u8 *data) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 1258c2ecf20Sopenharmony_ci int ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (len > SPI_TRANSFER_BUF_LEN - 1 || len <= 0) 1288c2ecf20Sopenharmony_ci ret = -EINVAL; 1298c2ecf20Sopenharmony_ci else { 1308c2ecf20Sopenharmony_ci priv->spi_transfer_buf[0] = ENC28J60_WRITE_BUF_MEM; 1318c2ecf20Sopenharmony_ci memcpy(&priv->spi_transfer_buf[1], data, len); 1328c2ecf20Sopenharmony_ci ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1); 1338c2ecf20Sopenharmony_ci if (ret && netif_msg_drv(priv)) 1348c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() failed: ret = %d\n", 1358c2ecf20Sopenharmony_ci __func__, ret); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci return ret; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * basic SPI read operation 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic u8 spi_read_op(struct enc28j60_net *priv, u8 op, u8 addr) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 1468c2ecf20Sopenharmony_ci u8 tx_buf[2]; 1478c2ecf20Sopenharmony_ci u8 rx_buf[4]; 1488c2ecf20Sopenharmony_ci u8 val = 0; 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci int slen = SPI_OPLEN; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* do dummy read if needed */ 1538c2ecf20Sopenharmony_ci if (addr & SPRD_MASK) 1548c2ecf20Sopenharmony_ci slen++; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci tx_buf[0] = op | (addr & ADDR_MASK); 1578c2ecf20Sopenharmony_ci ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen); 1588c2ecf20Sopenharmony_ci if (ret) 1598c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() failed: ret = %d\n", 1608c2ecf20Sopenharmony_ci __func__, ret); 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci val = rx_buf[slen - 1]; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return val; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* 1688c2ecf20Sopenharmony_ci * basic SPI write operation 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_cistatic int spi_write_op(struct enc28j60_net *priv, u8 op, u8 addr, u8 val) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 1738c2ecf20Sopenharmony_ci int ret; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci priv->spi_transfer_buf[0] = op | (addr & ADDR_MASK); 1768c2ecf20Sopenharmony_ci priv->spi_transfer_buf[1] = val; 1778c2ecf20Sopenharmony_ci ret = spi_write(priv->spi, priv->spi_transfer_buf, 2); 1788c2ecf20Sopenharmony_ci if (ret && netif_msg_drv(priv)) 1798c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() failed: ret = %d\n", 1808c2ecf20Sopenharmony_ci __func__, ret); 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void enc28j60_soft_reset(struct enc28j60_net *priv) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); 1878c2ecf20Sopenharmony_ci /* Errata workaround #1, CLKRDY check is unreliable, 1888c2ecf20Sopenharmony_ci * delay at least 1 ms instead */ 1898c2ecf20Sopenharmony_ci udelay(2000); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * select the current register bank if necessary 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_cistatic void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci u8 b = (addr & BANK_MASK) >> 5; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* These registers (EIE, EIR, ESTAT, ECON2, ECON1) 2008c2ecf20Sopenharmony_ci * are present in all banks, no need to switch bank. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci if (addr >= EIE && addr <= ECON1) 2038c2ecf20Sopenharmony_ci return; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* Clear or set each bank selection bit as needed */ 2068c2ecf20Sopenharmony_ci if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) { 2078c2ecf20Sopenharmony_ci if (b & ECON1_BSEL0) 2088c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, 2098c2ecf20Sopenharmony_ci ECON1_BSEL0); 2108c2ecf20Sopenharmony_ci else 2118c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, 2128c2ecf20Sopenharmony_ci ECON1_BSEL0); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) { 2158c2ecf20Sopenharmony_ci if (b & ECON1_BSEL1) 2168c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, 2178c2ecf20Sopenharmony_ci ECON1_BSEL1); 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, 2208c2ecf20Sopenharmony_ci ECON1_BSEL1); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci priv->bank = b; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* 2268c2ecf20Sopenharmony_ci * Register access routines through the SPI bus. 2278c2ecf20Sopenharmony_ci * Every register access comes in two flavours: 2288c2ecf20Sopenharmony_ci * - nolock_xxx: caller needs to invoke mutex_lock, usually to access 2298c2ecf20Sopenharmony_ci * atomically more than one register 2308c2ecf20Sopenharmony_ci * - locked_xxx: caller doesn't need to invoke mutex_lock, single access 2318c2ecf20Sopenharmony_ci * 2328c2ecf20Sopenharmony_ci * Some registers can be accessed through the bit field clear and 2338c2ecf20Sopenharmony_ci * bit field set to avoid a read modify write cycle. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/* 2378c2ecf20Sopenharmony_ci * Register bit field Set 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic void nolock_reg_bfset(struct enc28j60_net *priv, u8 addr, u8 mask) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci enc28j60_set_bank(priv, addr); 2428c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_BIT_FIELD_SET, addr, mask); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void locked_reg_bfset(struct enc28j60_net *priv, u8 addr, u8 mask) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 2488c2ecf20Sopenharmony_ci nolock_reg_bfset(priv, addr, mask); 2498c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* 2538c2ecf20Sopenharmony_ci * Register bit field Clear 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_cistatic void nolock_reg_bfclr(struct enc28j60_net *priv, u8 addr, u8 mask) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci enc28j60_set_bank(priv, addr); 2588c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, addr, mask); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void locked_reg_bfclr(struct enc28j60_net *priv, u8 addr, u8 mask) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 2648c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, addr, mask); 2658c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* 2698c2ecf20Sopenharmony_ci * Register byte read 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistatic int nolock_regb_read(struct enc28j60_net *priv, u8 address) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci enc28j60_set_bank(priv, address); 2748c2ecf20Sopenharmony_ci return spi_read_op(priv, ENC28J60_READ_CTRL_REG, address); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int locked_regb_read(struct enc28j60_net *priv, u8 address) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int ret; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 2828c2ecf20Sopenharmony_ci ret = nolock_regb_read(priv, address); 2838c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci/* 2898c2ecf20Sopenharmony_ci * Register word read 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic int nolock_regw_read(struct enc28j60_net *priv, u8 address) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int rl, rh; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci enc28j60_set_bank(priv, address); 2968c2ecf20Sopenharmony_ci rl = spi_read_op(priv, ENC28J60_READ_CTRL_REG, address); 2978c2ecf20Sopenharmony_ci rh = spi_read_op(priv, ENC28J60_READ_CTRL_REG, address + 1); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return (rh << 8) | rl; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int locked_regw_read(struct enc28j60_net *priv, u8 address) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci int ret; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 3078c2ecf20Sopenharmony_ci ret = nolock_regw_read(priv, address); 3088c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return ret; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci * Register byte write 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_cistatic void nolock_regb_write(struct enc28j60_net *priv, u8 address, u8 data) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci enc28j60_set_bank(priv, address); 3198c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address, data); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic void locked_regb_write(struct enc28j60_net *priv, u8 address, u8 data) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 3258c2ecf20Sopenharmony_ci nolock_regb_write(priv, address, data); 3268c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* 3308c2ecf20Sopenharmony_ci * Register word write 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_cistatic void nolock_regw_write(struct enc28j60_net *priv, u8 address, u16 data) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci enc28j60_set_bank(priv, address); 3358c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address, (u8) data); 3368c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address + 1, 3378c2ecf20Sopenharmony_ci (u8) (data >> 8)); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void locked_regw_write(struct enc28j60_net *priv, u8 address, u16 data) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 3438c2ecf20Sopenharmony_ci nolock_regw_write(priv, address, data); 3448c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/* 3488c2ecf20Sopenharmony_ci * Buffer memory read 3498c2ecf20Sopenharmony_ci * Select the starting address and execute a SPI buffer read. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_cistatic void enc28j60_mem_read(struct enc28j60_net *priv, u16 addr, int len, 3528c2ecf20Sopenharmony_ci u8 *data) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 3558c2ecf20Sopenharmony_ci nolock_regw_write(priv, ERDPTL, addr); 3568c2ecf20Sopenharmony_ci#ifdef CONFIG_ENC28J60_WRITEVERIFY 3578c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) { 3588c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 3598c2ecf20Sopenharmony_ci u16 reg; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci reg = nolock_regw_read(priv, ERDPTL); 3628c2ecf20Sopenharmony_ci if (reg != addr) 3638c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 3648c2ecf20Sopenharmony_ci "%s() error writing ERDPT (0x%04x - 0x%04x)\n", 3658c2ecf20Sopenharmony_ci __func__, reg, addr); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci#endif 3688c2ecf20Sopenharmony_ci spi_read_buf(priv, len, data); 3698c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* 3738c2ecf20Sopenharmony_ci * Write packet to enc28j60 TX buffer memory 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_cistatic void 3768c2ecf20Sopenharmony_cienc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 3818c2ecf20Sopenharmony_ci /* Set the write pointer to start of transmit buffer area */ 3828c2ecf20Sopenharmony_ci nolock_regw_write(priv, EWRPTL, TXSTART_INIT); 3838c2ecf20Sopenharmony_ci#ifdef CONFIG_ENC28J60_WRITEVERIFY 3848c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) { 3858c2ecf20Sopenharmony_ci u16 reg; 3868c2ecf20Sopenharmony_ci reg = nolock_regw_read(priv, EWRPTL); 3878c2ecf20Sopenharmony_ci if (reg != TXSTART_INIT) 3888c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 3898c2ecf20Sopenharmony_ci "%s() ERWPT:0x%04x != 0x%04x\n", 3908c2ecf20Sopenharmony_ci __func__, reg, TXSTART_INIT); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci#endif 3938c2ecf20Sopenharmony_ci /* Set the TXND pointer to correspond to the packet size given */ 3948c2ecf20Sopenharmony_ci nolock_regw_write(priv, ETXNDL, TXSTART_INIT + len); 3958c2ecf20Sopenharmony_ci /* write per-packet control byte */ 3968c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_WRITE_BUF_MEM, 0, 0x00); 3978c2ecf20Sopenharmony_ci if (netif_msg_hw(priv)) 3988c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 3998c2ecf20Sopenharmony_ci "%s() after control byte ERWPT:0x%04x\n", 4008c2ecf20Sopenharmony_ci __func__, nolock_regw_read(priv, EWRPTL)); 4018c2ecf20Sopenharmony_ci /* copy the packet into the transmit buffer */ 4028c2ecf20Sopenharmony_ci spi_write_buf(priv, len, data); 4038c2ecf20Sopenharmony_ci if (netif_msg_hw(priv)) 4048c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 4058c2ecf20Sopenharmony_ci "%s() after write packet ERWPT:0x%04x, len=%d\n", 4068c2ecf20Sopenharmony_ci __func__, nolock_regw_read(priv, EWRPTL), len); 4078c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int poll_ready(struct enc28j60_net *priv, u8 reg, u8 mask, u8 val) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 4138c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(20); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* 20 msec timeout read */ 4168c2ecf20Sopenharmony_ci while ((nolock_regb_read(priv, reg) & mask) != val) { 4178c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 4188c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 4198c2ecf20Sopenharmony_ci dev_dbg(dev, "reg %02x ready timeout!\n", reg); 4208c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci cpu_relax(); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* 4288c2ecf20Sopenharmony_ci * Wait until the PHY operation is complete. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_cistatic int wait_phy_ready(struct enc28j60_net *priv) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci return poll_ready(priv, MISTAT, MISTAT_BUSY, 0) ? 0 : 1; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* 4368c2ecf20Sopenharmony_ci * PHY register read 4378c2ecf20Sopenharmony_ci * PHY registers are not accessed directly, but through the MII. 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_cistatic u16 enc28j60_phy_read(struct enc28j60_net *priv, u8 address) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci u16 ret; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 4448c2ecf20Sopenharmony_ci /* set the PHY register address */ 4458c2ecf20Sopenharmony_ci nolock_regb_write(priv, MIREGADR, address); 4468c2ecf20Sopenharmony_ci /* start the register read operation */ 4478c2ecf20Sopenharmony_ci nolock_regb_write(priv, MICMD, MICMD_MIIRD); 4488c2ecf20Sopenharmony_ci /* wait until the PHY read completes */ 4498c2ecf20Sopenharmony_ci wait_phy_ready(priv); 4508c2ecf20Sopenharmony_ci /* quit reading */ 4518c2ecf20Sopenharmony_ci nolock_regb_write(priv, MICMD, 0x00); 4528c2ecf20Sopenharmony_ci /* return the data */ 4538c2ecf20Sopenharmony_ci ret = nolock_regw_read(priv, MIRDL); 4548c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return ret; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int enc28j60_phy_write(struct enc28j60_net *priv, u8 address, u16 data) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci int ret; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 4648c2ecf20Sopenharmony_ci /* set the PHY register address */ 4658c2ecf20Sopenharmony_ci nolock_regb_write(priv, MIREGADR, address); 4668c2ecf20Sopenharmony_ci /* write the PHY data */ 4678c2ecf20Sopenharmony_ci nolock_regw_write(priv, MIWRL, data); 4688c2ecf20Sopenharmony_ci /* wait until the PHY write completes and return */ 4698c2ecf20Sopenharmony_ci ret = wait_phy_ready(priv); 4708c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* 4768c2ecf20Sopenharmony_ci * Program the hardware MAC address from dev->dev_addr. 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_cistatic int enc28j60_set_hw_macaddr(struct net_device *ndev) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci int ret; 4818c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(ndev); 4828c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 4858c2ecf20Sopenharmony_ci if (!priv->hw_enable) { 4868c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 4878c2ecf20Sopenharmony_ci dev_info(dev, "%s: Setting MAC address to %pM\n", 4888c2ecf20Sopenharmony_ci ndev->name, ndev->dev_addr); 4898c2ecf20Sopenharmony_ci /* NOTE: MAC address in ENC28J60 is byte-backward */ 4908c2ecf20Sopenharmony_ci nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]); 4918c2ecf20Sopenharmony_ci nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]); 4928c2ecf20Sopenharmony_ci nolock_regb_write(priv, MAADR3, ndev->dev_addr[2]); 4938c2ecf20Sopenharmony_ci nolock_regb_write(priv, MAADR2, ndev->dev_addr[3]); 4948c2ecf20Sopenharmony_ci nolock_regb_write(priv, MAADR1, ndev->dev_addr[4]); 4958c2ecf20Sopenharmony_ci nolock_regb_write(priv, MAADR0, ndev->dev_addr[5]); 4968c2ecf20Sopenharmony_ci ret = 0; 4978c2ecf20Sopenharmony_ci } else { 4988c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 4998c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 5008c2ecf20Sopenharmony_ci "%s() Hardware must be disabled to set Mac address\n", 5018c2ecf20Sopenharmony_ci __func__); 5028c2ecf20Sopenharmony_ci ret = -EBUSY; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 5058c2ecf20Sopenharmony_ci return ret; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/* 5098c2ecf20Sopenharmony_ci * Store the new hardware address in dev->dev_addr, and update the MAC. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_cistatic int enc28j60_set_mac_address(struct net_device *dev, void *addr) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct sockaddr *address = addr; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (netif_running(dev)) 5168c2ecf20Sopenharmony_ci return -EBUSY; 5178c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(address->sa_data)) 5188c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci ether_addr_copy(dev->dev_addr, address->sa_data); 5218c2ecf20Sopenharmony_ci return enc28j60_set_hw_macaddr(dev); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/* 5258c2ecf20Sopenharmony_ci * Debug routine to dump useful register contents 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_cistatic void enc28j60_dump_regs(struct enc28j60_net *priv, const char *msg) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 5328c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 5338c2ecf20Sopenharmony_ci " %s\n" 5348c2ecf20Sopenharmony_ci "HwRevID: 0x%02x\n" 5358c2ecf20Sopenharmony_ci "Cntrl: ECON1 ECON2 ESTAT EIR EIE\n" 5368c2ecf20Sopenharmony_ci " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n" 5378c2ecf20Sopenharmony_ci "MAC : MACON1 MACON3 MACON4\n" 5388c2ecf20Sopenharmony_ci " 0x%02x 0x%02x 0x%02x\n" 5398c2ecf20Sopenharmony_ci "Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\n" 5408c2ecf20Sopenharmony_ci " 0x%04x 0x%04x 0x%04x 0x%04x " 5418c2ecf20Sopenharmony_ci "0x%02x 0x%02x 0x%04x\n" 5428c2ecf20Sopenharmony_ci "Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\n" 5438c2ecf20Sopenharmony_ci " 0x%04x 0x%04x 0x%02x 0x%02x 0x%02x\n", 5448c2ecf20Sopenharmony_ci msg, nolock_regb_read(priv, EREVID), 5458c2ecf20Sopenharmony_ci nolock_regb_read(priv, ECON1), nolock_regb_read(priv, ECON2), 5468c2ecf20Sopenharmony_ci nolock_regb_read(priv, ESTAT), nolock_regb_read(priv, EIR), 5478c2ecf20Sopenharmony_ci nolock_regb_read(priv, EIE), nolock_regb_read(priv, MACON1), 5488c2ecf20Sopenharmony_ci nolock_regb_read(priv, MACON3), nolock_regb_read(priv, MACON4), 5498c2ecf20Sopenharmony_ci nolock_regw_read(priv, ERXSTL), nolock_regw_read(priv, ERXNDL), 5508c2ecf20Sopenharmony_ci nolock_regw_read(priv, ERXWRPTL), 5518c2ecf20Sopenharmony_ci nolock_regw_read(priv, ERXRDPTL), 5528c2ecf20Sopenharmony_ci nolock_regb_read(priv, ERXFCON), 5538c2ecf20Sopenharmony_ci nolock_regb_read(priv, EPKTCNT), 5548c2ecf20Sopenharmony_ci nolock_regw_read(priv, MAMXFLL), nolock_regw_read(priv, ETXSTL), 5558c2ecf20Sopenharmony_ci nolock_regw_read(priv, ETXNDL), 5568c2ecf20Sopenharmony_ci nolock_regb_read(priv, MACLCON1), 5578c2ecf20Sopenharmony_ci nolock_regb_read(priv, MACLCON2), 5588c2ecf20Sopenharmony_ci nolock_regb_read(priv, MAPHSUP)); 5598c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci/* 5638c2ecf20Sopenharmony_ci * ERXRDPT need to be set always at odd addresses, refer to errata datasheet 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_cistatic u16 erxrdpt_workaround(u16 next_packet_ptr, u16 start, u16 end) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci u16 erxrdpt; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if ((next_packet_ptr - 1 < start) || (next_packet_ptr - 1 > end)) 5708c2ecf20Sopenharmony_ci erxrdpt = end; 5718c2ecf20Sopenharmony_ci else 5728c2ecf20Sopenharmony_ci erxrdpt = next_packet_ptr - 1; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return erxrdpt; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* 5788c2ecf20Sopenharmony_ci * Calculate wrap around when reading beyond the end of the RX buffer 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_cistatic u16 rx_packet_start(u16 ptr) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci if (ptr + RSV_SIZE > RXEND_INIT) 5838c2ecf20Sopenharmony_ci return (ptr + RSV_SIZE) - (RXEND_INIT - RXSTART_INIT + 1); 5848c2ecf20Sopenharmony_ci else 5858c2ecf20Sopenharmony_ci return ptr + RSV_SIZE; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 5918c2ecf20Sopenharmony_ci u16 erxrdpt; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (start > 0x1FFF || end > 0x1FFF || start > end) { 5948c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 5958c2ecf20Sopenharmony_ci dev_err(dev, "%s(%d, %d) RXFIFO bad parameters!\n", 5968c2ecf20Sopenharmony_ci __func__, start, end); 5978c2ecf20Sopenharmony_ci return; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci /* set receive buffer start + end */ 6008c2ecf20Sopenharmony_ci priv->next_pk_ptr = start; 6018c2ecf20Sopenharmony_ci nolock_regw_write(priv, ERXSTL, start); 6028c2ecf20Sopenharmony_ci erxrdpt = erxrdpt_workaround(priv->next_pk_ptr, start, end); 6038c2ecf20Sopenharmony_ci nolock_regw_write(priv, ERXRDPTL, erxrdpt); 6048c2ecf20Sopenharmony_ci nolock_regw_write(priv, ERXNDL, end); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (start > 0x1FFF || end > 0x1FFF || start > end) { 6128c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 6138c2ecf20Sopenharmony_ci dev_err(dev, "%s(%d, %d) TXFIFO bad parameters!\n", 6148c2ecf20Sopenharmony_ci __func__, start, end); 6158c2ecf20Sopenharmony_ci return; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci /* set transmit buffer start + end */ 6188c2ecf20Sopenharmony_ci nolock_regw_write(priv, ETXSTL, start); 6198c2ecf20Sopenharmony_ci nolock_regw_write(priv, ETXNDL, end); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci/* 6238c2ecf20Sopenharmony_ci * Low power mode shrinks power consumption about 100x, so we'd like 6248c2ecf20Sopenharmony_ci * the chip to be in that mode whenever it's inactive. (However, we 6258c2ecf20Sopenharmony_ci * can't stay in low power mode during suspend with WOL active.) 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_cistatic void enc28j60_lowpower(struct enc28j60_net *priv, bool is_low) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 6328c2ecf20Sopenharmony_ci dev_dbg(dev, "%s power...\n", is_low ? "low" : "high"); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 6358c2ecf20Sopenharmony_ci if (is_low) { 6368c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, ECON1, ECON1_RXEN); 6378c2ecf20Sopenharmony_ci poll_ready(priv, ESTAT, ESTAT_RXBUSY, 0); 6388c2ecf20Sopenharmony_ci poll_ready(priv, ECON1, ECON1_TXRTS, 0); 6398c2ecf20Sopenharmony_ci /* ECON2_VRPS was set during initialization */ 6408c2ecf20Sopenharmony_ci nolock_reg_bfset(priv, ECON2, ECON2_PWRSV); 6418c2ecf20Sopenharmony_ci } else { 6428c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, ECON2, ECON2_PWRSV); 6438c2ecf20Sopenharmony_ci poll_ready(priv, ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY); 6448c2ecf20Sopenharmony_ci /* caller sets ECON1_RXEN */ 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic int enc28j60_hw_init(struct enc28j60_net *priv) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 6528c2ecf20Sopenharmony_ci u8 reg; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 6558c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() - %s\n", __func__, 6568c2ecf20Sopenharmony_ci priv->full_duplex ? "FullDuplex" : "HalfDuplex"); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 6598c2ecf20Sopenharmony_ci /* first reset the chip */ 6608c2ecf20Sopenharmony_ci enc28j60_soft_reset(priv); 6618c2ecf20Sopenharmony_ci /* Clear ECON1 */ 6628c2ecf20Sopenharmony_ci spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, ECON1, 0x00); 6638c2ecf20Sopenharmony_ci priv->bank = 0; 6648c2ecf20Sopenharmony_ci priv->hw_enable = false; 6658c2ecf20Sopenharmony_ci priv->tx_retry_count = 0; 6668c2ecf20Sopenharmony_ci priv->max_pk_counter = 0; 6678c2ecf20Sopenharmony_ci priv->rxfilter = RXFILTER_NORMAL; 6688c2ecf20Sopenharmony_ci /* enable address auto increment and voltage regulator powersave */ 6698c2ecf20Sopenharmony_ci nolock_regb_write(priv, ECON2, ECON2_AUTOINC | ECON2_VRPS); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT); 6728c2ecf20Sopenharmony_ci nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT); 6738c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* 6768c2ecf20Sopenharmony_ci * Check the RevID. 6778c2ecf20Sopenharmony_ci * If it's 0x00 or 0xFF probably the enc28j60 is not mounted or 6788c2ecf20Sopenharmony_ci * damaged. 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ci reg = locked_regb_read(priv, EREVID); 6818c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 6828c2ecf20Sopenharmony_ci dev_info(dev, "chip RevID: 0x%02x\n", reg); 6838c2ecf20Sopenharmony_ci if (reg == 0x00 || reg == 0xff) { 6848c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 6858c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() Invalid RevId %d\n", 6868c2ecf20Sopenharmony_ci __func__, reg); 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* default filter mode: (unicast OR broadcast) AND crc valid */ 6918c2ecf20Sopenharmony_ci locked_regb_write(priv, ERXFCON, 6928c2ecf20Sopenharmony_ci ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* enable MAC receive */ 6958c2ecf20Sopenharmony_ci locked_regb_write(priv, MACON1, 6968c2ecf20Sopenharmony_ci MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); 6978c2ecf20Sopenharmony_ci /* enable automatic padding and CRC operations */ 6988c2ecf20Sopenharmony_ci if (priv->full_duplex) { 6998c2ecf20Sopenharmony_ci locked_regb_write(priv, MACON3, 7008c2ecf20Sopenharmony_ci MACON3_PADCFG0 | MACON3_TXCRCEN | 7018c2ecf20Sopenharmony_ci MACON3_FRMLNEN | MACON3_FULDPX); 7028c2ecf20Sopenharmony_ci /* set inter-frame gap (non-back-to-back) */ 7038c2ecf20Sopenharmony_ci locked_regb_write(priv, MAIPGL, 0x12); 7048c2ecf20Sopenharmony_ci /* set inter-frame gap (back-to-back) */ 7058c2ecf20Sopenharmony_ci locked_regb_write(priv, MABBIPG, 0x15); 7068c2ecf20Sopenharmony_ci } else { 7078c2ecf20Sopenharmony_ci locked_regb_write(priv, MACON3, 7088c2ecf20Sopenharmony_ci MACON3_PADCFG0 | MACON3_TXCRCEN | 7098c2ecf20Sopenharmony_ci MACON3_FRMLNEN); 7108c2ecf20Sopenharmony_ci locked_regb_write(priv, MACON4, 1 << 6); /* DEFER bit */ 7118c2ecf20Sopenharmony_ci /* set inter-frame gap (non-back-to-back) */ 7128c2ecf20Sopenharmony_ci locked_regw_write(priv, MAIPGL, 0x0C12); 7138c2ecf20Sopenharmony_ci /* set inter-frame gap (back-to-back) */ 7148c2ecf20Sopenharmony_ci locked_regb_write(priv, MABBIPG, 0x12); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * MACLCON1 (default) 7188c2ecf20Sopenharmony_ci * MACLCON2 (default) 7198c2ecf20Sopenharmony_ci * Set the maximum packet size which the controller will accept. 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci locked_regw_write(priv, MAMXFLL, MAX_FRAMELEN); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* Configure LEDs */ 7248c2ecf20Sopenharmony_ci if (!enc28j60_phy_write(priv, PHLCON, ENC28J60_LAMPS_MODE)) 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (priv->full_duplex) { 7288c2ecf20Sopenharmony_ci if (!enc28j60_phy_write(priv, PHCON1, PHCON1_PDPXMD)) 7298c2ecf20Sopenharmony_ci return 0; 7308c2ecf20Sopenharmony_ci if (!enc28j60_phy_write(priv, PHCON2, 0x00)) 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci } else { 7338c2ecf20Sopenharmony_ci if (!enc28j60_phy_write(priv, PHCON1, 0x00)) 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci if (!enc28j60_phy_write(priv, PHCON2, PHCON2_HDLDIS)) 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci if (netif_msg_hw(priv)) 7398c2ecf20Sopenharmony_ci enc28j60_dump_regs(priv, "Hw initialized."); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return 1; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void enc28j60_hw_enable(struct enc28j60_net *priv) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* enable interrupts */ 7498c2ecf20Sopenharmony_ci if (netif_msg_hw(priv)) 7508c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() enabling interrupts.\n", 7518c2ecf20Sopenharmony_ci __func__); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci enc28j60_phy_write(priv, PHIE, PHIE_PGEIE | PHIE_PLNKIE); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 7568c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, EIR, EIR_DMAIF | EIR_LINKIF | 7578c2ecf20Sopenharmony_ci EIR_TXIF | EIR_TXERIF | EIR_RXERIF | EIR_PKTIF); 7588c2ecf20Sopenharmony_ci nolock_regb_write(priv, EIE, EIE_INTIE | EIE_PKTIE | EIE_LINKIE | 7598c2ecf20Sopenharmony_ci EIE_TXIE | EIE_TXERIE | EIE_RXERIE); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* enable receive logic */ 7628c2ecf20Sopenharmony_ci nolock_reg_bfset(priv, ECON1, ECON1_RXEN); 7638c2ecf20Sopenharmony_ci priv->hw_enable = true; 7648c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic void enc28j60_hw_disable(struct enc28j60_net *priv) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 7708c2ecf20Sopenharmony_ci /* disable interrupts and packet reception */ 7718c2ecf20Sopenharmony_ci nolock_regb_write(priv, EIE, 0x00); 7728c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, ECON1, ECON1_RXEN); 7738c2ecf20Sopenharmony_ci priv->hw_enable = false; 7748c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic int 7788c2ecf20Sopenharmony_cienc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(ndev); 7818c2ecf20Sopenharmony_ci int ret = 0; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (!priv->hw_enable) { 7848c2ecf20Sopenharmony_ci /* link is in low power mode now; duplex setting 7858c2ecf20Sopenharmony_ci * will take effect on next enc28j60_hw_init(). 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_ci if (autoneg == AUTONEG_DISABLE && speed == SPEED_10) 7888c2ecf20Sopenharmony_ci priv->full_duplex = (duplex == DUPLEX_FULL); 7898c2ecf20Sopenharmony_ci else { 7908c2ecf20Sopenharmony_ci if (netif_msg_link(priv)) 7918c2ecf20Sopenharmony_ci netdev_warn(ndev, "unsupported link setting\n"); 7928c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci } else { 7958c2ecf20Sopenharmony_ci if (netif_msg_link(priv)) 7968c2ecf20Sopenharmony_ci netdev_warn(ndev, "Warning: hw must be disabled to set link mode\n"); 7978c2ecf20Sopenharmony_ci ret = -EBUSY; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci return ret; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci/* 8038c2ecf20Sopenharmony_ci * Read the Transmit Status Vector 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_cistatic void enc28j60_read_tsv(struct enc28j60_net *priv, u8 tsv[TSV_SIZE]) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 8088c2ecf20Sopenharmony_ci int endptr; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci endptr = locked_regw_read(priv, ETXNDL); 8118c2ecf20Sopenharmony_ci if (netif_msg_hw(priv)) 8128c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "reading TSV at addr:0x%04x\n", 8138c2ecf20Sopenharmony_ci endptr + 1); 8148c2ecf20Sopenharmony_ci enc28j60_mem_read(priv, endptr + 1, TSV_SIZE, tsv); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic void enc28j60_dump_tsv(struct enc28j60_net *priv, const char *msg, 8188c2ecf20Sopenharmony_ci u8 tsv[TSV_SIZE]) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 8218c2ecf20Sopenharmony_ci u16 tmp1, tmp2; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s - TSV:\n", msg); 8248c2ecf20Sopenharmony_ci tmp1 = tsv[1]; 8258c2ecf20Sopenharmony_ci tmp1 <<= 8; 8268c2ecf20Sopenharmony_ci tmp1 |= tsv[0]; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci tmp2 = tsv[5]; 8298c2ecf20Sopenharmony_ci tmp2 <<= 8; 8308c2ecf20Sopenharmony_ci tmp2 |= tsv[4]; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8338c2ecf20Sopenharmony_ci "ByteCount: %d, CollisionCount: %d, TotByteOnWire: %d\n", 8348c2ecf20Sopenharmony_ci tmp1, tsv[2] & 0x0f, tmp2); 8358c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8368c2ecf20Sopenharmony_ci "TxDone: %d, CRCErr:%d, LenChkErr: %d, LenOutOfRange: %d\n", 8378c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXDONE), 8388c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXCRCERROR), 8398c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXLENCHKERROR), 8408c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXLENOUTOFRANGE)); 8418c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8428c2ecf20Sopenharmony_ci "Multicast: %d, Broadcast: %d, PacketDefer: %d, ExDefer: %d\n", 8438c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXMULTICAST), 8448c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXBROADCAST), 8458c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXPACKETDEFER), 8468c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXEXDEFER)); 8478c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8488c2ecf20Sopenharmony_ci "ExCollision: %d, LateCollision: %d, Giant: %d, Underrun: %d\n", 8498c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXEXCOLLISION), 8508c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXLATECOLLISION), 8518c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXGIANT), TSV_GETBIT(tsv, TSV_TXUNDERRUN)); 8528c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8538c2ecf20Sopenharmony_ci "ControlFrame: %d, PauseFrame: %d, BackPressApp: %d, VLanTagFrame: %d\n", 8548c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXCONTROLFRAME), 8558c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXPAUSEFRAME), 8568c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_BACKPRESSUREAPP), 8578c2ecf20Sopenharmony_ci TSV_GETBIT(tsv, TSV_TXVLANTAGFRAME)); 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci/* 8618c2ecf20Sopenharmony_ci * Receive Status vector 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_cistatic void enc28j60_dump_rsv(struct enc28j60_net *priv, const char *msg, 8648c2ecf20Sopenharmony_ci u16 pk_ptr, int len, u16 sts) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s - NextPk: 0x%04x - RSV:\n", msg, pk_ptr); 8698c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "ByteCount: %d, DribbleNibble: %d\n", 8708c2ecf20Sopenharmony_ci len, RSV_GETBIT(sts, RSV_DRIBBLENIBBLE)); 8718c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8728c2ecf20Sopenharmony_ci "RxOK: %d, CRCErr:%d, LenChkErr: %d, LenOutOfRange: %d\n", 8738c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXOK), 8748c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_CRCERROR), 8758c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_LENCHECKERR), 8768c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_LENOUTOFRANGE)); 8778c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8788c2ecf20Sopenharmony_ci "Multicast: %d, Broadcast: %d, LongDropEvent: %d, CarrierEvent: %d\n", 8798c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXMULTICAST), 8808c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXBROADCAST), 8818c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXLONGEVDROPEV), 8828c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_CARRIEREV)); 8838c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 8848c2ecf20Sopenharmony_ci "ControlFrame: %d, PauseFrame: %d, UnknownOp: %d, VLanTagFrame: %d\n", 8858c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXCONTROLFRAME), 8868c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXPAUSEFRAME), 8878c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXUNKNOWNOPCODE), 8888c2ecf20Sopenharmony_ci RSV_GETBIT(sts, RSV_RXTYPEVLAN)); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic void dump_packet(const char *msg, int len, const char *data) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci printk(KERN_DEBUG DRV_NAME ": %s - packet len:%d\n", msg, len); 8948c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1, 8958c2ecf20Sopenharmony_ci data, len, true); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/* 8998c2ecf20Sopenharmony_ci * Hardware receive function. 9008c2ecf20Sopenharmony_ci * Read the buffer memory, update the FIFO pointer to free the buffer, 9018c2ecf20Sopenharmony_ci * check the status vector and decrement the packet counter. 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_cistatic void enc28j60_hw_rx(struct net_device *ndev) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(ndev); 9068c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 9078c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 9088c2ecf20Sopenharmony_ci u16 erxrdpt, next_packet, rxstat; 9098c2ecf20Sopenharmony_ci u8 rsv[RSV_SIZE]; 9108c2ecf20Sopenharmony_ci int len; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (netif_msg_rx_status(priv)) 9138c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "RX pk_addr:0x%04x\n", 9148c2ecf20Sopenharmony_ci priv->next_pk_ptr); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (unlikely(priv->next_pk_ptr > RXEND_INIT)) { 9178c2ecf20Sopenharmony_ci if (netif_msg_rx_err(priv)) 9188c2ecf20Sopenharmony_ci netdev_err(ndev, "%s() Invalid packet address!! 0x%04x\n", 9198c2ecf20Sopenharmony_ci __func__, priv->next_pk_ptr); 9208c2ecf20Sopenharmony_ci /* packet address corrupted: reset RX logic */ 9218c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 9228c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, ECON1, ECON1_RXEN); 9238c2ecf20Sopenharmony_ci nolock_reg_bfset(priv, ECON1, ECON1_RXRST); 9248c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, ECON1, ECON1_RXRST); 9258c2ecf20Sopenharmony_ci nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT); 9268c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, EIR, EIR_RXERIF); 9278c2ecf20Sopenharmony_ci nolock_reg_bfset(priv, ECON1, ECON1_RXEN); 9288c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 9298c2ecf20Sopenharmony_ci ndev->stats.rx_errors++; 9308c2ecf20Sopenharmony_ci return; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci /* Read next packet pointer and rx status vector */ 9338c2ecf20Sopenharmony_ci enc28j60_mem_read(priv, priv->next_pk_ptr, sizeof(rsv), rsv); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci next_packet = rsv[1]; 9368c2ecf20Sopenharmony_ci next_packet <<= 8; 9378c2ecf20Sopenharmony_ci next_packet |= rsv[0]; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci len = rsv[3]; 9408c2ecf20Sopenharmony_ci len <<= 8; 9418c2ecf20Sopenharmony_ci len |= rsv[2]; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci rxstat = rsv[5]; 9448c2ecf20Sopenharmony_ci rxstat <<= 8; 9458c2ecf20Sopenharmony_ci rxstat |= rsv[4]; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (netif_msg_rx_status(priv)) 9488c2ecf20Sopenharmony_ci enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (!RSV_GETBIT(rxstat, RSV_RXOK) || len > MAX_FRAMELEN) { 9518c2ecf20Sopenharmony_ci if (netif_msg_rx_err(priv)) 9528c2ecf20Sopenharmony_ci netdev_err(ndev, "Rx Error (%04x)\n", rxstat); 9538c2ecf20Sopenharmony_ci ndev->stats.rx_errors++; 9548c2ecf20Sopenharmony_ci if (RSV_GETBIT(rxstat, RSV_CRCERROR)) 9558c2ecf20Sopenharmony_ci ndev->stats.rx_crc_errors++; 9568c2ecf20Sopenharmony_ci if (RSV_GETBIT(rxstat, RSV_LENCHECKERR)) 9578c2ecf20Sopenharmony_ci ndev->stats.rx_frame_errors++; 9588c2ecf20Sopenharmony_ci if (len > MAX_FRAMELEN) 9598c2ecf20Sopenharmony_ci ndev->stats.rx_over_errors++; 9608c2ecf20Sopenharmony_ci } else { 9618c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(ndev, len + NET_IP_ALIGN); 9628c2ecf20Sopenharmony_ci if (!skb) { 9638c2ecf20Sopenharmony_ci if (netif_msg_rx_err(priv)) 9648c2ecf20Sopenharmony_ci netdev_err(ndev, "out of memory for Rx'd frame\n"); 9658c2ecf20Sopenharmony_ci ndev->stats.rx_dropped++; 9668c2ecf20Sopenharmony_ci } else { 9678c2ecf20Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 9688c2ecf20Sopenharmony_ci /* copy the packet from the receive buffer */ 9698c2ecf20Sopenharmony_ci enc28j60_mem_read(priv, 9708c2ecf20Sopenharmony_ci rx_packet_start(priv->next_pk_ptr), 9718c2ecf20Sopenharmony_ci len, skb_put(skb, len)); 9728c2ecf20Sopenharmony_ci if (netif_msg_pktdata(priv)) 9738c2ecf20Sopenharmony_ci dump_packet(__func__, skb->len, skb->data); 9748c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, ndev); 9758c2ecf20Sopenharmony_ci /* update statistics */ 9768c2ecf20Sopenharmony_ci ndev->stats.rx_packets++; 9778c2ecf20Sopenharmony_ci ndev->stats.rx_bytes += len; 9788c2ecf20Sopenharmony_ci netif_rx_ni(skb); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci /* 9828c2ecf20Sopenharmony_ci * Move the RX read pointer to the start of the next 9838c2ecf20Sopenharmony_ci * received packet. 9848c2ecf20Sopenharmony_ci * This frees the memory we just read out. 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_ci erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT); 9878c2ecf20Sopenharmony_ci if (netif_msg_hw(priv)) 9888c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%s() ERXRDPT:0x%04x\n", 9898c2ecf20Sopenharmony_ci __func__, erxrdpt); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 9928c2ecf20Sopenharmony_ci nolock_regw_write(priv, ERXRDPTL, erxrdpt); 9938c2ecf20Sopenharmony_ci#ifdef CONFIG_ENC28J60_WRITEVERIFY 9948c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) { 9958c2ecf20Sopenharmony_ci u16 reg; 9968c2ecf20Sopenharmony_ci reg = nolock_regw_read(priv, ERXRDPTL); 9978c2ecf20Sopenharmony_ci if (reg != erxrdpt) 9988c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 9998c2ecf20Sopenharmony_ci "%s() ERXRDPT verify error (0x%04x - 0x%04x)\n", 10008c2ecf20Sopenharmony_ci __func__, reg, erxrdpt); 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci#endif 10038c2ecf20Sopenharmony_ci priv->next_pk_ptr = next_packet; 10048c2ecf20Sopenharmony_ci /* we are done with this packet, decrement the packet counter */ 10058c2ecf20Sopenharmony_ci nolock_reg_bfset(priv, ECON2, ECON2_PKTDEC); 10068c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci/* 10108c2ecf20Sopenharmony_ci * Calculate free space in RxFIFO 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_cistatic int enc28j60_get_free_rxfifo(struct enc28j60_net *priv) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci struct net_device *ndev = priv->netdev; 10158c2ecf20Sopenharmony_ci int epkcnt, erxst, erxnd, erxwr, erxrd; 10168c2ecf20Sopenharmony_ci int free_space; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 10198c2ecf20Sopenharmony_ci epkcnt = nolock_regb_read(priv, EPKTCNT); 10208c2ecf20Sopenharmony_ci if (epkcnt >= 255) 10218c2ecf20Sopenharmony_ci free_space = -1; 10228c2ecf20Sopenharmony_ci else { 10238c2ecf20Sopenharmony_ci erxst = nolock_regw_read(priv, ERXSTL); 10248c2ecf20Sopenharmony_ci erxnd = nolock_regw_read(priv, ERXNDL); 10258c2ecf20Sopenharmony_ci erxwr = nolock_regw_read(priv, ERXWRPTL); 10268c2ecf20Sopenharmony_ci erxrd = nolock_regw_read(priv, ERXRDPTL); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (erxwr > erxrd) 10298c2ecf20Sopenharmony_ci free_space = (erxnd - erxst) - (erxwr - erxrd); 10308c2ecf20Sopenharmony_ci else if (erxwr == erxrd) 10318c2ecf20Sopenharmony_ci free_space = (erxnd - erxst); 10328c2ecf20Sopenharmony_ci else 10338c2ecf20Sopenharmony_ci free_space = erxrd - erxwr - 1; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 10368c2ecf20Sopenharmony_ci if (netif_msg_rx_status(priv)) 10378c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "%s() free_space = %d\n", 10388c2ecf20Sopenharmony_ci __func__, free_space); 10398c2ecf20Sopenharmony_ci return free_space; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci/* 10438c2ecf20Sopenharmony_ci * Access the PHY to determine link status 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_cistatic void enc28j60_check_link_status(struct net_device *ndev) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(ndev); 10488c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 10498c2ecf20Sopenharmony_ci u16 reg; 10508c2ecf20Sopenharmony_ci int duplex; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci reg = enc28j60_phy_read(priv, PHSTAT2); 10538c2ecf20Sopenharmony_ci if (netif_msg_hw(priv)) 10548c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 10558c2ecf20Sopenharmony_ci "%s() PHSTAT1: %04x, PHSTAT2: %04x\n", __func__, 10568c2ecf20Sopenharmony_ci enc28j60_phy_read(priv, PHSTAT1), reg); 10578c2ecf20Sopenharmony_ci duplex = reg & PHSTAT2_DPXSTAT; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (reg & PHSTAT2_LSTAT) { 10608c2ecf20Sopenharmony_ci netif_carrier_on(ndev); 10618c2ecf20Sopenharmony_ci if (netif_msg_ifup(priv)) 10628c2ecf20Sopenharmony_ci netdev_info(ndev, "link up - %s\n", 10638c2ecf20Sopenharmony_ci duplex ? "Full duplex" : "Half duplex"); 10648c2ecf20Sopenharmony_ci } else { 10658c2ecf20Sopenharmony_ci if (netif_msg_ifdown(priv)) 10668c2ecf20Sopenharmony_ci netdev_info(ndev, "link down\n"); 10678c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistatic void enc28j60_tx_clear(struct net_device *ndev, bool err) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(ndev); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (err) 10768c2ecf20Sopenharmony_ci ndev->stats.tx_errors++; 10778c2ecf20Sopenharmony_ci else 10788c2ecf20Sopenharmony_ci ndev->stats.tx_packets++; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (priv->tx_skb) { 10818c2ecf20Sopenharmony_ci if (!err) 10828c2ecf20Sopenharmony_ci ndev->stats.tx_bytes += priv->tx_skb->len; 10838c2ecf20Sopenharmony_ci dev_kfree_skb(priv->tx_skb); 10848c2ecf20Sopenharmony_ci priv->tx_skb = NULL; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci locked_reg_bfclr(priv, ECON1, ECON1_TXRTS); 10878c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci/* 10918c2ecf20Sopenharmony_ci * RX handler 10928c2ecf20Sopenharmony_ci * Ignore PKTIF because is unreliable! (Look at the errata datasheet) 10938c2ecf20Sopenharmony_ci * Check EPKTCNT is the suggested workaround. 10948c2ecf20Sopenharmony_ci * We don't need to clear interrupt flag, automatically done when 10958c2ecf20Sopenharmony_ci * enc28j60_hw_rx() decrements the packet counter. 10968c2ecf20Sopenharmony_ci * Returns how many packet processed. 10978c2ecf20Sopenharmony_ci */ 10988c2ecf20Sopenharmony_cistatic int enc28j60_rx_interrupt(struct net_device *ndev) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(ndev); 11018c2ecf20Sopenharmony_ci int pk_counter, ret; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci pk_counter = locked_regb_read(priv, EPKTCNT); 11048c2ecf20Sopenharmony_ci if (pk_counter && netif_msg_intr(priv)) 11058c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "intRX, pk_cnt: %d\n", 11068c2ecf20Sopenharmony_ci pk_counter); 11078c2ecf20Sopenharmony_ci if (pk_counter > priv->max_pk_counter) { 11088c2ecf20Sopenharmony_ci /* update statistics */ 11098c2ecf20Sopenharmony_ci priv->max_pk_counter = pk_counter; 11108c2ecf20Sopenharmony_ci if (netif_msg_rx_status(priv) && priv->max_pk_counter > 1) 11118c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "RX max_pk_cnt: %d\n", 11128c2ecf20Sopenharmony_ci priv->max_pk_counter); 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci ret = pk_counter; 11158c2ecf20Sopenharmony_ci while (pk_counter-- > 0) 11168c2ecf20Sopenharmony_ci enc28j60_hw_rx(ndev); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return ret; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic void enc28j60_irq_work_handler(struct work_struct *work) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct enc28j60_net *priv = 11248c2ecf20Sopenharmony_ci container_of(work, struct enc28j60_net, irq_work); 11258c2ecf20Sopenharmony_ci struct net_device *ndev = priv->netdev; 11268c2ecf20Sopenharmony_ci int intflags, loop; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* disable further interrupts */ 11298c2ecf20Sopenharmony_ci locked_reg_bfclr(priv, EIE, EIE_INTIE); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci do { 11328c2ecf20Sopenharmony_ci loop = 0; 11338c2ecf20Sopenharmony_ci intflags = locked_regb_read(priv, EIR); 11348c2ecf20Sopenharmony_ci /* DMA interrupt handler (not currently used) */ 11358c2ecf20Sopenharmony_ci if ((intflags & EIR_DMAIF) != 0) { 11368c2ecf20Sopenharmony_ci loop++; 11378c2ecf20Sopenharmony_ci if (netif_msg_intr(priv)) 11388c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "intDMA(%d)\n", 11398c2ecf20Sopenharmony_ci loop); 11408c2ecf20Sopenharmony_ci locked_reg_bfclr(priv, EIR, EIR_DMAIF); 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci /* LINK changed handler */ 11438c2ecf20Sopenharmony_ci if ((intflags & EIR_LINKIF) != 0) { 11448c2ecf20Sopenharmony_ci loop++; 11458c2ecf20Sopenharmony_ci if (netif_msg_intr(priv)) 11468c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "intLINK(%d)\n", 11478c2ecf20Sopenharmony_ci loop); 11488c2ecf20Sopenharmony_ci enc28j60_check_link_status(ndev); 11498c2ecf20Sopenharmony_ci /* read PHIR to clear the flag */ 11508c2ecf20Sopenharmony_ci enc28j60_phy_read(priv, PHIR); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci /* TX complete handler */ 11538c2ecf20Sopenharmony_ci if (((intflags & EIR_TXIF) != 0) && 11548c2ecf20Sopenharmony_ci ((intflags & EIR_TXERIF) == 0)) { 11558c2ecf20Sopenharmony_ci bool err = false; 11568c2ecf20Sopenharmony_ci loop++; 11578c2ecf20Sopenharmony_ci if (netif_msg_intr(priv)) 11588c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "intTX(%d)\n", 11598c2ecf20Sopenharmony_ci loop); 11608c2ecf20Sopenharmony_ci priv->tx_retry_count = 0; 11618c2ecf20Sopenharmony_ci if (locked_regb_read(priv, ESTAT) & ESTAT_TXABRT) { 11628c2ecf20Sopenharmony_ci if (netif_msg_tx_err(priv)) 11638c2ecf20Sopenharmony_ci netdev_err(ndev, "Tx Error (aborted)\n"); 11648c2ecf20Sopenharmony_ci err = true; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci if (netif_msg_tx_done(priv)) { 11678c2ecf20Sopenharmony_ci u8 tsv[TSV_SIZE]; 11688c2ecf20Sopenharmony_ci enc28j60_read_tsv(priv, tsv); 11698c2ecf20Sopenharmony_ci enc28j60_dump_tsv(priv, "Tx Done", tsv); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci enc28j60_tx_clear(ndev, err); 11728c2ecf20Sopenharmony_ci locked_reg_bfclr(priv, EIR, EIR_TXIF); 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci /* TX Error handler */ 11758c2ecf20Sopenharmony_ci if ((intflags & EIR_TXERIF) != 0) { 11768c2ecf20Sopenharmony_ci u8 tsv[TSV_SIZE]; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci loop++; 11798c2ecf20Sopenharmony_ci if (netif_msg_intr(priv)) 11808c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "intTXErr(%d)\n", 11818c2ecf20Sopenharmony_ci loop); 11828c2ecf20Sopenharmony_ci locked_reg_bfclr(priv, ECON1, ECON1_TXRTS); 11838c2ecf20Sopenharmony_ci enc28j60_read_tsv(priv, tsv); 11848c2ecf20Sopenharmony_ci if (netif_msg_tx_err(priv)) 11858c2ecf20Sopenharmony_ci enc28j60_dump_tsv(priv, "Tx Error", tsv); 11868c2ecf20Sopenharmony_ci /* Reset TX logic */ 11878c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 11888c2ecf20Sopenharmony_ci nolock_reg_bfset(priv, ECON1, ECON1_TXRST); 11898c2ecf20Sopenharmony_ci nolock_reg_bfclr(priv, ECON1, ECON1_TXRST); 11908c2ecf20Sopenharmony_ci nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT); 11918c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 11928c2ecf20Sopenharmony_ci /* Transmit Late collision check for retransmit */ 11938c2ecf20Sopenharmony_ci if (TSV_GETBIT(tsv, TSV_TXLATECOLLISION)) { 11948c2ecf20Sopenharmony_ci if (netif_msg_tx_err(priv)) 11958c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, 11968c2ecf20Sopenharmony_ci "LateCollision TXErr (%d)\n", 11978c2ecf20Sopenharmony_ci priv->tx_retry_count); 11988c2ecf20Sopenharmony_ci if (priv->tx_retry_count++ < MAX_TX_RETRYCOUNT) 11998c2ecf20Sopenharmony_ci locked_reg_bfset(priv, ECON1, 12008c2ecf20Sopenharmony_ci ECON1_TXRTS); 12018c2ecf20Sopenharmony_ci else 12028c2ecf20Sopenharmony_ci enc28j60_tx_clear(ndev, true); 12038c2ecf20Sopenharmony_ci } else 12048c2ecf20Sopenharmony_ci enc28j60_tx_clear(ndev, true); 12058c2ecf20Sopenharmony_ci locked_reg_bfclr(priv, EIR, EIR_TXERIF | EIR_TXIF); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci /* RX Error handler */ 12088c2ecf20Sopenharmony_ci if ((intflags & EIR_RXERIF) != 0) { 12098c2ecf20Sopenharmony_ci loop++; 12108c2ecf20Sopenharmony_ci if (netif_msg_intr(priv)) 12118c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "intRXErr(%d)\n", 12128c2ecf20Sopenharmony_ci loop); 12138c2ecf20Sopenharmony_ci /* Check free FIFO space to flag RX overrun */ 12148c2ecf20Sopenharmony_ci if (enc28j60_get_free_rxfifo(priv) <= 0) { 12158c2ecf20Sopenharmony_ci if (netif_msg_rx_err(priv)) 12168c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "RX Overrun\n"); 12178c2ecf20Sopenharmony_ci ndev->stats.rx_dropped++; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci locked_reg_bfclr(priv, EIR, EIR_RXERIF); 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci /* RX handler */ 12228c2ecf20Sopenharmony_ci if (enc28j60_rx_interrupt(ndev)) 12238c2ecf20Sopenharmony_ci loop++; 12248c2ecf20Sopenharmony_ci } while (loop); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* re-enable interrupts */ 12278c2ecf20Sopenharmony_ci locked_reg_bfset(priv, EIE, EIE_INTIE); 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci/* 12318c2ecf20Sopenharmony_ci * Hardware transmit function. 12328c2ecf20Sopenharmony_ci * Fill the buffer memory and send the contents of the transmit buffer 12338c2ecf20Sopenharmony_ci * onto the network 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_cistatic void enc28j60_hw_tx(struct enc28j60_net *priv) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct net_device *ndev = priv->netdev; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci BUG_ON(!priv->tx_skb); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (netif_msg_tx_queued(priv)) 12428c2ecf20Sopenharmony_ci netdev_printk(KERN_DEBUG, ndev, "Tx Packet Len:%d\n", 12438c2ecf20Sopenharmony_ci priv->tx_skb->len); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (netif_msg_pktdata(priv)) 12468c2ecf20Sopenharmony_ci dump_packet(__func__, 12478c2ecf20Sopenharmony_ci priv->tx_skb->len, priv->tx_skb->data); 12488c2ecf20Sopenharmony_ci enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci#ifdef CONFIG_ENC28J60_WRITEVERIFY 12518c2ecf20Sopenharmony_ci /* readback and verify written data */ 12528c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) { 12538c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 12548c2ecf20Sopenharmony_ci int test_len, k; 12558c2ecf20Sopenharmony_ci u8 test_buf[64]; /* limit the test to the first 64 bytes */ 12568c2ecf20Sopenharmony_ci int okflag; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci test_len = priv->tx_skb->len; 12598c2ecf20Sopenharmony_ci if (test_len > sizeof(test_buf)) 12608c2ecf20Sopenharmony_ci test_len = sizeof(test_buf); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* + 1 to skip control byte */ 12638c2ecf20Sopenharmony_ci enc28j60_mem_read(priv, TXSTART_INIT + 1, test_len, test_buf); 12648c2ecf20Sopenharmony_ci okflag = 1; 12658c2ecf20Sopenharmony_ci for (k = 0; k < test_len; k++) { 12668c2ecf20Sopenharmony_ci if (priv->tx_skb->data[k] != test_buf[k]) { 12678c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, 12688c2ecf20Sopenharmony_ci "Error, %d location differ: 0x%02x-0x%02x\n", 12698c2ecf20Sopenharmony_ci k, priv->tx_skb->data[k], test_buf[k]); 12708c2ecf20Sopenharmony_ci okflag = 0; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci if (!okflag) 12748c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "Tx write buffer, verify ERROR!\n"); 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci#endif 12778c2ecf20Sopenharmony_ci /* set TX request flag */ 12788c2ecf20Sopenharmony_ci locked_reg_bfset(priv, ECON1, ECON1_TXRTS); 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cistatic netdev_tx_t enc28j60_send_packet(struct sk_buff *skb, 12828c2ecf20Sopenharmony_ci struct net_device *dev) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* If some error occurs while trying to transmit this 12878c2ecf20Sopenharmony_ci * packet, you should return '1' from this function. 12888c2ecf20Sopenharmony_ci * In such a case you _may not_ do anything to the 12898c2ecf20Sopenharmony_ci * SKB, it is still owned by the network queueing 12908c2ecf20Sopenharmony_ci * layer when an error is returned. This means you 12918c2ecf20Sopenharmony_ci * may not modify any SKB fields, you may not free 12928c2ecf20Sopenharmony_ci * the SKB, etc. 12938c2ecf20Sopenharmony_ci */ 12948c2ecf20Sopenharmony_ci netif_stop_queue(dev); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* Remember the skb for deferred processing */ 12978c2ecf20Sopenharmony_ci priv->tx_skb = skb; 12988c2ecf20Sopenharmony_ci schedule_work(&priv->tx_work); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 13018c2ecf20Sopenharmony_ci} 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_cistatic void enc28j60_tx_work_handler(struct work_struct *work) 13048c2ecf20Sopenharmony_ci{ 13058c2ecf20Sopenharmony_ci struct enc28j60_net *priv = 13068c2ecf20Sopenharmony_ci container_of(work, struct enc28j60_net, tx_work); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* actual delivery of data */ 13098c2ecf20Sopenharmony_ci enc28j60_hw_tx(priv); 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic irqreturn_t enc28j60_irq(int irq, void *dev_id) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct enc28j60_net *priv = dev_id; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* 13178c2ecf20Sopenharmony_ci * Can't do anything in interrupt context because we need to 13188c2ecf20Sopenharmony_ci * block (spi_sync() is blocking) so fire of the interrupt 13198c2ecf20Sopenharmony_ci * handling workqueue. 13208c2ecf20Sopenharmony_ci * Remember that we access enc28j60 registers through SPI bus 13218c2ecf20Sopenharmony_ci * via spi_sync() call. 13228c2ecf20Sopenharmony_ci */ 13238c2ecf20Sopenharmony_ci schedule_work(&priv->irq_work); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic void enc28j60_tx_timeout(struct net_device *ndev, unsigned int txqueue) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(ndev); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci if (netif_msg_timer(priv)) 13338c2ecf20Sopenharmony_ci netdev_err(ndev, "tx timeout\n"); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci ndev->stats.tx_errors++; 13368c2ecf20Sopenharmony_ci /* can't restart safely under softirq */ 13378c2ecf20Sopenharmony_ci schedule_work(&priv->restart_work); 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci/* 13418c2ecf20Sopenharmony_ci * Open/initialize the board. This is called (in the current kernel) 13428c2ecf20Sopenharmony_ci * sometime after booting when the 'ifconfig' program is run. 13438c2ecf20Sopenharmony_ci * 13448c2ecf20Sopenharmony_ci * This routine should set everything up anew at each open, even 13458c2ecf20Sopenharmony_ci * registers that "should" only need to be set once at boot, so that 13468c2ecf20Sopenharmony_ci * there is non-reboot way to recover if something goes wrong. 13478c2ecf20Sopenharmony_ci */ 13488c2ecf20Sopenharmony_cistatic int enc28j60_net_open(struct net_device *dev) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) { 13538c2ecf20Sopenharmony_ci if (netif_msg_ifup(priv)) 13548c2ecf20Sopenharmony_ci netdev_err(dev, "invalid MAC address %pM\n", dev->dev_addr); 13558c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci /* Reset the hardware here (and take it out of low power mode) */ 13588c2ecf20Sopenharmony_ci enc28j60_lowpower(priv, false); 13598c2ecf20Sopenharmony_ci enc28j60_hw_disable(priv); 13608c2ecf20Sopenharmony_ci if (!enc28j60_hw_init(priv)) { 13618c2ecf20Sopenharmony_ci if (netif_msg_ifup(priv)) 13628c2ecf20Sopenharmony_ci netdev_err(dev, "hw_reset() failed\n"); 13638c2ecf20Sopenharmony_ci return -EINVAL; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci /* Update the MAC address (in case user has changed it) */ 13668c2ecf20Sopenharmony_ci enc28j60_set_hw_macaddr(dev); 13678c2ecf20Sopenharmony_ci /* Enable interrupts */ 13688c2ecf20Sopenharmony_ci enc28j60_hw_enable(priv); 13698c2ecf20Sopenharmony_ci /* check link status */ 13708c2ecf20Sopenharmony_ci enc28j60_check_link_status(dev); 13718c2ecf20Sopenharmony_ci /* We are now ready to accept transmit requests from 13728c2ecf20Sopenharmony_ci * the queueing layer of the networking. 13738c2ecf20Sopenharmony_ci */ 13748c2ecf20Sopenharmony_ci netif_start_queue(dev); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci return 0; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci/* The inverse routine to net_open(). */ 13808c2ecf20Sopenharmony_cistatic int enc28j60_net_close(struct net_device *dev) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci enc28j60_hw_disable(priv); 13858c2ecf20Sopenharmony_ci enc28j60_lowpower(priv, true); 13868c2ecf20Sopenharmony_ci netif_stop_queue(dev); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci return 0; 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci/* 13928c2ecf20Sopenharmony_ci * Set or clear the multicast filter for this adapter 13938c2ecf20Sopenharmony_ci * num_addrs == -1 Promiscuous mode, receive all packets 13948c2ecf20Sopenharmony_ci * num_addrs == 0 Normal mode, filter out multicast packets 13958c2ecf20Sopenharmony_ci * num_addrs > 0 Multicast mode, receive normal and MC packets 13968c2ecf20Sopenharmony_ci */ 13978c2ecf20Sopenharmony_cistatic void enc28j60_set_multicast_list(struct net_device *dev) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 14008c2ecf20Sopenharmony_ci int oldfilter = priv->rxfilter; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 14038c2ecf20Sopenharmony_ci if (netif_msg_link(priv)) 14048c2ecf20Sopenharmony_ci netdev_info(dev, "promiscuous mode\n"); 14058c2ecf20Sopenharmony_ci priv->rxfilter = RXFILTER_PROMISC; 14068c2ecf20Sopenharmony_ci } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { 14078c2ecf20Sopenharmony_ci if (netif_msg_link(priv)) 14088c2ecf20Sopenharmony_ci netdev_info(dev, "%smulticast mode\n", 14098c2ecf20Sopenharmony_ci (dev->flags & IFF_ALLMULTI) ? "all-" : ""); 14108c2ecf20Sopenharmony_ci priv->rxfilter = RXFILTER_MULTI; 14118c2ecf20Sopenharmony_ci } else { 14128c2ecf20Sopenharmony_ci if (netif_msg_link(priv)) 14138c2ecf20Sopenharmony_ci netdev_info(dev, "normal mode\n"); 14148c2ecf20Sopenharmony_ci priv->rxfilter = RXFILTER_NORMAL; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci if (oldfilter != priv->rxfilter) 14188c2ecf20Sopenharmony_ci schedule_work(&priv->setrx_work); 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_cistatic void enc28j60_setrx_work_handler(struct work_struct *work) 14228c2ecf20Sopenharmony_ci{ 14238c2ecf20Sopenharmony_ci struct enc28j60_net *priv = 14248c2ecf20Sopenharmony_ci container_of(work, struct enc28j60_net, setrx_work); 14258c2ecf20Sopenharmony_ci struct device *dev = &priv->spi->dev; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (priv->rxfilter == RXFILTER_PROMISC) { 14288c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 14298c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "promiscuous mode\n"); 14308c2ecf20Sopenharmony_ci locked_regb_write(priv, ERXFCON, 0x00); 14318c2ecf20Sopenharmony_ci } else if (priv->rxfilter == RXFILTER_MULTI) { 14328c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 14338c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "multicast mode\n"); 14348c2ecf20Sopenharmony_ci locked_regb_write(priv, ERXFCON, 14358c2ecf20Sopenharmony_ci ERXFCON_UCEN | ERXFCON_CRCEN | 14368c2ecf20Sopenharmony_ci ERXFCON_BCEN | ERXFCON_MCEN); 14378c2ecf20Sopenharmony_ci } else { 14388c2ecf20Sopenharmony_ci if (netif_msg_drv(priv)) 14398c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "normal mode\n"); 14408c2ecf20Sopenharmony_ci locked_regb_write(priv, ERXFCON, 14418c2ecf20Sopenharmony_ci ERXFCON_UCEN | ERXFCON_CRCEN | 14428c2ecf20Sopenharmony_ci ERXFCON_BCEN); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic void enc28j60_restart_work_handler(struct work_struct *work) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci struct enc28j60_net *priv = 14498c2ecf20Sopenharmony_ci container_of(work, struct enc28j60_net, restart_work); 14508c2ecf20Sopenharmony_ci struct net_device *ndev = priv->netdev; 14518c2ecf20Sopenharmony_ci int ret; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci rtnl_lock(); 14548c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 14558c2ecf20Sopenharmony_ci enc28j60_net_close(ndev); 14568c2ecf20Sopenharmony_ci ret = enc28j60_net_open(ndev); 14578c2ecf20Sopenharmony_ci if (unlikely(ret)) { 14588c2ecf20Sopenharmony_ci netdev_info(ndev, "could not restart %d\n", ret); 14598c2ecf20Sopenharmony_ci dev_close(ndev); 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci rtnl_unlock(); 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci/* ......................... ETHTOOL SUPPORT ........................... */ 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic void 14688c2ecf20Sopenharmony_cienc28j60_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 14718c2ecf20Sopenharmony_ci strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 14728c2ecf20Sopenharmony_ci strlcpy(info->bus_info, 14738c2ecf20Sopenharmony_ci dev_name(dev->dev.parent), sizeof(info->bus_info)); 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic int 14778c2ecf20Sopenharmony_cienc28j60_get_link_ksettings(struct net_device *dev, 14788c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 14798c2ecf20Sopenharmony_ci{ 14808c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 14838c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half); 14848c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Full); 14858c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, TP); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_10; 14888c2ecf20Sopenharmony_ci cmd->base.duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; 14898c2ecf20Sopenharmony_ci cmd->base.port = PORT_TP; 14908c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return 0; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic int 14968c2ecf20Sopenharmony_cienc28j60_set_link_ksettings(struct net_device *dev, 14978c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci return enc28j60_setlink(dev, cmd->base.autoneg, 15008c2ecf20Sopenharmony_ci cmd->base.speed, cmd->base.duplex); 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_cistatic u32 enc28j60_get_msglevel(struct net_device *dev) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 15068c2ecf20Sopenharmony_ci return priv->msg_enable; 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_cistatic void enc28j60_set_msglevel(struct net_device *dev, u32 val) 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 15128c2ecf20Sopenharmony_ci priv->msg_enable = val; 15138c2ecf20Sopenharmony_ci} 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_cistatic const struct ethtool_ops enc28j60_ethtool_ops = { 15168c2ecf20Sopenharmony_ci .get_drvinfo = enc28j60_get_drvinfo, 15178c2ecf20Sopenharmony_ci .get_msglevel = enc28j60_get_msglevel, 15188c2ecf20Sopenharmony_ci .set_msglevel = enc28j60_set_msglevel, 15198c2ecf20Sopenharmony_ci .get_link_ksettings = enc28j60_get_link_ksettings, 15208c2ecf20Sopenharmony_ci .set_link_ksettings = enc28j60_set_link_ksettings, 15218c2ecf20Sopenharmony_ci}; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_cistatic int enc28j60_chipset_init(struct net_device *dev) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci struct enc28j60_net *priv = netdev_priv(dev); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci return enc28j60_hw_init(priv); 15288c2ecf20Sopenharmony_ci} 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cistatic const struct net_device_ops enc28j60_netdev_ops = { 15318c2ecf20Sopenharmony_ci .ndo_open = enc28j60_net_open, 15328c2ecf20Sopenharmony_ci .ndo_stop = enc28j60_net_close, 15338c2ecf20Sopenharmony_ci .ndo_start_xmit = enc28j60_send_packet, 15348c2ecf20Sopenharmony_ci .ndo_set_rx_mode = enc28j60_set_multicast_list, 15358c2ecf20Sopenharmony_ci .ndo_set_mac_address = enc28j60_set_mac_address, 15368c2ecf20Sopenharmony_ci .ndo_tx_timeout = enc28j60_tx_timeout, 15378c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 15388c2ecf20Sopenharmony_ci}; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_cistatic int enc28j60_probe(struct spi_device *spi) 15418c2ecf20Sopenharmony_ci{ 15428c2ecf20Sopenharmony_ci unsigned char macaddr[ETH_ALEN]; 15438c2ecf20Sopenharmony_ci struct net_device *dev; 15448c2ecf20Sopenharmony_ci struct enc28j60_net *priv; 15458c2ecf20Sopenharmony_ci int ret = 0; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (netif_msg_drv(&debug)) 15488c2ecf20Sopenharmony_ci dev_info(&spi->dev, "Ethernet driver %s loaded\n", DRV_VERSION); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct enc28j60_net)); 15518c2ecf20Sopenharmony_ci if (!dev) { 15528c2ecf20Sopenharmony_ci ret = -ENOMEM; 15538c2ecf20Sopenharmony_ci goto error_alloc; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci priv->netdev = dev; /* priv to netdev reference */ 15588c2ecf20Sopenharmony_ci priv->spi = spi; /* priv to spi reference */ 15598c2ecf20Sopenharmony_ci priv->msg_enable = netif_msg_init(debug.msg_enable, ENC28J60_MSG_DEFAULT); 15608c2ecf20Sopenharmony_ci mutex_init(&priv->lock); 15618c2ecf20Sopenharmony_ci INIT_WORK(&priv->tx_work, enc28j60_tx_work_handler); 15628c2ecf20Sopenharmony_ci INIT_WORK(&priv->setrx_work, enc28j60_setrx_work_handler); 15638c2ecf20Sopenharmony_ci INIT_WORK(&priv->irq_work, enc28j60_irq_work_handler); 15648c2ecf20Sopenharmony_ci INIT_WORK(&priv->restart_work, enc28j60_restart_work_handler); 15658c2ecf20Sopenharmony_ci spi_set_drvdata(spi, priv); /* spi to priv reference */ 15668c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &spi->dev); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci if (!enc28j60_chipset_init(dev)) { 15698c2ecf20Sopenharmony_ci if (netif_msg_probe(priv)) 15708c2ecf20Sopenharmony_ci dev_info(&spi->dev, "chip not found\n"); 15718c2ecf20Sopenharmony_ci ret = -EIO; 15728c2ecf20Sopenharmony_ci goto error_irq; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (device_get_mac_address(&spi->dev, macaddr, sizeof(macaddr))) 15768c2ecf20Sopenharmony_ci ether_addr_copy(dev->dev_addr, macaddr); 15778c2ecf20Sopenharmony_ci else 15788c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 15798c2ecf20Sopenharmony_ci enc28j60_set_hw_macaddr(dev); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci /* Board setup must set the relevant edge trigger type; 15828c2ecf20Sopenharmony_ci * level triggers won't currently work. 15838c2ecf20Sopenharmony_ci */ 15848c2ecf20Sopenharmony_ci ret = request_irq(spi->irq, enc28j60_irq, 0, DRV_NAME, priv); 15858c2ecf20Sopenharmony_ci if (ret < 0) { 15868c2ecf20Sopenharmony_ci if (netif_msg_probe(priv)) 15878c2ecf20Sopenharmony_ci dev_err(&spi->dev, "request irq %d failed (ret = %d)\n", 15888c2ecf20Sopenharmony_ci spi->irq, ret); 15898c2ecf20Sopenharmony_ci goto error_irq; 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci dev->if_port = IF_PORT_10BASET; 15938c2ecf20Sopenharmony_ci dev->irq = spi->irq; 15948c2ecf20Sopenharmony_ci dev->netdev_ops = &enc28j60_netdev_ops; 15958c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 15968c2ecf20Sopenharmony_ci dev->ethtool_ops = &enc28j60_ethtool_ops; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci enc28j60_lowpower(priv, true); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci ret = register_netdev(dev); 16018c2ecf20Sopenharmony_ci if (ret) { 16028c2ecf20Sopenharmony_ci if (netif_msg_probe(priv)) 16038c2ecf20Sopenharmony_ci dev_err(&spi->dev, "register netdev failed (ret = %d)\n", 16048c2ecf20Sopenharmony_ci ret); 16058c2ecf20Sopenharmony_ci goto error_register; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci return 0; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cierror_register: 16118c2ecf20Sopenharmony_ci free_irq(spi->irq, priv); 16128c2ecf20Sopenharmony_cierror_irq: 16138c2ecf20Sopenharmony_ci free_netdev(dev); 16148c2ecf20Sopenharmony_cierror_alloc: 16158c2ecf20Sopenharmony_ci return ret; 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_cistatic int enc28j60_remove(struct spi_device *spi) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci struct enc28j60_net *priv = spi_get_drvdata(spi); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci unregister_netdev(priv->netdev); 16238c2ecf20Sopenharmony_ci free_irq(spi->irq, priv); 16248c2ecf20Sopenharmony_ci free_netdev(priv->netdev); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci return 0; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cistatic const struct of_device_id enc28j60_dt_ids[] = { 16308c2ecf20Sopenharmony_ci { .compatible = "microchip,enc28j60" }, 16318c2ecf20Sopenharmony_ci { /* sentinel */ } 16328c2ecf20Sopenharmony_ci}; 16338c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, enc28j60_dt_ids); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_cistatic struct spi_driver enc28j60_driver = { 16368c2ecf20Sopenharmony_ci .driver = { 16378c2ecf20Sopenharmony_ci .name = DRV_NAME, 16388c2ecf20Sopenharmony_ci .of_match_table = enc28j60_dt_ids, 16398c2ecf20Sopenharmony_ci }, 16408c2ecf20Sopenharmony_ci .probe = enc28j60_probe, 16418c2ecf20Sopenharmony_ci .remove = enc28j60_remove, 16428c2ecf20Sopenharmony_ci}; 16438c2ecf20Sopenharmony_cimodule_spi_driver(enc28j60_driver); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_NAME " ethernet driver"); 16468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>"); 16478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 16488c2ecf20Sopenharmony_cimodule_param_named(debug, debug.msg_enable, int, 0); 16498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug verbosity level in amount of bits set (0=none, ..., 31=all)"); 16508c2ecf20Sopenharmony_ciMODULE_ALIAS("spi:" DRV_NAME); 1651