On Fri, 14 Jul 2006 14:11:34 +0000 "Bahadir Balban" <bahadir.balban@xxxxxxxxx> wrote: > Attached is a driver patch for SMSC911x family of ethernet chips, > generated against 2.6.18-rc1 sources. There's a similar driver in the > tree; this one has been tested by SMSC on all flavors of the chip and > claimed to be efficient. > Please submit drivers to netdev@xxxxxxxxxxxxxxx > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig > index 3918990..d158e05 100644 > --- a/drivers/net/Kconfig > +++ b/drivers/net/Kconfig > @@ -865,6 +865,13 @@ config NET_NETX > <file:Documentation/networking/net-modules.txt>. The module > will be called netx-eth. > > +config SMSC911X > + tristate "SMSC 911x family of embedded ethernet support" > + depends on NET_ETHERNET > + ---help--- > + Say Y here if you want support for SMSC LAN911x family > + of ethernet chips. > + > config DM9000 > tristate "DM9000 support" > depends on (ARM || MIPS) && NET_ETHERNET > diff --git a/drivers/net/Makefile b/drivers/net/Makefile > index c91e951..51f680b 100644 > --- a/drivers/net/Makefile > +++ b/drivers/net/Makefile > @@ -196,6 +196,7 @@ obj-$(CONFIG_S2IO) += s2io.o > obj-$(CONFIG_MYRI10GE) += myri10ge/ > obj-$(CONFIG_SMC91X) += smc91x.o > obj-$(CONFIG_SMC911X) += smc911x.o > +obj-$(CONFIG_SMSC911X) += smsc911x.o > obj-$(CONFIG_DM9000) += dm9000.o > obj-$(CONFIG_FEC_8XX) += fec_8xx/ > > diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c > new file mode 100644 > index 0000000..e2f9adb > --- /dev/null > +++ b/drivers/net/smsc911x.c > @@ -0,0 +1,2105 @@ > +/*************************************************************************** > + * > + * Copyright (C) 2004-2005 SMSC > + * Copyright (C) 2005 ARM > + * > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > + * > + *************************************************************************** > + * Rewritten, heavily based on smsc911x simple driver by SMSC. > + * Partly uses io macros from smc91x.c by Nicolas Pitre > + */ > + > +#include <linux/config.h> > +#include <linux/delay.h> > +#include <linux/errno.h> > +#include <linux/etherdevice.h> > +#include <linux/init.h> > +#include <linux/ioport.h> > +#include <linux/kernel.h> > +#include <linux/mii.h> > +#include <linux/module.h> > +#include <linux/netdevice.h> > +#include <linux/platform_device.h> > +#include <linux/sched.h> > +#include <linux/slab.h> > +#include <linux/timer.h> > +#include <linux/version.h> > +#include <asm/bug.h> > +#include <asm/bitops.h> > +#include <asm/dma.h> > +#include <asm/irq.h> > +#include <asm/io.h> > +#include "smsc911x.h" > + > +#define SMSC_CHIPNAME "smsc911x" > + > +/* Tasklet declarations */ > +static unsigned long rx_tasklet_parameter; > +static void smsc911x_rx_tasklet(unsigned long data); > + > +DECLARE_TASKLET(rx_tasklet, smsc911x_rx_tasklet, 0); * should be static. * if you want to receive in softirq context use NAPI rather than a tasklet. > +MODULE_LICENSE("GPL"); > +/* Entry point for starting/opening the interface */ > +static int smsc911x_open(struct net_device *dev) > +{ > + struct smsc911x_data *pdata; > + unsigned char *mac_byte; > + unsigned int mac_high16; > + unsigned int mac_low32; > + unsigned int timeout; > + unsigned int intcfg; > + int result; > + > + /* Set interrupt deassertion to 220uS */ > + intcfg = 22 << 24; > + timeout = 1000; > + result = -ENODEV; > + pdata = 0; > + > + BUG_ON(!dev); This kind of BUG_ON is useless, you will get whacked when you deref the pointer anyway. > + pdata = netdev_priv(dev); > + BUG_ON(!pdata); > + > + /* Initialise smsc911x */ > + > + /* > + * dwIntCfg|=INT_CFG_IRQ_POL_; use this to set IRQ_POL bit > + * dwIntCfg|=INT_CFG_IRQ_TYPE_; use this to set IRQ_TYPE bit > + */ > + if (!smsc911x_lan_initialise(pdata, intcfg)) > + goto done; > + > + SMSC_TRACE("Testing irq handler using IRQ %d", dev->irq); > + pdata->request_irq_disable = 0; > + pdata->software_irq_signal = 0; > + SMC_regwrite((SMC_regread(pdata, INT_EN) | INT_EN_SW_INT_EN_), > + pdata, INT_EN); > + do { > + udelay(10); > + timeout--; > + } while (timeout && (!pdata->software_irq_signal)); > + > + if (!pdata->software_irq_signal) { > + printk("<1>ISR failed signaling test."); > + result = -ENODEV; > + goto done; > + } > + SMSC_TRACE("IRQ handler passed test using IRQ %d", dev->irq); > + > + printk("%s: SMSC9%3x identified at %#08x, IRQ: %d\n", dev->name, > + (u32)((pdata->idrev >> 16) & 0xFFFF), pdata->base, dev->irq); > + > + smsc911x_mac_initialise(pdata); > + > + /* Read mac address from EEPROM */ > + mac_high16 = smsc911x_mac_read(pdata, ADDRH); > + mac_low32 = smsc911x_mac_read(pdata, ADDRL); > + > + if ((mac_high16 == 0x0000FFFF) && (mac_low32 == 0xFFFFFFFF)) { > + /* Use default MAC addresses if eeprom values are invalid */ > + mac_high16 = 0x00000070; > + mac_low32 = 0x110F8000; > + > + smsc911x_mac_write(pdata, ADDRH, mac_high16); > + smsc911x_mac_write(pdata, ADDRL, mac_low32); Please use random_ether_addr instead of the default value. > + SMSC_TRACE("MAC Address is set by default to 0x%04X%08X", > + mac_high16, mac_low32); > + } else { > + SMSC_TRACE("Mac Address is read from LAN911x as 0x%04X%08X", > + mac_high16, mac_low32); > + } > + mac_byte = (unsigned char *)&mac_low32; > + dev->dev_addr[0] = mac_byte[0]; > + dev->dev_addr[1] = mac_byte[1]; > + dev->dev_addr[2] = mac_byte[2]; > + dev->dev_addr[3] = mac_byte[3]; What about byte order? > + > + mac_byte = (unsigned char *)&mac_high16; > + dev->dev_addr[4] = mac_byte[0]; > + dev->dev_addr[5] = mac_byte[1]; > + > + printk("%s: SMSC9%3x MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", > + dev->name, (u32)((pdata->idrev >> 16) & 0xFFFF), > + dev->dev_addr[5], dev->dev_addr[4], dev->dev_addr[3], > + dev->dev_addr[2], dev->dev_addr[1], dev->dev_addr[0]); > + > + netif_carrier_off(dev); > + if (!smsc911x_phy_initialise(pdata)) { > + SMSC_WARNING("Failed to initialize PHY"); > + result = -ENODEV; > + goto done; > + } > + > + smsc911x_tx_initialise(pdata); > + smsc911x_rx_initialise(pdata); > + netif_start_queue(dev); > + > + result = 0; > + > +done: > + SMSC_TRACE("result: %d", result); > + return result; > +} > + > +/* Entry point for stopping the interface */ > +static int smsc911x_stop(struct net_device *dev) > +{ > + unsigned long flags; > + unsigned long base; > + unsigned long idrev; > + struct smsc911x_data *pdata; > + struct net_device *pnetdev; > + > + BUG_ON(!dev); > + pdata = netdev_priv(dev); > + BUG_ON(!pdata); > + > + pdata->stop_link_poll = 1; > + del_timer_sync(&pdata->link_poll_timer); > + > + spin_lock_irqsave(&dev->_xmit_lock, flags); > + SMC_regwrite((SMC_regread(pdata, INT_CFG) & (~INT_CFG_IRQ_EN_)), > + pdata, INT_CFG); > + netif_stop_queue(pdata->dev); > + spin_unlock_irqrestore(&dev->_xmit_lock, flags); > + > + /* At this point all Rx and Tx activity is stopped */ > + pdata->stats.rx_dropped += SMC_regread(pdata, RX_DROP); > + smsc911x_tx_update_txcounters(pdata); > + > + /* Preserve important fields */ > + base = pdata->base; > + idrev = pdata->idrev; > + pnetdev = pdata->dev; > + > + /* Clear all structure */ > + memset((void *)pdata, 0, sizeof(struct smsc911x_data)); > + > + /* Reassign important fields */ > + pdata->base = base; > + pdata->idrev = idrev; > + pdata->dev = pnetdev; > + > + SMSC_TRACE("<--Simp911x_stop"); > + return 0; > +} > + > +/* Entry point for transmitting a packet */ > +static int > +smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) > +{ > + struct smsc911x_data *pdata; > + > + BUG_ON(!skb); > + BUG_ON(!dev); > + BUG_ON(!netdev_priv(dev)); More bullshit bugon. Why the silly wrapper func? > + pdata = netdev_priv(dev); > + smsc911x_tx_sendskb(pdata, skb); > + return 0; > +} ... > + platform_set_drvdata(pdev, netdev); > + strcpy(netdev->name, "eth%d"); Already done by alloc_etherdev... > + retval = register_netdev(netdev); > + > + if (retval) { > + SMSC_WARNING("Error %i registering device", retval); > + retval = -ENODEV; > + goto out_unmap_io; > + } else { > + SMSC_TRACE("Network interface: \"%s\"",netdev->name); > + } > + > + if ((retval = smsc911x_init(netdev)) < 0) > + goto out_deregister_netdev; Please init before registering. Because during registration it is possible that some callback would want to bring up the device automatically, or send a packet. > + if (request_irq(netdev->irq, smsc911x_irqhandler, > + SA_INTERRUPT, SMSC_CHIPNAME, netdev_priv(netdev)) != 0) { > + SMSC_WARNING("Unable to claim requested irq: %d", netdev->irq); > + retval = -ENODEV; > + goto out_deregister_netdev; > + } You must have the IRQ in place before registering. > + return 0; > + > +out_deregister_netdev: > + unregister_netdev(netdev); > +out_unmap_io: > + platform_set_drvdata(pdev, NULL); > + iounmap((void *) base); > +out_free_netdev: > + rx_tasklet_parameter = 0; > + free_netdev(netdev); > +out_release_io: > + release_mem_region(res->start, res->end - res->start); > +out: > + return retval; > +} > + > diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h > new file mode 100644 > index 0000000..5ab2987 > --- /dev/null > +++ b/drivers/net/smsc911x.h > @@ -0,0 +1,526 @@ > +#ifndef __SMSC911X_H__ > +#define __SMSC911X_H__ > + > +#define USE_PHY_WORK_AROUND > +#define USE_LED1_WORK_AROUND /* 10/100 LED link-state inversion */ > + > +/* Debugging */ > +#define USE_DEBUG 0 > +#if USE_DEBUG >= 1 > +# define SMSC_WARNING(fmt, args...) \ > + printk(KERN_EMERG "SMSC_WARNING: %s: " fmt "\n",\ > + __FUNCTION__ , ## args) > +#else > +# define SMSC_WARNING(msg, args...) > +#endif /* USE_DEBUG >= 1 */ Consider using pr_debug and the ethtool message level model. > +#if USE_DEBUG >= 2 > +# define SMSC_TRACE(fmt,args...) \ > + printk(KERN_EMERG "SMSC_TRACE: %s: " fmt "\n", \ > + __FUNCTION__ , ## args) > +#else > +# define SMSC_TRACE(msg,args...) > +#endif /* USE_DEBUG >= 2 */ -- Stephen Hemminger <shemminger@xxxxxxxx> "And in the Packet there writ down that doome" - : send the line "unsubscribe linux-net" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html