12cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /*************************************************************************** 22cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 32cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * Copyright (C) 2007,2008 SMSC 42cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 52cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * This program is free software; you can redistribute it and/or 62cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * modify it under the terms of the GNU General Public License 72cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * as published by the Free Software Foundation; either version 2 82cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * of the License, or (at your option) any later version. 92cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * This program is distributed in the hope that it will be useful, 112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * but WITHOUT ANY WARRANTY; without even the implied warranty of 122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * GNU General Public License for more details. 142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * You should have received a copy of the GNU General Public License 160ab75ae81da249988bf3c7a38e0a48d4b9be1e0cJeff Kirsher * along with this program; if not, see <http://www.gnu.org/licenses/>. 172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning *************************************************************************** 192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning */ 202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 21acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches 23a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/kernel.h> 252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/netdevice.h> 262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/phy.h> 272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/pci.h> 282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/if_vlan.h> 292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/dma-mapping.h> 302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/crc32.h> 315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 329d9779e723a5d23b94abbe5bb7d1197921f6f3ddPaul Gortmaker#include <linux/module.h> 332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <asm/unaligned.h> 342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include "smsc9420.h" 352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define DRV_NAME "smsc9420" 372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define DRV_MDIONAME "smsc9420-mdio" 382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define DRV_DESCRIPTION "SMSC LAN9420 driver" 392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define DRV_VERSION "1.01" 402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 412cb377283f3469d66f0ea7358015abfe8366e5d0Steve GlendinningMODULE_LICENSE("GPL"); 422cb377283f3469d66f0ea7358015abfe8366e5d0Steve GlendinningMODULE_VERSION(DRV_VERSION); 432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstruct smsc9420_dma_desc { 452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 status; 462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 length; 472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 buffer1; 482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 buffer2; 492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstruct smsc9420_ring_info { 522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct sk_buff *skb; 532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_addr_t mapping; 542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstruct smsc9420_pdata { 57b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu void __iomem *ioaddr; 582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct pci_dev *pdev; 592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev; 602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_dma_desc *rx_ring; 622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_dma_desc *tx_ring; 632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_ring_info *tx_buffers; 642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_ring_info *rx_buffers; 652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_addr_t rx_dma_addr; 662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_addr_t tx_dma_addr; 672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int tx_ring_head, tx_ring_tail; 682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int rx_ring_head, rx_ring_tail; 692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spinlock_t int_lock; 712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spinlock_t phy_lock; 722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct napi_struct napi; 742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bool software_irq_signal; 762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bool rx_csum; 772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 msg_enable; 782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct phy_device *phy_dev; 802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct mii_bus *mii_bus; 812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int phy_irq[PHY_MAX_ADDR]; 822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int last_duplex; 832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int last_carrier; 842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 869baa3c34ac4e27f7e062f266f50cc5dbea26a6c1Benoit Tainestatic const struct pci_device_id smsc9420_id_table[] = { 872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, }, 882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning { 0, } 892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 912cb377283f3469d66f0ea7358015abfe8366e5d0Steve GlendinningMODULE_DEVICE_TABLE(pci, smsc9420_id_table); 922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define SMSC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) 942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic uint smsc_debug; 962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic uint debug = -1; 972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningmodule_param(debug, uint, 0); 982cb377283f3469d66f0ea7358015abfe8366e5d0Steve GlendinningMODULE_PARM_DESC(debug, "debug level"); 992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset) 1012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 102b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu return ioread32(pd->ioaddr + offset); 1032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic inline void 1062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningsmsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value) 1072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 108b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu iowrite32(value, pd->ioaddr + offset); 1092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd) 1122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* to ensure PCI write completion, we must perform a PCI read */ 1142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_read(pd, ID_REV); 1152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx) 1182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; 1202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unsigned long flags; 1212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 addr; 1222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i, reg = -EIO; 1232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->phy_lock, flags); 1252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* confirm MII not busy */ 1272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { 128acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, drv, pd->dev, "MII is busy???\n"); 1292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* set the address, index & direction (read from PHY) */ 1332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | 1342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_READ_; 1352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MII_ACCESS, addr); 1362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* wait for read to complete with 50us timeout */ 1382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < 5; i++) { 1392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(smsc9420_reg_read(pd, MII_ACCESS) & 1402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_BUSY_)) { 1412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning reg = (u16)smsc9420_reg_read(pd, MII_DATA); 1422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 1452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 147acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, drv, pd->dev, "MII busy timeout!\n"); 1482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout: 1502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->phy_lock, flags); 1512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return reg; 1522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx, 1552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 val) 1562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; 1582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unsigned long flags; 1592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 addr; 1602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i, reg = -EIO; 1612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->phy_lock, flags); 1632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* confirm MII not busy */ 1652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { 166acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, drv, pd->dev, "MII is busy???\n"); 1672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* put the data to write in the MAC */ 1712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MII_DATA, (u32)val); 1722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* set the address, index & direction (write to PHY) */ 1742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | 1752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_WRITE_; 1762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MII_ACCESS, addr); 1772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* wait for write to complete with 50us timeout */ 1792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < 5; i++) { 1802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(smsc9420_reg_read(pd, MII_ACCESS) & 1812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_BUSY_)) { 1822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning reg = 0; 1832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 1862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 188acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, drv, pd->dev, "MII busy timeout!\n"); 1892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout: 1912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->phy_lock, flags); 1922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return reg; 1932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Returns hash bit number for given MAC address 1962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * Example: 1972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 01 00 5E 00 00 01 -> returns bit number 31 */ 1982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic u32 smsc9420_hash(u8 addr[ETH_ALEN]) 1992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; 2012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_eeprom_reload(struct smsc9420_pdata *pd) 2042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int timeout = 100000; 2062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd); 2082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { 210acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, drv, pd->dev, "%s: Eeprom busy\n", __func__); 2112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -EIO; 2122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 2132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, E2P_CMD, 2152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_)); 2162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning do { 2182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 2192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_)) 2202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 2212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } while (timeout--); 2222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 223acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, drv, pd->dev, "%s: Eeprom timed out\n", __func__); 2242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -EIO; 2252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Standard ioctls for mii-tool */ 2282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 2292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 2312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!netif_running(dev) || !pd->phy_dev) 2332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -EINVAL; 2342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 23528b041139e344ecd0f144d6205b004ae354cfa1eRichard Cochran return phy_mii_ioctl(pd->phy_dev, ifr, cmd); 2362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_ethtool_get_settings(struct net_device *dev, 2392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct ethtool_cmd *cmd) 2402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 2422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2436c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!pd->phy_dev) 2446c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return -ENODEV; 2456c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 2462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning cmd->maxtxpkt = 1; 2472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning cmd->maxrxpkt = 1; 2482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return phy_ethtool_gset(pd->phy_dev, cmd); 2492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_ethtool_set_settings(struct net_device *dev, 2522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct ethtool_cmd *cmd) 2532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 2552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2566c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!pd->phy_dev) 2576c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return -ENODEV; 2586c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 2592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return phy_ethtool_sset(pd->phy_dev, cmd); 2602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_ethtool_get_drvinfo(struct net_device *netdev, 2632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct ethtool_drvinfo *drvinfo) 2642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 2662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 26768aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 26868aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(drvinfo->bus_info, pci_name(pd->pdev), 26968aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones sizeof(drvinfo->bus_info)); 27068aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); 2712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev) 2742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 2762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return pd->msg_enable; 2772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data) 2802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 2822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->msg_enable = data; 2832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_ethtool_nway_reset(struct net_device *netdev) 2862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 2886c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 2896c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!pd->phy_dev) 2906c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return -ENODEV; 2916c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 2922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return phy_start_aneg(pd->phy_dev); 2932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 295a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinningstatic int smsc9420_ethtool_getregslen(struct net_device *dev) 296a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning{ 297a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning /* all smsc9420 registers plus all phy registers */ 298a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning return 0x100 + (32 * sizeof(u32)); 299a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning} 300a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 301a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinningstatic void 302a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinningsmsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, 303a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning void *buf) 304a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning{ 305a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 306a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning struct phy_device *phy_dev = pd->phy_dev; 307a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning unsigned int i, j = 0; 308a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning u32 *data = buf; 309a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 310a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning regs->version = smsc9420_reg_read(pd, ID_REV); 311a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning for (i = 0; i < 0x100; i += (sizeof(u32))) 312a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning data[j++] = smsc9420_reg_read(pd, i); 313a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 3146c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning // cannot read phy registers if the net device is down 3156c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!phy_dev) 3166c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return; 3176c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 318a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning for (i = 0; i <= 31; i++) 319a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i); 320a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning} 321a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 322012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd) 323012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 324012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG); 325012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning temp &= ~GPIO_CFG_EEPR_EN_; 326012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_reg_write(pd, GPIO_CFG, temp); 327012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning msleep(1); 328012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 329012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 330012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op) 331012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 332012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int timeout = 100; 333012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u32 e2cmd; 334012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 335acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, hw, pd->dev, "op 0x%08x\n", op); 336012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { 337acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, hw, pd->dev, "Busy at start\n"); 338012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return -EBUSY; 339012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 340012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 341012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning e2cmd = op | E2P_CMD_EPC_BUSY_; 342012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_reg_write(pd, E2P_CMD, e2cmd); 343012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 344012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning do { 345012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning msleep(1); 346012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning e2cmd = smsc9420_reg_read(pd, E2P_CMD); 3479df8f4e3ee760c14211a5f484e9ee4f0bc0c566bSteve Glendinning } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout)); 348012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 349012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (!timeout) { 350acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_info(pd, hw, pd->dev, "TIMED OUT\n"); 351012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return -EAGAIN; 352012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 353012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 354012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { 355acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_info(pd, hw, pd->dev, 356acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "Error occurred during eeprom operation\n"); 357012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return -EINVAL; 358012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 359012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 360012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return 0; 361012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 362012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 363012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd, 364012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u8 address, u8 *data) 365012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 366012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u32 op = E2P_CMD_EPC_CMD_READ_ | address; 367012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret; 368012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 369acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, hw, pd->dev, "address 0x%x\n", address); 370012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_send_cmd(pd, op); 371012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 372012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (!ret) 373012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning data[address] = smsc9420_reg_read(pd, E2P_DATA); 374012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 375012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 376012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 377012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 378012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd, 379012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u8 address, u8 data) 380012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 381012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; 382012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret; 383012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 384acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, hw, pd->dev, "address 0x%x, data 0x%x\n", address, data); 385012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_send_cmd(pd, op); 386012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 387012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (!ret) { 388012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning op = E2P_CMD_EPC_CMD_WRITE_ | address; 389012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_reg_write(pd, E2P_DATA, (u32)data); 390012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_send_cmd(pd, op); 391012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 392012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 393012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 394012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 395012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 396012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_ethtool_get_eeprom_len(struct net_device *dev) 397012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 398012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return SMSC9420_EEPROM_SIZE; 399012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 400012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 401012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_ethtool_get_eeprom(struct net_device *dev, 402012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct ethtool_eeprom *eeprom, u8 *data) 403012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 404012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 405012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u8 eeprom_data[SMSC9420_EEPROM_SIZE]; 406012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int len, i; 407012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 408012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_enable_access(pd); 409012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 410012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning len = min(eeprom->len, SMSC9420_EEPROM_SIZE); 411012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning for (i = 0; i < len; i++) { 412012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data); 413012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (ret < 0) { 414012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning eeprom->len = 0; 415012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 416012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 417012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 418012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 419012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning memcpy(data, &eeprom_data[eeprom->offset], len); 420196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning eeprom->magic = SMSC9420_EEPROM_MAGIC; 421012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning eeprom->len = len; 422012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return 0; 423012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 424012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 425012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_ethtool_set_eeprom(struct net_device *dev, 426012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct ethtool_eeprom *eeprom, u8 *data) 427012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 428012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 429012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret; 430012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 431196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning if (eeprom->magic != SMSC9420_EEPROM_MAGIC) 432196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning return -EINVAL; 433196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning 434012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_enable_access(pd); 435012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_); 436012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data); 437012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_); 438012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 439012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning /* Single byte write, according to man page */ 440012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning eeprom->len = 1; 441012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 442012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 443012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 444012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 4452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic const struct ethtool_ops smsc9420_ethtool_ops = { 4462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_settings = smsc9420_ethtool_get_settings, 4472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .set_settings = smsc9420_ethtool_set_settings, 4482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_drvinfo = smsc9420_ethtool_get_drvinfo, 4492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_msglevel = smsc9420_ethtool_get_msglevel, 4502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .set_msglevel = smsc9420_ethtool_set_msglevel, 4512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .nway_reset = smsc9420_ethtool_nway_reset, 4522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_link = ethtool_op_get_link, 453012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning .get_eeprom_len = smsc9420_ethtool_get_eeprom_len, 454012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning .get_eeprom = smsc9420_ethtool_get_eeprom, 455012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning .set_eeprom = smsc9420_ethtool_set_eeprom, 456a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning .get_regs_len = smsc9420_ethtool_getregslen, 457a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning .get_regs = smsc9420_ethtool_getregs, 45850c0c110024fcd5718355ddc80f6853d7fe3e388Richard Cochran .get_ts_info = ethtool_op_get_ts_info, 4592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 4602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Sets the device MAC address to dev_addr */ 4622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_set_mac_address(struct net_device *dev) 4632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 4642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 4652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u8 *dev_addr = dev->dev_addr; 4662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; 4672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | 4682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (dev_addr[1] << 8) | dev_addr[0]; 4692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, ADDRH, mac_high16); 4712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, ADDRL, mac_low32); 4722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 4732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_check_mac_address(struct net_device *dev) 4752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 4762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 4772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Check if mac address has been specified when bringing interface up */ 4792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (is_valid_ether_addr(dev->dev_addr)) { 4802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_set_mac_address(dev); 481acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, probe, pd->dev, 482acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "MAC Address is specified by configuration\n"); 4832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 4842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Try reading mac address from device. if EEPROM is present 4852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * it will already have been set */ 4862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_high16 = smsc9420_reg_read(pd, ADDRH); 4872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_low32 = smsc9420_reg_read(pd, ADDRL); 4882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[0] = (u8)(mac_low32); 4892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[1] = (u8)(mac_low32 >> 8); 4902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[2] = (u8)(mac_low32 >> 16); 4912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[3] = (u8)(mac_low32 >> 24); 4922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[4] = (u8)(mac_high16); 4932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[5] = (u8)(mac_high16 >> 8); 4942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (is_valid_ether_addr(dev->dev_addr)) { 4962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* eeprom values are valid so use them */ 497acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, probe, pd->dev, 498acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "Mac Address is read from EEPROM\n"); 4992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 5002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* eeprom values are invalid, generate random MAC */ 501f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka eth_hw_addr_random(dev); 5022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_set_mac_address(dev); 503acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, probe, pd->dev, 504acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "MAC Address is set to random\n"); 5052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 5082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_stop_tx(struct smsc9420_pdata *pd) 5102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 5112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 dmac_control, mac_cr, dma_intr_ena; 51246578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin int timeout = 1000; 5132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable TX DMAC */ 5152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); 5162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control &= (~DMAC_CONTROL_ST_); 5172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); 5182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Wait max 10ms for transmit process to stop */ 52046578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin while (--timeout) { 5212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_) 5222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 5232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 5242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 52646578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin if (!timeout) 527acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifdown, pd->dev, "TX DMAC failed to stop\n"); 5282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* ACK Tx DMAC stop bit */ 5302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_); 5312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask TX DMAC interrupts */ 5332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 5342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena &= ~(DMAC_INTR_ENA_TX_); 5352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 5362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 5372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop MAC TX */ 5392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_); 5402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 5412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 5422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 5432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_free_tx_ring(struct smsc9420_pdata *pd) 5452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 5462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 5472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_ring); 5492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->tx_buffers) 5512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return; 5522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < TX_RING_SIZE; i++) { 5542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct sk_buff *skb = pd->tx_buffers[i].skb; 5552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (skb) { 5572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_buffers[i].mapping); 5582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping, 5592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->len, PCI_DMA_TODEVICE); 5602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(skb); 5612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].status = 0; 5642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].length = 0; 5652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer1 = 0; 5662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer2 = 0; 5672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 5692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning kfree(pd->tx_buffers); 5712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers = NULL; 5722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_head = 0; 5742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_tail = 0; 5752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 5762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_free_rx_ring(struct smsc9420_pdata *pd) 5782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 5792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 5802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->rx_ring); 5822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->rx_buffers) 5842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return; 5852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < RX_RING_SIZE; i++) { 5872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_buffers[i].skb) 5882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(pd->rx_buffers[i].skb); 5892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_buffers[i].mapping) 5912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping, 5922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 5932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].status = 0; 5952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].length = 0; 5962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].buffer1 = 0; 5972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].buffer2 = 0; 5982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 6002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning kfree(pd->rx_buffers); 6022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers = NULL; 6032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_head = 0; 6052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_tail = 0; 6062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 6072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_stop_rx(struct smsc9420_pdata *pd) 6092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 61046578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin int timeout = 1000; 6112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_cr, dmac_control, dma_intr_ena; 6122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask RX DMAC interrupts */ 6142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 6152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena &= (~DMAC_INTR_ENA_RX_); 6162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 6172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop RX MAC prior to stoping DMA */ 6202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_); 6212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 6222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop RX DMAC */ 6252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); 6262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control &= (~DMAC_CONTROL_SR_); 6272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); 6282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* wait up to 10ms for receive to stop */ 63146578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin while (--timeout) { 6322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_) 6332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 6342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 6352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 63746578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin if (!timeout) 638acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifdown, pd->dev, 639acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "RX DMAC did not stop! timeout\n"); 6402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* ACK the Rx DMAC stop bit */ 6422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_); 6432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 6442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic irqreturn_t smsc9420_isr(int irq, void *dev_id) 6462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 6472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = dev_id; 6482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 int_cfg, int_sts, int_ctl; 6492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning irqreturn_t ret = IRQ_NONE; 6502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ulong flags; 6512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd); 653b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu BUG_ON(!pd->ioaddr); 6542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG); 6562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* check if it's our interrupt */ 6582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) != 6592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) 6602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return IRQ_NONE; 6612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_sts = smsc9420_reg_read(pd, INT_STAT); 6632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (likely(INT_STAT_DMAC_INT_ & int_sts)) { 6652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 status = smsc9420_reg_read(pd, DMAC_STATUS); 6662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 ints_to_clear = 0; 6672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & DMAC_STS_TX_) { 6692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_); 6702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_wake_queue(pd->dev); 6712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & DMAC_STS_RX_) { 6742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask RX DMAC interrupts */ 6752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 6762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena &= (~DMAC_INTR_ENA_RX_); 6772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 6782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_); 681288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_schedule(&pd->napi); 6822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (ints_to_clear) 6852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear); 6862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ret = IRQ_HANDLED; 6882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(INT_STAT_SW_INT_ & int_sts)) { 6912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask software interrupt */ 6922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 6932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_ctl = smsc9420_reg_read(pd, INT_CTL); 6942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_ctl &= (~INT_CTL_SW_INT_EN_); 6952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CTL, int_ctl); 6962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 6972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_); 6992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->software_irq_signal = true; 7002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smp_wmb(); 7012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ret = IRQ_HANDLED; 7032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 7042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* to ensure PCI write completion, we must perform a PCI read */ 7062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 7072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return ret; 7092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 7102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 711e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#ifdef CONFIG_NET_POLL_CONTROLLER 712e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinningstatic void smsc9420_poll_controller(struct net_device *dev) 713e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning{ 714b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu struct smsc9420_pdata *pd = netdev_priv(dev); 715b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu const int irq = pd->pdev->irq; 716b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu 717b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu disable_irq(irq); 718e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning smsc9420_isr(0, dev); 719b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu enable_irq(irq); 720e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning} 721e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#endif /* CONFIG_NET_POLL_CONTROLLER */ 722e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning 7232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd) 7242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 7252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_); 7262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_read(pd, BUS_MODE); 7272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(2); 7282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_) 729acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, drv, pd->dev, "Software reset not cleared\n"); 7302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 7312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_stop(struct net_device *dev) 7332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 7342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 7352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 int_cfg; 7362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ulong flags; 7372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd); 7392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->phy_dev); 7402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable master interrupt */ 7422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 7432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 7442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 7452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 7462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_tx_disable(dev); 7482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning napi_disable(&pd->napi); 7492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_tx(pd); 7512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_tx_ring(pd); 7522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_rx(pd); 7542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 7552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 756b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu free_irq(pd->pdev->irq, pd); 7572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_dmac_soft_reset(pd); 7592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phy_stop(pd->phy_dev); 7612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phy_disconnect(pd->phy_dev); 7632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->phy_dev = NULL; 7642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_unregister(pd->mii_bus); 7652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_free(pd->mii_bus); 7662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 7682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 7692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status) 7712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 7722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) { 7732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_errors++; 7742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (desc_status & RDES0_DESCRIPTOR_ERROR_) 7752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_over_errors++; 7762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else if (desc_status & (RDES0_FRAME_TOO_LONG_ | 7772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_)) 7782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_frame_errors++; 7792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else if (desc_status & RDES0_CRC_ERROR_) 7802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_crc_errors++; 7812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 7822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(desc_status & RDES0_LENGTH_ERROR_)) 7842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_length_errors++; 7852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) && 7872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (desc_status & RDES0_FIRST_DESCRIPTOR_)))) 7882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_length_errors++; 7892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (desc_status & RDES0_MULTICAST_FRAME_) 7912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.multicast++; 7922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 7932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index, 7952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning const u32 status) 7962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 7972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pd->dev; 7982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct sk_buff *skb; 7992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_) 8002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning >> RDES0_FRAME_LENGTH_SHFT_; 8012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* remove crc from packet lendth */ 8032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning packet_length -= 4; 8042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_csum) 8062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning packet_length -= 2; 8072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_packets++; 8092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_bytes += packet_length; 8102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping, 8122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 8132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].mapping = 0; 8142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb = pd->rx_buffers[index].skb; 8162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].skb = NULL; 8172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_csum) { 8192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) + 8202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning NET_IP_ALIGN + packet_length + 4); 821cd7a3b75ba7af7d14a264fe3d414fcc74307f748Steve Glendinning put_unaligned_le16(hw_csum, &skb->csum); 8222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->ip_summed = CHECKSUM_COMPLETE; 8232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 8242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb_reserve(skb, NET_IP_ALIGN); 8262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb_put(skb, packet_length); 8272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->protocol = eth_type_trans(skb, dev); 8292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_receive_skb(skb); 8312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 8322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index) 8342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 8352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ); 8362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_addr_t mapping; 8372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->rx_buffers[index].skb); 8392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->rx_buffers[index].mapping); 8402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 841720a43efd30f04a0a492c85fb997361c44fbae05Joe Perches if (unlikely(!skb)) 8422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 8432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb), 8452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 8462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pci_dma_mapping_error(pd->pdev, mapping)) { 8472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(skb); 848acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, rx_err, pd->dev, "pci_map_single failed!\n"); 8492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 8502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 8512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].skb = skb; 8532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].mapping = mapping; 8542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN; 8552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[index].status = RDES0_OWN_; 8562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 8572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 8592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 8602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd) 8622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 8632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning while (pd->rx_ring_tail != pd->rx_ring_head) { 8642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail)) 8652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 8662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE; 8682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 8692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 8702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_rx_poll(struct napi_struct *napi, int budget) 8722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 8732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = 8742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning container_of(napi, struct smsc9420_pdata, napi); 8752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pd->dev; 8762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 drop_frame_cnt, dma_intr_ena, status; 8772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int work_done; 8782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (work_done = 0; work_done < budget; work_done++) { 8802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning rmb(); 8812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning status = pd->rx_ring[pd->rx_ring_head].status; 8822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop if DMAC owns this dma descriptor */ 8842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & RDES0_OWN_) 8852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 8862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_rx_count_stats(dev, status); 8882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_rx_handoff(pd, pd->rx_ring_head, status); 8892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE; 8902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_alloc_new_rx_buffers(pd); 8912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 8922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR); 8942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_dropped += 8952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF); 8962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Kick RXDMA */ 8982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); 8992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 9002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (work_done < budget) { 902288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_complete(&pd->napi); 9032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* re-enable RX DMA interrupts */ 9052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 9062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); 9072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 9082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 9092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return work_done; 9112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 9122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void 9142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningsmsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length) 9152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 9162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(status & TDES0_ERROR_SUMMARY_)) { 9172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_errors++; 9182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & (TDES0_EXCESSIVE_DEFERRAL_ | 9192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning TDES0_EXCESSIVE_COLLISIONS_)) 9202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_aborted_errors++; 9212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_)) 9232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_carrier_errors++; 9242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 9252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_packets++; 9262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_bytes += (length & 0x7FF); 9272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) { 9302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.collisions += 16; 9312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 9322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.collisions += 9332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (status & TDES0_COLLISION_COUNT_MASK_) >> 9342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning TDES0_COLLISION_COUNT_SHFT_; 9352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(status & TDES0_HEARTBEAT_FAIL_)) 9382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_heartbeat_errors++; 9392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 9402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Check for completed dma transfers, update stats and free skbs */ 9422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_complete_tx(struct net_device *dev) 9432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 9442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 9452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning while (pd->tx_ring_tail != pd->tx_ring_head) { 9472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int index = pd->tx_ring_tail; 9482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 status, length; 9492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning rmb(); 9512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning status = pd->tx_ring[index].status; 9522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning length = pd->tx_ring[index].length; 9532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Check if DMA still owns this descriptor */ 9552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(TDES0_OWN_ & status)) 9562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 9572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_tx_update_stats(dev, status, length); 9592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_buffers[index].skb); 9612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_buffers[index].mapping); 9622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping, 9642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE); 9652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].mapping = 0; 9662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(pd->tx_buffers[index].skb); 9682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].skb = NULL; 9692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].buffer1 = 0; 9712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 9722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE; 9742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 9762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 97761357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb, 97861357325f377889a1daffa14962d705dc814dd0eStephen Hemminger struct net_device *dev) 9792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 9802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 9812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_addr_t mapping; 9822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int index = pd->tx_ring_head; 9832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 tmp_desc1; 9842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bool about_to_take_last_desc = 9852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail); 9862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_complete_tx(dev); 9882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning rmb(); 9902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_ring[index].status & TDES0_OWN_); 9912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_buffers[index].skb); 9922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_buffers[index].mapping); 9932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mapping = pci_map_single(pd->pdev, skb->data, 9952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->len, PCI_DMA_TODEVICE); 9962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pci_dma_mapping_error(pd->pdev, mapping)) { 997acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, tx_err, pd->dev, 998acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "pci_map_single failed, dropping packet\n"); 9992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return NETDEV_TX_BUSY; 10002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].skb = skb; 10032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].mapping = mapping; 10042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF)); 10062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(about_to_take_last_desc)) { 10072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning tmp_desc1 |= TDES1_IC_; 10082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_stop_queue(pd->dev); 10092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* check if we are at the last descriptor and need to set EOR */ 10122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(index == (TX_RING_SIZE - 1))) 10132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning tmp_desc1 |= TDES1_TER_; 10142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].buffer1 = mapping; 10162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].length = tmp_desc1; 10172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 10182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* increment head */ 10202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE; 10212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* assign ownership to DMAC */ 10232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].status = TDES0_OWN_; 10242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 10252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10266241207253b940048ffb6ba483a248813261ce6aRichard Cochran skb_tx_timestamp(skb); 10276241207253b940048ffb6ba483a248813261ce6aRichard Cochran 10282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* kick the DMA */ 10292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, TX_POLL_DEMAND, 1); 10302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 10312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return NETDEV_TX_OK; 10332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 10342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic struct net_device_stats *smsc9420_get_stats(struct net_device *dev) 10362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 10372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 10382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR); 10392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_dropped += 10402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF); 10412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return &dev->stats; 10422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 10432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_set_multicast_list(struct net_device *dev) 10452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 10462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 10472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); 10482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (dev->flags & IFF_PROMISC) { 1050acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, hw, pd->dev, "Promiscuous Mode Enabled\n"); 10512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_PRMS_; 10522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_MCPAS_); 10532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_HPFILT_); 10542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else if (dev->flags & IFF_ALLMULTI) { 1055acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, hw, pd->dev, "Receive all Multicast Enabled\n"); 10562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_PRMS_); 10572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_MCPAS_; 10582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_HPFILT_); 10594cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko } else if (!netdev_mc_empty(dev)) { 106022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 10612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 hash_lo = 0, hash_hi = 0; 10622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1063acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, hw, pd->dev, "Multicast filter enabled\n"); 106422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) { 106522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko u32 bit_num = smsc9420_hash(ha->addr); 10662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mask = 1 << (bit_num & 0x1F); 10672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (bit_num & 0x20) 10692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning hash_hi |= mask; 10702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else 10712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning hash_lo |= mask; 10722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHH, hash_hi); 10752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHL, hash_lo); 10762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_PRMS_); 10782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_MCPAS_); 10792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_HPFILT_; 10802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 1081acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, hw, pd->dev, "Receive own packets only\n"); 10822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHH, 0); 10832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHL, 0); 10842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_PRMS_); 10862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_MCPAS_); 10872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_HPFILT_); 10882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 10912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 10922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 10932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) 10952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 10962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct phy_device *phy_dev = pd->phy_dev; 10972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 flow; 10982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (phy_dev->duplex == DUPLEX_FULL) { 11002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); 11012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 rmtadv = phy_read(phy_dev, MII_LPA); 1102bc02ff95fe4ebd3e5ee7455c0aa6f76ebe39ebcaSteve Glendinning u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); 11032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (cap & FLOW_CTRL_RX) 11052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning flow = 0xFFFF0002; 11062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else 11072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning flow = 0; 11082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1109acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_info(pd, link, pd->dev, "rx pause %s, tx pause %s\n", 1110acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches cap & FLOW_CTRL_RX ? "enabled" : "disabled", 1111acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches cap & FLOW_CTRL_TX ? "enabled" : "disabled"); 11122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 1113acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_info(pd, link, pd->dev, "half duplex\n"); 11142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning flow = 0; 11152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, FLOW, flow); 11182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 11192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Update link mode if anything has changed. Called periodically when the 11212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * PHY is in polling mode, even if nothing has changed. */ 11222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_phy_adjust_link(struct net_device *dev) 11232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 11242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 11252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct phy_device *phy_dev = pd->phy_dev; 11262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int carrier; 11272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (phy_dev->duplex != pd->last_duplex) { 11292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); 11302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (phy_dev->duplex) { 1131acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, link, pd->dev, "full duplex mode\n"); 11322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_FDPX_; 11332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 1134acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, link, pd->dev, "half duplex mode\n"); 11352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= ~MAC_CR_FDPX_; 11362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 11382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_phy_update_flowcontrol(pd); 11402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_duplex = phy_dev->duplex; 11412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning carrier = netif_carrier_ok(dev); 11442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (carrier != pd->last_carrier) { 11452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (carrier) 1146acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, link, pd->dev, "carrier OK\n"); 11472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else 1148acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, link, pd->dev, "no carrier\n"); 11492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_carrier = carrier; 11502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 11522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_probe(struct net_device *dev) 11542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 11552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 11562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct phy_device *phydev = NULL; 11572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->phy_dev); 11592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Device only supports internal PHY at address 1 */ 11612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->mii_bus->phy_map[1]) { 11624800599397e2610d4b17a55ef04a16ff3523263dBen Boeckel netdev_err(dev, "no PHY found at address 1\n"); 11632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENODEV; 11642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phydev = pd->mii_bus->phy_map[1]; 1167acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_info(pd, probe, pd->dev, "PHY addr %d, phy_id 0x%08X\n", 1168acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches phydev->addr, phydev->phy_id); 11692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1170db1d7bf70f42124f73675fca62fe32f3ab1111b4Kay Sievers phydev = phy_connect(dev, dev_name(&phydev->dev), 1171f9a8f83b04e0c362a2fc660dbad980d24af209fcFlorian Fainelli smsc9420_phy_adjust_link, PHY_INTERFACE_MODE_MII); 11722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (IS_ERR(phydev)) { 11744800599397e2610d4b17a55ef04a16ff3523263dBen Boeckel netdev_err(dev, "Could not attach to PHY\n"); 11752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return PTR_ERR(phydev); 11762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11784800599397e2610d4b17a55ef04a16ff3523263dBen Boeckel netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", 11794800599397e2610d4b17a55ef04a16ff3523263dBen Boeckel phydev->drv->name, dev_name(&phydev->dev), phydev->irq); 11802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask with MAC supported features */ 11822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | 11832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning SUPPORTED_Asym_Pause); 11842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phydev->advertising = phydev->supported; 11852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->phy_dev = phydev; 11872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_duplex = -1; 11882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_carrier = -1; 11892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 11912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 11922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_init(struct net_device *dev) 11942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 11952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 11962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int err = -ENXIO, i; 11972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus = mdiobus_alloc(); 11992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->mii_bus) { 12002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning err = -ENOMEM; 12012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto err_out_1; 12022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->name = DRV_MDIONAME; 12042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x", 12052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (pd->pdev->bus->number << 8) | pd->pdev->devfn); 12062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->priv = pd; 12072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->read = smsc9420_mii_read; 12082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->write = smsc9420_mii_write; 12092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->irq = pd->phy_irq; 12102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < PHY_MAX_ADDR; ++i) 12112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->irq[i] = PHY_POLL; 12122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Mask all PHYs except ID 1 (internal) */ 12142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->phy_mask = ~(1 << 1); 12152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (mdiobus_register(pd->mii_bus)) { 1217acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, probe, pd->dev, "Error registering mii bus\n"); 12182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto err_out_free_bus_2; 12192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_mii_probe(dev) < 0) { 1222acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, probe, pd->dev, "Error probing mii bus\n"); 12232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto err_out_unregister_bus_3; 12242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 12272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningerr_out_unregister_bus_3: 12292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_unregister(pd->mii_bus); 12302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningerr_out_free_bus_2: 12312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_free(pd->mii_bus); 12322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningerr_out_1: 12332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return err; 12342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 12352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd) 12372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 12382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 12392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_ring); 12412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 124214f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches pd->tx_buffers = kmalloc_array(TX_RING_SIZE, 124314f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches sizeof(struct smsc9420_ring_info), 124414f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches GFP_KERNEL); 124514f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches if (!pd->tx_buffers) 12462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 12472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Initialize the TX Ring */ 12492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < TX_RING_SIZE; i++) { 12502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[i].skb = NULL; 12512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[i].mapping = 0; 12522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].status = 0; 12532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].length = 0; 12542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer1 = 0; 12552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer2 = 0; 12562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_; 12582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 12592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_head = 0; 12612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_tail = 0; 12622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr); 12642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 12652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 12672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 12682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd) 12702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 12712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 12722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->rx_ring); 12742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1275acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches pd->rx_buffers = kmalloc_array(RX_RING_SIZE, 1276acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches sizeof(struct smsc9420_ring_info), 1277acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches GFP_KERNEL); 1278acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches if (pd->rx_buffers == NULL) 12792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 12802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* initialize the rx ring */ 12822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < RX_RING_SIZE; i++) { 12832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].status = 0; 12842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].length = PKT_BUF_SZ; 12852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].buffer2 = 0; 12862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[i].skb = NULL; 12872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[i].mapping = 0; 12882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_); 12902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* now allocate the entire ring of skbs */ 12922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < RX_RING_SIZE; i++) { 12932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_alloc_rx_buffer(pd, i)) { 1294acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, 1295acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "failed to allocate rx skb %d\n", i); 12962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_rx_skbs; 12972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_head = 0; 13012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_tail = 0; 13022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q); 1304acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, ifup, pd->dev, "VLAN1 = 0x%08x\n", 1305acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches smsc9420_reg_read(pd, VLAN1)); 13062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_csum) { 13082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Enable RX COE */ 13092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN; 13102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, COE_CR, coe); 1311acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, ifup, pd->dev, "COE_CR = 0x%08x\n", coe); 13122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr); 13152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 13182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_rx_skbs: 13202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 13212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout: 13222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 13232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 13242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_open(struct net_device *dev) 13262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1327b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu struct smsc9420_pdata *pd = netdev_priv(dev); 13282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl; 1329b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu const int irq = pd->pdev->irq; 13302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unsigned long flags; 13312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int result = 0, timeout; 13322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!is_valid_ether_addr(dev->dev_addr)) { 1334acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, 1335acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "dev_addr is not a valid MAC address\n"); 13362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -EADDRNOTAVAIL; 13372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_0; 13382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_carrier_off(dev); 13412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13423ad2f3fbb961429d2aa627465ae4829758bc7e07Daniel Mack /* disable, mask and acknowledge all interrupts */ 13432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 13442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 13452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 13462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CTL, 0); 13472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 13482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, 0); 13492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF); 13502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1352cf68ca1e4f6f4404d772d5f1c090e017db709356Michael Opdenacker result = request_irq(irq, smsc9420_isr, IRQF_SHARED, DRV_NAME, pd); 1353b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu if (result) { 1354acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, "Unable to use IRQ = %d\n", irq); 13552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENODEV; 13562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_0; 13572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_dmac_soft_reset(pd); 13602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* make sure MAC_CR is sane */ 13622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, 0); 13632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_set_mac_address(dev); 13652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Configure GPIO pins to drive LEDs */ 13672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, GPIO_CFG, 13682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_)); 13692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bus_mode = BUS_MODE_DMA_BURST_LENGTH_16; 13712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#ifdef __BIG_ENDIAN 13732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bus_mode |= BUS_MODE_DBO_; 13742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#endif 13752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, BUS_MODE, bus_mode); 13772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* set bus master bridge arbitration priority for Rx and TX DMA */ 13812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1); 13822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, 13842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_)); 13852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* test the IRQ connection to the ISR */ 1389acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, ifup, pd->dev, "Testing ISR using IRQ %d\n", irq); 13901609559547ae0ddc2e4829c7f78ac2c4869875b9Steve Glendinning pd->software_irq_signal = false; 13912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 13932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* configure interrupt deassertion timer and enable interrupts */ 13942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; 13952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg &= ~(INT_CFG_INT_DEAS_MASK); 13962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK); 13972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 13982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* unmask software interrupt */ 14002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_; 14012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CTL, int_ctl); 14022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 14032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 14042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning timeout = 1000; 14062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning while (timeout--) { 14072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->software_irq_signal) 14082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 14092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning msleep(1); 14102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable interrupts */ 14132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 14142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 14152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 14162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 14172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->software_irq_signal) { 1419acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, "ISR failed signaling test\n"); 14202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENODEV; 14212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_irq_1; 14222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1424acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, ifup, pd->dev, "ISR passed test using IRQ %d\n", irq); 14252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = smsc9420_alloc_tx_ring(pd); 14272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 1428acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, 1429acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "Failed to Initialize tx dma ring\n"); 14302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENOMEM; 14312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_irq_1; 14322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = smsc9420_alloc_rx_ring(pd); 14352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 1436acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, 1437acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "Failed to Initialize rx dma ring\n"); 14382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENOMEM; 14392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_tx_ring_2; 14402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = smsc9420_mii_init(dev); 14432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 1444acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, "Failed to initialize Phy\n"); 14452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENODEV; 14462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_rx_ring_3; 14472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Bring the PHY up */ 14502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phy_start(pd->phy_dev); 14512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning napi_enable(&pd->napi); 14532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* start tx and rx */ 14552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_; 14562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 14572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); 14592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_; 14602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); 14612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 14622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 14642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena |= 14652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); 14662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 14672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 14682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_wake_queue(dev); 14702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); 14722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* enable interrupts */ 14742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 14752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; 14762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 14772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 14782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 14802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_rx_ring_3: 14822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 14832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_tx_ring_2: 14842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_tx_ring(pd); 14852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_irq_1: 1486b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu free_irq(irq, pd); 14872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_0: 14882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return result; 14892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 14902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#ifdef CONFIG_PM 14922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state) 14942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 14952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pci_get_drvdata(pdev); 14962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 14972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 int_cfg; 14982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ulong flags; 14992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable interrupts */ 15012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 15022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 15032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 15042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 15052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (netif_running(dev)) { 15072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_tx_disable(dev); 15082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_tx(pd); 15092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_tx_ring(pd); 15102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning napi_disable(&pd->napi); 15122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_rx(pd); 15132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 15142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1515b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu free_irq(pd->pdev->irq, pd); 15162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_device_detach(dev); 15182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 15192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_save_state(pdev); 15212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); 15222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_disable_device(pdev); 15232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_power_state(pdev, pci_choose_state(pdev, state)); 15242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 15262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 15272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_resume(struct pci_dev *pdev) 15292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 15302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pci_get_drvdata(pdev); 15312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 15322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int err; 15332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_power_state(pdev, PCI_D0); 15352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_restore_state(pdev); 15362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning err = pci_enable_device(pdev); 15382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (err) 15392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return err; 15402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_master(pdev); 15422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1543c018b7af5e9e59c19df39a86e3da58e6293d922bJulia Lawall err = pci_enable_wake(pdev, PCI_D0, 0); 15442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (err) 1545acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, ifup, pd->dev, "pci_enable_wake failed: %d\n", 1546acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches err); 15472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (netif_running(dev)) { 1549b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu /* FIXME: gross. It looks like ancient PM relic.*/ 15502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning err = smsc9420_open(dev); 15512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_device_attach(dev); 15522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 15532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return err; 15542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 15552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#endif /* CONFIG_PM */ 15572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic const struct net_device_ops smsc9420_netdev_ops = { 15592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_open = smsc9420_open, 15602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_stop = smsc9420_stop, 15612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_start_xmit = smsc9420_hard_start_xmit, 15622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_get_stats = smsc9420_get_stats, 1563afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = smsc9420_set_multicast_list, 15642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_do_ioctl = smsc9420_do_ioctl, 15652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_validate_addr = eth_validate_addr, 1566fe96aaa14f553f0eb7af0e3502563a5400c65257Stephen Hemminger .ndo_set_mac_address = eth_mac_addr, 1567e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#ifdef CONFIG_NET_POLL_CONTROLLER 1568e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning .ndo_poll_controller = smsc9420_poll_controller, 1569e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#endif /* CONFIG_NET_POLL_CONTROLLER */ 15702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 15712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1572f3f9e50927b6c4791bf81dacae8bf5e7832b535dBill Pembertonstatic int 15732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningsmsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) 15742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 15752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev; 15762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd; 15772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning void __iomem *virt_addr; 15782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int result = 0; 15792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 id_rev; 15802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1581acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches pr_info("%s version %s\n", DRV_DESCRIPTION, DRV_VERSION); 15822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* First do the PCI initialisation */ 15842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = pci_enable_device(pdev); 15852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(result)) { 15864800599397e2610d4b17a55ef04a16ff3523263dBen Boeckel pr_err("Cannot enable smsc9420\n"); 15872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_0; 15882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 15892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_master(pdev); 15912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev = alloc_etherdev(sizeof(*pd)); 159341de8d4cff21a2e81e3d9ff66f5f7c903f9c3ab1Joe Perches if (!dev) 15942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_disable_pci_device_1; 15952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning SET_NETDEV_DEV(dev, &pdev->dev); 15972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) { 15994800599397e2610d4b17a55ef04a16ff3523263dBen Boeckel netdev_err(dev, "Cannot find PCI device base address\n"); 16002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_netdev_2; 16012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((pci_request_regions(pdev, DRV_NAME))) { 1604acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netdev_err(dev, "Cannot obtain PCI resources, aborting\n"); 16052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_netdev_2; 16062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1608284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { 1609acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netdev_err(dev, "No usable DMA configuration, aborting\n"); 16102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_regions_3; 16112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR), 16142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_resource_len(pdev, SMSC_BAR)); 16152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!virt_addr) { 1616acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netdev_err(dev, "Cannot map device registers, aborting\n"); 16172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_regions_3; 16182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* registers are double mapped with 0 offset for LE and 0x200 for BE */ 16212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning virt_addr += LAN9420_CPSR_ENDIAN_OFFSET; 16222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd = netdev_priv(dev); 16242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* pci descriptors are created in the PCI consistent area */ 16262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring = pci_alloc_consistent(pdev, 16272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE + 16282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE, 16292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning &pd->rx_dma_addr); 16302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->rx_ring) 16322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_io_4; 16332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* descriptors are aligned due to the nature of pci_alloc_consistent */ 16356469933605a3ecdfa66b98160cde98ecd256cb3fJoe Perches pd->tx_ring = (pd->rx_ring + RX_RING_SIZE); 16362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_dma_addr = pd->rx_dma_addr + 16372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE; 16382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->pdev = pdev; 16402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->dev = dev; 1641b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu pd->ioaddr = virt_addr; 16422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->msg_enable = smsc_debug; 16432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_csum = true; 16442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1645acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_dbg(pd, probe, pd->dev, "lan_base=0x%08lx\n", (ulong)virt_addr); 16462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning id_rev = smsc9420_reg_read(pd, ID_REV); 16482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning switch (id_rev & 0xFFFF0000) { 16492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning case 0x94200000: 1650acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_info(pd, probe, pd->dev, 1651acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches "LAN9420 identified, ID_REV=0x%08X\n", id_rev); 16522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 16532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning default: 1654acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, probe, pd->dev, "LAN9420 NOT identified\n"); 1655acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, probe, pd->dev, "ID_REV=0x%08X\n", id_rev); 16562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_dmadesc_5; 16572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_dmac_soft_reset(pd); 16602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_eeprom_reload(pd); 16612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_check_mac_address(dev); 16622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->netdev_ops = &smsc9420_netdev_ops; 16642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->ethtool_ops = &smsc9420_ethtool_ops; 16652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT); 16672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = register_netdev(dev); 16692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 1670acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches netif_warn(pd, probe, pd->dev, "error %i registering device\n", 1671acec6d75ac41bc22cd948f62689fac7b878401ffJoe Perches result); 16722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_dmadesc_5; 16732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_drvdata(pdev, dev); 16762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_init(&pd->int_lock); 16782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_init(&pd->phy_lock); 16792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); 16812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 16832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_dmadesc_5: 16852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * 16862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); 16872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_io_4: 16882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET); 16892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_regions_3: 16902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_release_regions(pdev); 16912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_netdev_2: 16922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning free_netdev(dev); 16932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_disable_pci_device_1: 16942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_disable_device(pdev); 16952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_0: 16962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENODEV; 16972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 16982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1699f3f9e50927b6c4791bf81dacae8bf5e7832b535dBill Pembertonstatic void smsc9420_remove(struct pci_dev *pdev) 17002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 17012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev; 17022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd; 17032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev = pci_get_drvdata(pdev); 17052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!dev) 17062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return; 17072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd = netdev_priv(dev); 17092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unregister_netdev(dev); 17102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* tx_buffers and rx_buffers are freed in stop */ 17122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_buffers); 17132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->rx_buffers); 17142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_ring); 17162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->rx_ring); 17172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * 17192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); 17202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1721b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu iounmap(pd->ioaddr - LAN9420_CPSR_ENDIAN_OFFSET); 17222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_release_regions(pdev); 17232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning free_netdev(dev); 17242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_disable_device(pdev); 17252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 17262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic struct pci_driver smsc9420_driver = { 17282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .name = DRV_NAME, 17292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .id_table = smsc9420_id_table, 17302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .probe = smsc9420_probe, 1731f3f9e50927b6c4791bf81dacae8bf5e7832b535dBill Pemberton .remove = smsc9420_remove, 17322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#ifdef CONFIG_PM 17332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .suspend = smsc9420_suspend, 17342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .resume = smsc9420_resume, 17352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#endif /* CONFIG_PM */ 17362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 17372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int __init smsc9420_init_module(void) 17392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 17402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT); 17412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return pci_register_driver(&smsc9420_driver); 17432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 17442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void __exit smsc9420_exit_module(void) 17462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 17472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unregister_driver(&smsc9420_driver); 17482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 17492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningmodule_init(smsc9420_init_module); 17512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningmodule_exit(smsc9420_exit_module); 1752