smsc9420.c revision 720a43efd30f04a0a492c85fb997361c44fbae05
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 162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * along with this program; if not, write to the Free Software 172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning *************************************************************************** 202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning */ 212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 22a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/kernel.h> 242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/netdevice.h> 252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/phy.h> 262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/pci.h> 272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/if_vlan.h> 282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/dma-mapping.h> 292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <linux/crc32.h> 305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 319d9779e723a5d23b94abbe5bb7d1197921f6f3ddPaul Gortmaker#include <linux/module.h> 322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include <asm/unaligned.h> 332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#include "smsc9420.h" 342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define DRV_NAME "smsc9420" 362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define PFX DRV_NAME ": " 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 86a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(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 Glendinning#define smsc_dbg(TYPE, f, a...) \ 1012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningdo { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ 1022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_DEBUG PFX f "\n", ## a); \ 1032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} while (0) 1042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define smsc_info(TYPE, f, a...) \ 1062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningdo { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ 1072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_INFO PFX f "\n", ## a); \ 1082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} while (0) 1092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#define smsc_warn(TYPE, f, a...) \ 1112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningdo { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ 1122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_WARNING PFX f "\n", ## a); \ 1132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} while (0) 1142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset) 1162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 117b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu return ioread32(pd->ioaddr + offset); 1182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic inline void 1212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningsmsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value) 1222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 123b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu iowrite32(value, pd->ioaddr + offset); 1242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd) 1272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* to ensure PCI write completion, we must perform a PCI read */ 1292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_read(pd, ID_REV); 1302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx) 1332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; 1352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unsigned long flags; 1362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 addr; 1372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i, reg = -EIO; 1382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->phy_lock, flags); 1402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* confirm MII not busy */ 1422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { 1432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(DRV, "MII is busy???"); 1442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* set the address, index & direction (read from PHY) */ 1482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | 1492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_READ_; 1502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MII_ACCESS, addr); 1512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* wait for read to complete with 50us timeout */ 1532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < 5; i++) { 1542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(smsc9420_reg_read(pd, MII_ACCESS) & 1552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_BUSY_)) { 1562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning reg = (u16)smsc9420_reg_read(pd, MII_DATA); 1572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 1602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(DRV, "MII busy timeout!"); 1632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout: 1652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->phy_lock, flags); 1662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return reg; 1672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 1682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx, 1702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 val) 1712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; 1732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unsigned long flags; 1742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 addr; 1752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i, reg = -EIO; 1762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->phy_lock, flags); 1782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* confirm MII not busy */ 1802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { 1812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(DRV, "MII is busy???"); 1822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 1842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* put the data to write in the MAC */ 1862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MII_DATA, (u32)val); 1872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* set the address, index & direction (write to PHY) */ 1892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | 1902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_WRITE_; 1912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MII_ACCESS, addr); 1922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* wait for write to complete with 50us timeout */ 1942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < 5; i++) { 1952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(smsc9420_reg_read(pd, MII_ACCESS) & 1962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning MII_ACCESS_MII_BUSY_)) { 1972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning reg = 0; 1982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 1992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 2002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 2012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 2022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(DRV, "MII busy timeout!"); 2042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout: 2062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->phy_lock, flags); 2072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return reg; 2082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Returns hash bit number for given MAC address 2112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * Example: 2122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * 01 00 5E 00 00 01 -> returns bit number 31 */ 2132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic u32 smsc9420_hash(u8 addr[ETH_ALEN]) 2142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; 2162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_eeprom_reload(struct smsc9420_pdata *pd) 2192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int timeout = 100000; 2212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd); 2232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { 2252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(DRV, "smsc9420_eeprom_reload: Eeprom busy"); 2262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -EIO; 2272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 2282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, E2P_CMD, 2302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_)); 2312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning do { 2332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 2342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_)) 2352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 2362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } while (timeout--); 2372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(DRV, "smsc9420_eeprom_reload: Eeprom timed out"); 2392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -EIO; 2402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Standard ioctls for mii-tool */ 2432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 2442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 2462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!netif_running(dev) || !pd->phy_dev) 2482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -EINVAL; 2492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 25028b041139e344ecd0f144d6205b004ae354cfa1eRichard Cochran return phy_mii_ioctl(pd->phy_dev, ifr, cmd); 2512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_ethtool_get_settings(struct net_device *dev, 2542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct ethtool_cmd *cmd) 2552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 2572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2586c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!pd->phy_dev) 2596c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return -ENODEV; 2606c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 2612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning cmd->maxtxpkt = 1; 2622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning cmd->maxrxpkt = 1; 2632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return phy_ethtool_gset(pd->phy_dev, cmd); 2642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_ethtool_set_settings(struct net_device *dev, 2672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct ethtool_cmd *cmd) 2682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 2702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2716c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!pd->phy_dev) 2726c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return -ENODEV; 2736c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 2742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return phy_ethtool_sset(pd->phy_dev, cmd); 2752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_ethtool_get_drvinfo(struct net_device *netdev, 2782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct ethtool_drvinfo *drvinfo) 2792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 2812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 28268aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 28368aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(drvinfo->bus_info, pci_name(pd->pdev), 28468aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones sizeof(drvinfo->bus_info)); 28568aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); 2862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev) 2892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 2912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return pd->msg_enable; 2922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 2942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data) 2952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 2962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 2972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->msg_enable = data; 2982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 2992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 3002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_ethtool_nway_reset(struct net_device *netdev) 3012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 3022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(netdev); 3036c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 3046c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!pd->phy_dev) 3056c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return -ENODEV; 3066c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 3072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return phy_start_aneg(pd->phy_dev); 3082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 3092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 310a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinningstatic int smsc9420_ethtool_getregslen(struct net_device *dev) 311a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning{ 312a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning /* all smsc9420 registers plus all phy registers */ 313a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning return 0x100 + (32 * sizeof(u32)); 314a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning} 315a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 316a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinningstatic void 317a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinningsmsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, 318a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning void *buf) 319a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning{ 320a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 321a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning struct phy_device *phy_dev = pd->phy_dev; 322a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning unsigned int i, j = 0; 323a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning u32 *data = buf; 324a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 325a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning regs->version = smsc9420_reg_read(pd, ID_REV); 326a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning for (i = 0; i < 0x100; i += (sizeof(u32))) 327a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning data[j++] = smsc9420_reg_read(pd, i); 328a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 3296c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning // cannot read phy registers if the net device is down 3306c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning if (!phy_dev) 3316c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning return; 3326c53b1b15e222244358d3cbbefd2a13920faa352Steve Glendinning 333a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning for (i = 0; i <= 31; i++) 334a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i); 335a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning} 336a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning 337012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd) 338012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 339012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG); 340012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning temp &= ~GPIO_CFG_EEPR_EN_; 341012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_reg_write(pd, GPIO_CFG, temp); 342012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning msleep(1); 343012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 344012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 345012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op) 346012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 347012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int timeout = 100; 348012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u32 e2cmd; 349012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 350012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc_dbg(HW, "op 0x%08x", op); 351012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { 352012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc_warn(HW, "Busy at start"); 353012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return -EBUSY; 354012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 355012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 356012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning e2cmd = op | E2P_CMD_EPC_BUSY_; 357012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_reg_write(pd, E2P_CMD, e2cmd); 358012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 359012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning do { 360012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning msleep(1); 361012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning e2cmd = smsc9420_reg_read(pd, E2P_CMD); 3629df8f4e3ee760c14211a5f484e9ee4f0bc0c566bSteve Glendinning } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout)); 363012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 364012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (!timeout) { 365012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc_info(HW, "TIMED OUT"); 366012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return -EAGAIN; 367012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 368012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 369012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { 37025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi smsc_info(HW, "Error occurred during eeprom operation"); 371012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return -EINVAL; 372012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 373012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 374012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return 0; 375012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 376012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 377012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd, 378012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u8 address, u8 *data) 379012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 380012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u32 op = E2P_CMD_EPC_CMD_READ_ | address; 381012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret; 382012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 383012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc_dbg(HW, "address 0x%x", address); 384012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_send_cmd(pd, op); 385012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 386012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (!ret) 387012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning data[address] = smsc9420_reg_read(pd, E2P_DATA); 388012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 389012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 390012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 391012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 392012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd, 393012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u8 address, u8 data) 394012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 395012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; 396012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret; 397012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 398012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc_dbg(HW, "address 0x%x, data 0x%x", address, data); 399012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_send_cmd(pd, op); 400012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 401012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (!ret) { 402012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning op = E2P_CMD_EPC_CMD_WRITE_ | address; 403012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_reg_write(pd, E2P_DATA, (u32)data); 404012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_send_cmd(pd, op); 405012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 406012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 407012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 408012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 409012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 410012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_ethtool_get_eeprom_len(struct net_device *dev) 411012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 412012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return SMSC9420_EEPROM_SIZE; 413012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 414012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 415012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_ethtool_get_eeprom(struct net_device *dev, 416012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct ethtool_eeprom *eeprom, u8 *data) 417012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 418012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 419012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning u8 eeprom_data[SMSC9420_EEPROM_SIZE]; 420012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int len, i; 421012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 422012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_enable_access(pd); 423012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 424012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning len = min(eeprom->len, SMSC9420_EEPROM_SIZE); 425012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning for (i = 0; i < len; i++) { 426012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data); 427012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning if (ret < 0) { 428012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning eeprom->len = 0; 429012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 430012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 431012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning } 432012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 433012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning memcpy(data, &eeprom_data[eeprom->offset], len); 434196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning eeprom->magic = SMSC9420_EEPROM_MAGIC; 435012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning eeprom->len = len; 436012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return 0; 437012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 438012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 439012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinningstatic int smsc9420_ethtool_set_eeprom(struct net_device *dev, 440012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct ethtool_eeprom *eeprom, u8 *data) 441012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning{ 442012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 443012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning int ret; 444012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 445196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning if (eeprom->magic != SMSC9420_EEPROM_MAGIC) 446196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning return -EINVAL; 447196b7e1b9cca9e187bb61fa7d60f04f4ab2c0592Steve Glendinning 448012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_enable_access(pd); 449012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_); 450012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data); 451012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_); 452012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 453012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning /* Single byte write, according to man page */ 454012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning eeprom->len = 1; 455012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 456012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning return ret; 457012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning} 458012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning 4592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic const struct ethtool_ops smsc9420_ethtool_ops = { 4602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_settings = smsc9420_ethtool_get_settings, 4612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .set_settings = smsc9420_ethtool_set_settings, 4622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_drvinfo = smsc9420_ethtool_get_drvinfo, 4632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_msglevel = smsc9420_ethtool_get_msglevel, 4642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .set_msglevel = smsc9420_ethtool_set_msglevel, 4652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .nway_reset = smsc9420_ethtool_nway_reset, 4662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .get_link = ethtool_op_get_link, 467012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning .get_eeprom_len = smsc9420_ethtool_get_eeprom_len, 468012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning .get_eeprom = smsc9420_ethtool_get_eeprom, 469012b215ceb55aa38826f091cecfd373cc9bbb05bSteve Glendinning .set_eeprom = smsc9420_ethtool_set_eeprom, 470a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning .get_regs_len = smsc9420_ethtool_getregslen, 471a7276db6adfded660eec1e1629710b8b82d83455Steve Glendinning .get_regs = smsc9420_ethtool_getregs, 47250c0c110024fcd5718355ddc80f6853d7fe3e388Richard Cochran .get_ts_info = ethtool_op_get_ts_info, 4732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 4742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Sets the device MAC address to dev_addr */ 4762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_set_mac_address(struct net_device *dev) 4772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 4782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 4792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u8 *dev_addr = dev->dev_addr; 4802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; 4812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | 4822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (dev_addr[1] << 8) | dev_addr[0]; 4832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, ADDRH, mac_high16); 4852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, ADDRL, mac_low32); 4862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 4872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_check_mac_address(struct net_device *dev) 4892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 4902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 4912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 4922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Check if mac address has been specified when bringing interface up */ 4932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (is_valid_ether_addr(dev->dev_addr)) { 4942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_set_mac_address(dev); 4952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(PROBE, "MAC Address is specified by configuration"); 4962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 4972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Try reading mac address from device. if EEPROM is present 4982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * it will already have been set */ 4992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_high16 = smsc9420_reg_read(pd, ADDRH); 5002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_low32 = smsc9420_reg_read(pd, ADDRL); 5012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[0] = (u8)(mac_low32); 5022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[1] = (u8)(mac_low32 >> 8); 5032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[2] = (u8)(mac_low32 >> 16); 5042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[3] = (u8)(mac_low32 >> 24); 5052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[4] = (u8)(mac_high16); 5062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->dev_addr[5] = (u8)(mac_high16 >> 8); 5072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (is_valid_ether_addr(dev->dev_addr)) { 5092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* eeprom values are valid so use them */ 5102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(PROBE, "Mac Address is read from EEPROM"); 5112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 5122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* eeprom values are invalid, generate random MAC */ 513f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka eth_hw_addr_random(dev); 5142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_set_mac_address(dev); 515f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka smsc_dbg(PROBE, "MAC Address is set to random"); 5162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 5192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_stop_tx(struct smsc9420_pdata *pd) 5212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 5222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 dmac_control, mac_cr, dma_intr_ena; 52346578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin int timeout = 1000; 5242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable TX DMAC */ 5262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); 5272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control &= (~DMAC_CONTROL_ST_); 5282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); 5292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Wait max 10ms for transmit process to stop */ 53146578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin while (--timeout) { 5322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_) 5332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 5342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 5352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 53746578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin if (!timeout) 5382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFDOWN, "TX DMAC failed to stop"); 5392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* ACK Tx DMAC stop bit */ 5412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_); 5422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask TX DMAC interrupts */ 5442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 5452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena &= ~(DMAC_INTR_ENA_TX_); 5462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 5472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 5482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop MAC TX */ 5502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_); 5512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 5522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 5532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 5542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_free_tx_ring(struct smsc9420_pdata *pd) 5562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 5572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 5582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_ring); 5602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->tx_buffers) 5622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return; 5632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < TX_RING_SIZE; i++) { 5652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct sk_buff *skb = pd->tx_buffers[i].skb; 5662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (skb) { 5682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_buffers[i].mapping); 5692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping, 5702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->len, PCI_DMA_TODEVICE); 5712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(skb); 5722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].status = 0; 5752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].length = 0; 5762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer1 = 0; 5772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer2 = 0; 5782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 5792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 5802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning kfree(pd->tx_buffers); 5822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers = NULL; 5832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_head = 0; 5852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_tail = 0; 5862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 5872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_free_rx_ring(struct smsc9420_pdata *pd) 5892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 5902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 5912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->rx_ring); 5932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->rx_buffers) 5952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return; 5962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 5972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < RX_RING_SIZE; i++) { 5982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_buffers[i].skb) 5992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(pd->rx_buffers[i].skb); 6002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_buffers[i].mapping) 6022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping, 6032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 6042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].status = 0; 6062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].length = 0; 6072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].buffer1 = 0; 6082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].buffer2 = 0; 6092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 6112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning kfree(pd->rx_buffers); 6132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers = NULL; 6142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_head = 0; 6162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_tail = 0; 6172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 6182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_stop_rx(struct smsc9420_pdata *pd) 6202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 62146578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin int timeout = 1000; 6222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_cr, dmac_control, dma_intr_ena; 6232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask RX DMAC interrupts */ 6252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 6262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena &= (~DMAC_INTR_ENA_RX_); 6272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 6282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop RX MAC prior to stoping DMA */ 6312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_); 6322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 6332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop RX DMAC */ 6362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); 6372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control &= (~DMAC_CONTROL_SR_); 6382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); 6392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* wait up to 10ms for receive to stop */ 64246578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin while (--timeout) { 6432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_) 6442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 6452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(10); 6462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 64846578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin if (!timeout) 6492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFDOWN, "RX DMAC did not stop! timeout."); 6502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* ACK the Rx DMAC stop bit */ 6522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_); 6532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 6542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic irqreturn_t smsc9420_isr(int irq, void *dev_id) 6562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 6572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = dev_id; 6582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 int_cfg, int_sts, int_ctl; 6592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning irqreturn_t ret = IRQ_NONE; 6602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ulong flags; 6612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd); 663b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu BUG_ON(!pd->ioaddr); 6642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG); 6662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* check if it's our interrupt */ 6682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) != 6692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) 6702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return IRQ_NONE; 6712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_sts = smsc9420_reg_read(pd, INT_STAT); 6732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (likely(INT_STAT_DMAC_INT_ & int_sts)) { 6752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 status = smsc9420_reg_read(pd, DMAC_STATUS); 6762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 ints_to_clear = 0; 6772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & DMAC_STS_TX_) { 6792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_); 6802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_wake_queue(pd->dev); 6812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & DMAC_STS_RX_) { 6842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask RX DMAC interrupts */ 6852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 6862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena &= (~DMAC_INTR_ENA_RX_); 6872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 6882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 6892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_); 691288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_schedule(&pd->napi); 6922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (ints_to_clear) 6952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear); 6962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 6972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ret = IRQ_HANDLED; 6982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 6992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(INT_STAT_SW_INT_ & int_sts)) { 7012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask software interrupt */ 7022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 7032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_ctl = smsc9420_reg_read(pd, INT_CTL); 7042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_ctl &= (~INT_CTL_SW_INT_EN_); 7052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CTL, int_ctl); 7062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 7072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_); 7092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->software_irq_signal = true; 7102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smp_wmb(); 7112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ret = IRQ_HANDLED; 7132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 7142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* to ensure PCI write completion, we must perform a PCI read */ 7162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 7172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return ret; 7192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 7202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 721e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#ifdef CONFIG_NET_POLL_CONTROLLER 722e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinningstatic void smsc9420_poll_controller(struct net_device *dev) 723e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning{ 724b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu struct smsc9420_pdata *pd = netdev_priv(dev); 725b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu const int irq = pd->pdev->irq; 726b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu 727b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu disable_irq(irq); 728e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning smsc9420_isr(0, dev); 729b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu enable_irq(irq); 730e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning} 731e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#endif /* CONFIG_NET_POLL_CONTROLLER */ 732e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning 7332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd) 7342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 7352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_); 7362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_read(pd, BUS_MODE); 7372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning udelay(2); 7382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_) 7392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(DRV, "Software reset not cleared"); 7402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 7412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_stop(struct net_device *dev) 7432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 7442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 7452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 int_cfg; 7462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ulong flags; 7472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd); 7492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->phy_dev); 7502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable master interrupt */ 7522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 7532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 7542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 7552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 7562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_tx_disable(dev); 7582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning napi_disable(&pd->napi); 7592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_tx(pd); 7612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_tx_ring(pd); 7622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_rx(pd); 7642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 7652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 766b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu free_irq(pd->pdev->irq, pd); 7672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_dmac_soft_reset(pd); 7692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phy_stop(pd->phy_dev); 7712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phy_disconnect(pd->phy_dev); 7732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->phy_dev = NULL; 7742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_unregister(pd->mii_bus); 7752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_free(pd->mii_bus); 7762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 7782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 7792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status) 7812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 7822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) { 7832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_errors++; 7842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (desc_status & RDES0_DESCRIPTOR_ERROR_) 7852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_over_errors++; 7862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else if (desc_status & (RDES0_FRAME_TOO_LONG_ | 7872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_)) 7882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_frame_errors++; 7892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else if (desc_status & RDES0_CRC_ERROR_) 7902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_crc_errors++; 7912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 7922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(desc_status & RDES0_LENGTH_ERROR_)) 7942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_length_errors++; 7952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 7962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) && 7972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (desc_status & RDES0_FIRST_DESCRIPTOR_)))) 7982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_length_errors++; 7992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (desc_status & RDES0_MULTICAST_FRAME_) 8012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.multicast++; 8022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 8032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index, 8052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning const u32 status) 8062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 8072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pd->dev; 8082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct sk_buff *skb; 8092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_) 8102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning >> RDES0_FRAME_LENGTH_SHFT_; 8112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* remove crc from packet lendth */ 8132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning packet_length -= 4; 8142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_csum) 8162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning packet_length -= 2; 8172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_packets++; 8192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_bytes += packet_length; 8202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping, 8222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 8232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].mapping = 0; 8242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb = pd->rx_buffers[index].skb; 8262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].skb = NULL; 8272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_csum) { 8292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) + 8302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning NET_IP_ALIGN + packet_length + 4); 831cd7a3b75ba7af7d14a264fe3d414fcc74307f748Steve Glendinning put_unaligned_le16(hw_csum, &skb->csum); 8322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->ip_summed = CHECKSUM_COMPLETE; 8332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 8342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb_reserve(skb, NET_IP_ALIGN); 8362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb_put(skb, packet_length); 8372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->protocol = eth_type_trans(skb, dev); 8392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_receive_skb(skb); 8412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 8422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index) 8442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 8452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ); 8462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_addr_t mapping; 8472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->rx_buffers[index].skb); 8492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->rx_buffers[index].mapping); 8502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 851720a43efd30f04a0a492c85fb997361c44fbae05Joe Perches if (unlikely(!skb)) 8522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 8532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb), 8552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 8562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pci_dma_mapping_error(pd->pdev, mapping)) { 8572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(skb); 8582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(RX_ERR, "pci_map_single failed!"); 8592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 8602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 8612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].skb = skb; 8632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[index].mapping = mapping; 8642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN; 8652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[index].status = RDES0_OWN_; 8662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 8672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 8692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 8702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd) 8722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 8732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning while (pd->rx_ring_tail != pd->rx_ring_head) { 8742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail)) 8752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 8762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE; 8782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 8792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 8802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_rx_poll(struct napi_struct *napi, int budget) 8822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 8832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = 8842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning container_of(napi, struct smsc9420_pdata, napi); 8852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pd->dev; 8862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 drop_frame_cnt, dma_intr_ena, status; 8872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int work_done; 8882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (work_done = 0; work_done < budget; work_done++) { 8902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning rmb(); 8912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning status = pd->rx_ring[pd->rx_ring_head].status; 8922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* stop if DMAC owns this dma descriptor */ 8942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & RDES0_OWN_) 8952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 8962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 8972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_rx_count_stats(dev, status); 8982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_rx_handoff(pd, pd->rx_ring_head, status); 8992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE; 9002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_alloc_new_rx_buffers(pd); 9012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR); 9042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_dropped += 9052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF); 9062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Kick RXDMA */ 9082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); 9092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 9102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (work_done < budget) { 912288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_complete(&pd->napi); 9132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* re-enable RX DMA interrupts */ 9152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 9162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); 9172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 9182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 9192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return work_done; 9212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 9222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void 9242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningsmsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length) 9252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 9262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(status & TDES0_ERROR_SUMMARY_)) { 9272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_errors++; 9282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & (TDES0_EXCESSIVE_DEFERRAL_ | 9292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning TDES0_EXCESSIVE_COLLISIONS_)) 9302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_aborted_errors++; 9312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_)) 9332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_carrier_errors++; 9342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 9352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_packets++; 9362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_bytes += (length & 0x7FF); 9372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) { 9402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.collisions += 16; 9412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 9422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.collisions += 9432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (status & TDES0_COLLISION_COUNT_MASK_) >> 9442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning TDES0_COLLISION_COUNT_SHFT_; 9452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(status & TDES0_HEARTBEAT_FAIL_)) 9482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.tx_heartbeat_errors++; 9492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 9502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Check for completed dma transfers, update stats and free skbs */ 9522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_complete_tx(struct net_device *dev) 9532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 9542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 9552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning while (pd->tx_ring_tail != pd->tx_ring_head) { 9572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int index = pd->tx_ring_tail; 9582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 status, length; 9592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning rmb(); 9612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning status = pd->tx_ring[index].status; 9622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning length = pd->tx_ring[index].length; 9632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Check if DMA still owns this descriptor */ 9652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(TDES0_OWN_ & status)) 9662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 9672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_tx_update_stats(dev, status, length); 9692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_buffers[index].skb); 9712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_buffers[index].mapping); 9722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping, 9742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE); 9752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].mapping = 0; 9762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_kfree_skb_any(pd->tx_buffers[index].skb); 9782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].skb = NULL; 9792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].buffer1 = 0; 9812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 9822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE; 9842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 9852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 9862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 98761357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb, 98861357325f377889a1daffa14962d705dc814dd0eStephen Hemminger struct net_device *dev) 9892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 9902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 9912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_addr_t mapping; 9922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int index = pd->tx_ring_head; 9932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 tmp_desc1; 9942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bool about_to_take_last_desc = 9952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail); 9962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_complete_tx(dev); 9982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 9992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning rmb(); 10002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_ring[index].status & TDES0_OWN_); 10012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_buffers[index].skb); 10022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_buffers[index].mapping); 10032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mapping = pci_map_single(pd->pdev, skb->data, 10052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning skb->len, PCI_DMA_TODEVICE); 10062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pci_dma_mapping_error(pd->pdev, mapping)) { 10072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(TX_ERR, "pci_map_single failed, dropping packet"); 10082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return NETDEV_TX_BUSY; 10092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].skb = skb; 10122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[index].mapping = mapping; 10132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF)); 10152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(about_to_take_last_desc)) { 10162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning tmp_desc1 |= TDES1_IC_; 10172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_stop_queue(pd->dev); 10182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* check if we are at the last descriptor and need to set EOR */ 10212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(index == (TX_RING_SIZE - 1))) 10222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning tmp_desc1 |= TDES1_TER_; 10232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].buffer1 = mapping; 10252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].length = tmp_desc1; 10262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 10272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* increment head */ 10292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE; 10302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* assign ownership to DMAC */ 10322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[index].status = TDES0_OWN_; 10332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 10342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10356241207253b940048ffb6ba483a248813261ce6aRichard Cochran skb_tx_timestamp(skb); 10366241207253b940048ffb6ba483a248813261ce6aRichard Cochran 10372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* kick the DMA */ 10382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, TX_POLL_DEMAND, 1); 10392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 10402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return NETDEV_TX_OK; 10422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 10432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic struct net_device_stats *smsc9420_get_stats(struct net_device *dev) 10452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 10462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 10472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR); 10482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->stats.rx_dropped += 10492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF); 10502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return &dev->stats; 10512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 10522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_set_multicast_list(struct net_device *dev) 10542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 10552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 10562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); 10572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (dev->flags & IFF_PROMISC) { 10592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(HW, "Promiscuous Mode Enabled"); 10602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_PRMS_; 10612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_MCPAS_); 10622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_HPFILT_); 10632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else if (dev->flags & IFF_ALLMULTI) { 10642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(HW, "Receive all Multicast Enabled"); 10652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_PRMS_); 10662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_MCPAS_; 10672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_HPFILT_); 10684cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko } else if (!netdev_mc_empty(dev)) { 106922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 10702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 hash_lo = 0, hash_hi = 0; 10712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(HW, "Multicast filter enabled"); 107322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) { 107422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko u32 bit_num = smsc9420_hash(ha->addr); 10752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mask = 1 << (bit_num & 0x1F); 10762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (bit_num & 0x20) 10782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning hash_hi |= mask; 10792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else 10802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning hash_lo |= mask; 10812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHH, hash_hi); 10842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHL, hash_lo); 10852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_PRMS_); 10872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_MCPAS_); 10882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_HPFILT_; 10892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 10902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(HW, "Receive own packets only."); 10912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHH, 0); 10922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, HASHL, 0); 10932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_PRMS_); 10952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_MCPAS_); 10962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= (~MAC_CR_HPFILT_); 10972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 10982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 10992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 11002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 11012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 11022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) 11042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 11052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct phy_device *phy_dev = pd->phy_dev; 11062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 flow; 11072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (phy_dev->duplex == DUPLEX_FULL) { 11092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); 11102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u16 rmtadv = phy_read(phy_dev, MII_LPA); 1111bc02ff95fe4ebd3e5ee7455c0aa6f76ebe39ebcaSteve Glendinning u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); 11122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (cap & FLOW_CTRL_RX) 11142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning flow = 0xFFFF0002; 11152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else 11162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning flow = 0; 11172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_info(LINK, "rx pause %s, tx pause %s", 11192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), 11202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); 11212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 11222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_info(LINK, "half duplex"); 11232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning flow = 0; 11242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, FLOW, flow); 11272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 11282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning/* Update link mode if anything has changed. Called periodically when the 11302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning * PHY is in polling mode, even if nothing has changed. */ 11312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void smsc9420_phy_adjust_link(struct net_device *dev) 11322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 11332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 11342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct phy_device *phy_dev = pd->phy_dev; 11352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int carrier; 11362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (phy_dev->duplex != pd->last_duplex) { 11382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); 11392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (phy_dev->duplex) { 11402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(LINK, "full duplex mode"); 11412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr |= MAC_CR_FDPX_; 11422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } else { 11432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(LINK, "half duplex mode"); 11442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr &= ~MAC_CR_FDPX_; 11452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 11472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_phy_update_flowcontrol(pd); 11492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_duplex = phy_dev->duplex; 11502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning carrier = netif_carrier_ok(dev); 11532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (carrier != pd->last_carrier) { 11542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (carrier) 11552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(LINK, "carrier OK"); 11562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning else 11572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(LINK, "no carrier"); 11582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_carrier = carrier; 11592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 11612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_probe(struct net_device *dev) 11632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 11642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 11652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct phy_device *phydev = NULL; 11662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->phy_dev); 11682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Device only supports internal PHY at address 1 */ 11702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->mii_bus->phy_map[1]) { 11712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pr_err("%s: no PHY found at address 1\n", dev->name); 11722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENODEV; 11732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phydev = pd->mii_bus->phy_map[1]; 11762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr, 11772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phydev->phy_id); 11782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1179db1d7bf70f42124f73675fca62fe32f3ab1111b4Kay Sievers phydev = phy_connect(dev, dev_name(&phydev->dev), 1180f9a8f83b04e0c362a2fc660dbad980d24af209fcFlorian Fainelli smsc9420_phy_adjust_link, PHY_INTERFACE_MODE_MII); 11812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (IS_ERR(phydev)) { 11832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pr_err("%s: Could not attach to PHY\n", dev->name); 11842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return PTR_ERR(phydev); 11852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 11862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", 1188db1d7bf70f42124f73675fca62fe32f3ab1111b4Kay Sievers dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq); 11892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* mask with MAC supported features */ 11912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | 11922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning SUPPORTED_Asym_Pause); 11932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phydev->advertising = phydev->supported; 11942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->phy_dev = phydev; 11962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_duplex = -1; 11972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->last_carrier = -1; 11982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 11992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 12002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 12012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_mii_init(struct net_device *dev) 12032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 12042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 12052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int err = -ENXIO, i; 12062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus = mdiobus_alloc(); 12082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->mii_bus) { 12092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning err = -ENOMEM; 12102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto err_out_1; 12112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->name = DRV_MDIONAME; 12132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x", 12142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (pd->pdev->bus->number << 8) | pd->pdev->devfn); 12152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->priv = pd; 12162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->read = smsc9420_mii_read; 12172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->write = smsc9420_mii_write; 12182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->irq = pd->phy_irq; 12192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < PHY_MAX_ADDR; ++i) 12202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->irq[i] = PHY_POLL; 12212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Mask all PHYs except ID 1 (internal) */ 12232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->mii_bus->phy_mask = ~(1 << 1); 12242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (mdiobus_register(pd->mii_bus)) { 12262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(PROBE, "Error registering mii bus"); 12272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto err_out_free_bus_2; 12282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_mii_probe(dev) < 0) { 12312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(PROBE, "Error probing mii bus"); 12322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto err_out_unregister_bus_3; 12332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 12362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningerr_out_unregister_bus_3: 12382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_unregister(pd->mii_bus); 12392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningerr_out_free_bus_2: 12402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mdiobus_free(pd->mii_bus); 12412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningerr_out_1: 12422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return err; 12432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 12442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd) 12462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 12472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 12482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_ring); 12502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 125114f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches pd->tx_buffers = kmalloc_array(TX_RING_SIZE, 125214f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches sizeof(struct smsc9420_ring_info), 125314f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches GFP_KERNEL); 125414f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches if (!pd->tx_buffers) 12552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 12562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Initialize the TX Ring */ 12582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < TX_RING_SIZE; i++) { 12592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[i].skb = NULL; 12602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_buffers[i].mapping = 0; 12612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].status = 0; 12622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].length = 0; 12632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer1 = 0; 12642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[i].buffer2 = 0; 12652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_; 12672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning wmb(); 12682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_head = 0; 12702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_ring_tail = 0; 12712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr); 12732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 12742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 12762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 12772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd) 12792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 12802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int i; 12812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->rx_ring); 12832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) * 12852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning RX_RING_SIZE), GFP_KERNEL); 12862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_buffers == NULL) { 12872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "Failed to allocated rx_buffers"); 12882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out; 12892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 12912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* initialize the rx ring */ 12922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < RX_RING_SIZE; i++) { 12932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].status = 0; 12942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].length = PKT_BUF_SZ; 12952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[i].buffer2 = 0; 12962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[i].skb = NULL; 12972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_buffers[i].mapping = 0; 12982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 12992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_); 13002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* now allocate the entire ring of skbs */ 13022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning for (i = 0; i < RX_RING_SIZE; i++) { 13032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (smsc9420_alloc_rx_buffer(pd, i)) { 13042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "failed to allocate rx skb %d", i); 13052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_rx_skbs; 13062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_head = 0; 13102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring_tail = 0; 13112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q); 13132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(IFUP, "VLAN1 = 0x%08x", smsc9420_reg_read(pd, VLAN1)); 13142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->rx_csum) { 13162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Enable RX COE */ 13172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN; 13182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, COE_CR, coe); 13192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(IFUP, "COE_CR = 0x%08x", coe); 13202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr); 13232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 13262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_rx_skbs: 13282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 13292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout: 13302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENOMEM; 13312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 13322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_open(struct net_device *dev) 13342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 1335b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu struct smsc9420_pdata *pd = netdev_priv(dev); 13362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl; 1337b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu const int irq = pd->pdev->irq; 13382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unsigned long flags; 13392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int result = 0, timeout; 13402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!is_valid_ether_addr(dev->dev_addr)) { 13422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "dev_addr is not a valid MAC address"); 13432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -EADDRNOTAVAIL; 13442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_0; 13452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_carrier_off(dev); 13482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13493ad2f3fbb961429d2aa627465ae4829758bc7e07Daniel Mack /* disable, mask and acknowledge all interrupts */ 13502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 13512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 13522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 13532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CTL, 0); 13542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 13552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, 0); 13562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF); 13572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1359b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu result = request_irq(irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED, 1360b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu DRV_NAME, pd); 1361b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu if (result) { 1362b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu smsc_warn(IFUP, "Unable to use IRQ = %d", irq); 13632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENODEV; 13642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_0; 13652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 13662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_dmac_soft_reset(pd); 13682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* make sure MAC_CR is sane */ 13702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, 0); 13712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_set_mac_address(dev); 13732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Configure GPIO pins to drive LEDs */ 13752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, GPIO_CFG, 13762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_)); 13772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bus_mode = BUS_MODE_DMA_BURST_LENGTH_16; 13792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#ifdef __BIG_ENDIAN 13812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning bus_mode |= BUS_MODE_DBO_; 13822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#endif 13832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, BUS_MODE, bus_mode); 13852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* set bus master bridge arbitration priority for Rx and TX DMA */ 13892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1); 13902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, 13922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_)); 13932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 13952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 13962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* test the IRQ connection to the ISR */ 1397b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu smsc_dbg(IFUP, "Testing ISR using IRQ %d", irq); 13981609559547ae0ddc2e4829c7f78ac2c4869875b9Steve Glendinning pd->software_irq_signal = false; 13992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 14012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* configure interrupt deassertion timer and enable interrupts */ 14022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; 14032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg &= ~(INT_CFG_INT_DEAS_MASK); 14042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK); 14052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 14062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* unmask software interrupt */ 14082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_; 14092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CTL, int_ctl); 14102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 14112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 14122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning timeout = 1000; 14142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning while (timeout--) { 14152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (pd->software_irq_signal) 14162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 14172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning msleep(1); 14182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable interrupts */ 14212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 14222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 14232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 14242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 14252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->software_irq_signal) { 14272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "ISR failed signaling test"); 14282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENODEV; 14292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_irq_1; 14302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1432b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu smsc_dbg(IFUP, "ISR passed test using IRQ %d", irq); 14332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = smsc9420_alloc_tx_ring(pd); 14352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 14362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "Failed to Initialize tx dma ring"); 14372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENOMEM; 14382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_irq_1; 14392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = smsc9420_alloc_rx_ring(pd); 14422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 14432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "Failed to Initialize rx dma ring"); 14442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENOMEM; 14452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_tx_ring_2; 14462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = smsc9420_mii_init(dev); 14492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 14502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "Failed to initialize Phy"); 14512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = -ENODEV; 14522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_rx_ring_3; 14532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 14542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* Bring the PHY up */ 14562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning phy_start(pd->phy_dev); 14572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning napi_enable(&pd->napi); 14592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* start tx and rx */ 14612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_; 14622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, MAC_CR, mac_cr); 14632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); 14652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_; 14662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); 14672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 14682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); 14702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dma_intr_ena |= 14712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); 14722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); 14732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_pci_flush_write(pd); 14742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_wake_queue(dev); 14762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); 14782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* enable interrupts */ 14802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 14812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; 14822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 14832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 14842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 14862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_rx_ring_3: 14882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 14892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_tx_ring_2: 14902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_tx_ring(pd); 14912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_irq_1: 1492b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu free_irq(irq, pd); 14932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_0: 14942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return result; 14952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 14962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#ifdef CONFIG_PM 14982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 14992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state) 15002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 15012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pci_get_drvdata(pdev); 15022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 15032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 int_cfg; 15042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning ulong flags; 15052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* disable interrupts */ 15072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_irqsave(&pd->int_lock, flags); 15082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); 15092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_reg_write(pd, INT_CFG, int_cfg); 15102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_unlock_irqrestore(&pd->int_lock, flags); 15112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (netif_running(dev)) { 15132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_tx_disable(dev); 15142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_tx(pd); 15152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_tx_ring(pd); 15162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning napi_disable(&pd->napi); 15182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_stop_rx(pd); 15192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_free_rx_ring(pd); 15202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1521b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu free_irq(pd->pdev->irq, pd); 15222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_device_detach(dev); 15242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 15252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_save_state(pdev); 15272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); 15282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_disable_device(pdev); 15292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_power_state(pdev, pci_choose_state(pdev, state)); 15302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 15322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 15332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int smsc9420_resume(struct pci_dev *pdev) 15352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 15362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev = pci_get_drvdata(pdev); 15372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd = netdev_priv(dev); 15382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int err; 15392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_power_state(pdev, PCI_D0); 15412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_restore_state(pdev); 15422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning err = pci_enable_device(pdev); 15442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (err) 15452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return err; 15462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_master(pdev); 15482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning err = pci_enable_wake(pdev, 0, 0); 15502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (err) 15512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(IFUP, "pci_enable_wake failed: %d", err); 15522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (netif_running(dev)) { 1554b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu /* FIXME: gross. It looks like ancient PM relic.*/ 15552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning err = smsc9420_open(dev); 15562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_device_attach(dev); 15572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 15582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return err; 15592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 15602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#endif /* CONFIG_PM */ 15622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic const struct net_device_ops smsc9420_netdev_ops = { 15642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_open = smsc9420_open, 15652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_stop = smsc9420_stop, 15662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_start_xmit = smsc9420_hard_start_xmit, 15672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_get_stats = smsc9420_get_stats, 1568afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = smsc9420_set_multicast_list, 15692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_do_ioctl = smsc9420_do_ioctl, 15702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .ndo_validate_addr = eth_validate_addr, 1571fe96aaa14f553f0eb7af0e3502563a5400c65257Stephen Hemminger .ndo_set_mac_address = eth_mac_addr, 1572e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#ifdef CONFIG_NET_POLL_CONTROLLER 1573e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning .ndo_poll_controller = smsc9420_poll_controller, 1574e312674ffb5281a46a3ad06604edea6426c4eb24Steve Glendinning#endif /* CONFIG_NET_POLL_CONTROLLER */ 15752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 15762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1577f3f9e50927b6c4791bf81dacae8bf5e7832b535dBill Pembertonstatic int 15782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningsmsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) 15792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 15802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev; 15812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd; 15822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning void __iomem *virt_addr; 15832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning int result = 0; 15842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning u32 id_rev; 15852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_INFO DRV_DESCRIPTION " version " DRV_VERSION "\n"); 15872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* First do the PCI initialisation */ 15892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = pci_enable_device(pdev); 15902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (unlikely(result)) { 15912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_ERR "Cannot enable smsc9420\n"); 15922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_0; 15932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 15942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_master(pdev); 15962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 15972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev = alloc_etherdev(sizeof(*pd)); 159841de8d4cff21a2e81e3d9ff66f5f7c903f9c3ab1Joe Perches if (!dev) 15992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_disable_pci_device_1; 16002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning SET_NETDEV_DEV(dev, &pdev->dev); 16022cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) { 16042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_ERR "Cannot find PCI device base address\n"); 16052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_netdev_2; 16062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if ((pci_request_regions(pdev, DRV_NAME))) { 16092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); 16102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_netdev_2; 16112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1613284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { 16142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_ERR "No usable DMA configuration, aborting.\n"); 16152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_regions_3; 16162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR), 16192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_resource_len(pdev, SMSC_BAR)); 16202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!virt_addr) { 16212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning printk(KERN_ERR "Cannot map device registers, aborting.\n"); 16222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_regions_3; 16232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* registers are double mapped with 0 offset for LE and 0x200 for BE */ 16262cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning virt_addr += LAN9420_CPSR_ENDIAN_OFFSET; 16272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd = netdev_priv(dev); 16292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* pci descriptors are created in the PCI consistent area */ 16312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_ring = pci_alloc_consistent(pdev, 16322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE + 16332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE, 16342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning &pd->rx_dma_addr); 16352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16362cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!pd->rx_ring) 16372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_io_4; 16382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* descriptors are aligned due to the nature of pci_alloc_consistent */ 16406469933605a3ecdfa66b98160cde98ecd256cb3fJoe Perches pd->tx_ring = (pd->rx_ring + RX_RING_SIZE); 16412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->tx_dma_addr = pd->rx_dma_addr + 16422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE; 16432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->pdev = pdev; 16452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->dev = dev; 1646b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu pd->ioaddr = virt_addr; 16472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->msg_enable = smsc_debug; 16482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd->rx_csum = true; 16492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_dbg(PROBE, "lan_base=0x%08lx", (ulong)virt_addr); 16512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning id_rev = smsc9420_reg_read(pd, ID_REV); 16532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning switch (id_rev & 0xFFFF0000) { 16542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning case 0x94200000: 16552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_info(PROBE, "LAN9420 identified, ID_REV=0x%08X", id_rev); 16562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning break; 16572cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning default: 16582cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(PROBE, "LAN9420 NOT identified"); 16592cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(PROBE, "ID_REV=0x%08X", id_rev); 16602cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_dmadesc_5; 16612cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16622cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16632cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_dmac_soft_reset(pd); 16642cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_eeprom_reload(pd); 16652cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc9420_check_mac_address(dev); 16662cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16672cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->netdev_ops = &smsc9420_netdev_ops; 16682cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev->ethtool_ops = &smsc9420_ethtool_ops; 16692cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16702cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT); 16712cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16722cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning result = register_netdev(dev); 16732cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (result) { 16742cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_warn(PROBE, "error %i registering device", result); 16752cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning goto out_free_dmadesc_5; 16762cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning } 16772cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16782cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_drvdata(pdev, dev); 16792cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16802cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_init(&pd->int_lock); 16812cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning spin_lock_init(&pd->phy_lock); 16822cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16832cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); 16842cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16852cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return 0; 16862cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 16872cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_dmadesc_5: 16882cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * 16892cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); 16902cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_io_4: 16912cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET); 16922cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_regions_3: 16932cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_release_regions(pdev); 16942cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_free_netdev_2: 16952cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning free_netdev(dev); 16962cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_disable_pci_device_1: 16972cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_disable_device(pdev); 16982cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningout_0: 16992cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return -ENODEV; 17002cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 17012cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1702f3f9e50927b6c4791bf81dacae8bf5e7832b535dBill Pembertonstatic void smsc9420_remove(struct pci_dev *pdev) 17032cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 17042cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct net_device *dev; 17052cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning struct smsc9420_pdata *pd; 17062cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17072cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning dev = pci_get_drvdata(pdev); 17082cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning if (!dev) 17092cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return; 17102cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17112cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_set_drvdata(pdev, NULL); 17122cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17132cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pd = netdev_priv(dev); 17142cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning unregister_netdev(dev); 17152cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17162cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning /* tx_buffers and rx_buffers are freed in stop */ 17172cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->tx_buffers); 17182cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(pd->rx_buffers); 17192cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17202cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->tx_ring); 17212cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning BUG_ON(!pd->rx_ring); 17222cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17232cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * 17242cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); 17252cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 1726b5a80837b7e125729a49b2a8b80558d09bea7e19Francois Romieu iounmap(pd->ioaddr - LAN9420_CPSR_ENDIAN_OFFSET); 17272cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_release_regions(pdev); 17282cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning free_netdev(dev); 17292cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_disable_device(pdev); 17302cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 17312cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17322cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic struct pci_driver smsc9420_driver = { 17332cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .name = DRV_NAME, 17342cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .id_table = smsc9420_id_table, 17352cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .probe = smsc9420_probe, 1736f3f9e50927b6c4791bf81dacae8bf5e7832b535dBill Pemberton .remove = smsc9420_remove, 17372cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#ifdef CONFIG_PM 17382cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .suspend = smsc9420_suspend, 17392cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning .resume = smsc9420_resume, 17402cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning#endif /* CONFIG_PM */ 17412cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning}; 17422cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17432cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic int __init smsc9420_init_module(void) 17442cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 17452cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT); 17462cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17472cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning return pci_register_driver(&smsc9420_driver); 17482cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 17492cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17502cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningstatic void __exit smsc9420_exit_module(void) 17512cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning{ 17522cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning pci_unregister_driver(&smsc9420_driver); 17532cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning} 17542cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinning 17552cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningmodule_init(smsc9420_init_module); 17562cb377283f3469d66f0ea7358015abfe8366e5d0Steve Glendinningmodule_exit(smsc9420_exit_module); 1757