Re: smsc911x driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux