* tuning
* 0.20 - fix stupid RFEN thinko. i am such a smurf.
*
- * 20040828 0.21 - add hardware vlan accleration
- * by Neil Horman <nhorman@redhat.com>
* Driver Overview
* ===============
*
//#define dprintk printk
#define dprintk(x...) do { } while (0)
-#include <linux/config.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/prefetch.h>
#include <linux/ethtool.h>
#include <linux/timer.h>
-#include <linux/if_vlan.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#define DRV_NAME "ns83820"
-/* Global parameters. See module_param near the bottom. */
+/* Global parameters. See MODULE_PARM near the bottom. */
static int ihr = 2;
static int reset_phy = 0;
static int lnksts = 0; /* CFG_LNKSTS bit polarity */
/* tunables */
#define RX_BUF_SIZE 1500 /* 8192 */
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define NS83820_VLAN_ACCEL_SUPPORT
-#endif
/* Must not exceed ~65000. */
#define NR_RX_DESC 64
#define EXTSTS_UDPPKT 0x00200000
#define EXTSTS_TCPPKT 0x00080000
#define EXTSTS_IPPKT 0x00020000
-#define EXTSTS_VPKT 0x00010000
-#define EXTSTS_VTG_MASK 0x0000ffff
#define SPDSTS_POLARITY (CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))
#define CMDSTS_INTR 0x20000000
#define CMDSTS_ERR 0x10000000
#define CMDSTS_OK 0x08000000
-#define CMDSTS_RUNT 0x00200000
#define CMDSTS_LEN_MASK 0x0000ffff
#define CMDSTS_DEST_MASK 0x01800000
struct ns83820 {
struct net_device_stats stats;
- u8 __iomem *base;
+ u8 *base;
struct pci_dev *pci_dev;
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
- struct vlan_group *vlgrp;
-#endif
-
struct rx_info rx_info;
struct tasklet_struct rx_tasklet;
(((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > MIN_TX_DESC_FREE)
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
-static void ns83820_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
-{
- struct ns83820 *dev = PRIV(ndev);
-
- spin_lock_irq(&dev->misc_lock);
- spin_lock(&dev->tx_lock);
-
- dev->vlgrp = grp;
-
- spin_unlock(&dev->tx_lock);
- spin_unlock_irq(&dev->misc_lock);
-}
-
-static void ns83820_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid)
-{
- struct ns83820 *dev = PRIV(ndev);
-
- spin_lock_irq(&dev->misc_lock);
- spin_lock(&dev->tx_lock);
- if (dev->vlgrp)
- dev->vlgrp->vlan_devices[vid] = NULL;
- spin_unlock(&dev->tx_lock);
- spin_unlock_irq(&dev->misc_lock);
-}
-#endif
-
/* Packet Receiver
*
* The hardware supports linked lists of receive descriptors for
struct ns83820 *dev = PRIV(ndev);
struct rx_info *info = &dev->rx_info;
unsigned next_rx;
- int rx_rc, len;
u32 cmdsts, *desc;
unsigned long flags;
int nr = 0;
pci_unmap_single(dev->pci_dev, bufptr,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
- len = cmdsts & CMDSTS_LEN_MASK;
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
- /* NH: As was mentioned below, this chip is kinda
- * brain dead about vlan tag stripping. Frames
- * that are 64 bytes with a vlan header appended
- * like arp frames, or pings, are flagged as Runts
- * when the tag is stripped and hardware. This
- * also means that the OK bit in the descriptor
- * is cleared when the frame comes in so we have
- * to do a specific length check here to make sure
- * the frame would have been ok, had we not stripped
- * the tag.
- */
- if (likely((CMDSTS_OK & cmdsts) ||
- ((cmdsts & CMDSTS_RUNT) && len >= 56))) {
-#else
if (likely(CMDSTS_OK & cmdsts)) {
-#endif
+ int len = cmdsts & 0xffff;
skb_put(skb, len);
if (unlikely(!skb))
goto netdev_mangle_me_harder_failed;
skb->ip_summed = CHECKSUM_NONE;
}
skb->protocol = eth_type_trans(skb, ndev);
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
- if(extsts & EXTSTS_VPKT) {
- unsigned short tag;
- tag = ntohs(extsts & EXTSTS_VTG_MASK);
- rx_rc = vlan_hwaccel_rx(skb,dev->vlgrp,tag);
- } else {
- rx_rc = netif_rx(skb);
- }
-#else
- rx_rc = netif_rx(skb);
-#endif
- if (NET_RX_DROP == rx_rc) {
+ if (NET_RX_DROP == netif_rx(skb)) {
netdev_mangle_me_harder_failed:
dev->stats.rx_dropped ++;
}
extsts |= EXTSTS_UDPPKT;
}
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
- if(vlan_tx_tag_present(skb)) {
- /* fetch the vlan tag info out of the
- * ancilliary data if the vlan code
- * is using hw vlan acceleration
- */
- short tag = vlan_tx_tag_get(skb);
- extsts |= (EXTSTS_VPKT | htons(tag));
- }
-#endif
-
len = skb->len;
if (nr_frags)
len -= skb->data_len;
static void ns83820_update_stats(struct ns83820 *dev)
{
- u8 __iomem *base = dev->base;
+ u8 *base = dev->base;
/* the DP83820 will freeze counters, so we need to read all of them */
dev->stats.rx_errors += readl(base + 0x60) & 0xffff;
return &dev->stats;
}
-static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
+static int ns83820_ethtool_ioctl (struct ns83820 *dev, void __user *useraddr)
{
- struct ns83820 *dev = PRIV(ndev);
- strcpy(info->driver, "ns83820");
- strcpy(info->version, VERSION);
- strcpy(info->bus_info, pci_name(dev->pci_dev));
+ u32 ethcmd;
+
+ if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd)))
+ return -EFAULT;
+
+ switch (ethcmd) {
+ case ETHTOOL_GDRVINFO:
+ {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ strcpy(info.driver, "ns83820");
+ strcpy(info.version, VERSION);
+ strcpy(info.bus_info, pci_name(dev->pci_dev));
+ if (copy_to_user(useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get link status */
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = { ETHTOOL_GLINK };
+ u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+
+ if (cfg & CFG_LNKSTS)
+ edata.data = 1;
+ else
+ edata.data = 0;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
}
-static u32 ns83820_get_link(struct net_device *ndev)
+static int ns83820_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{
struct ns83820 *dev = PRIV(ndev);
- u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
- return cfg & CFG_LNKSTS ? 1 : 0;
-}
-static struct ethtool_ops ops = {
- .get_drvinfo = ns83820_get_drvinfo,
- .get_link = ns83820_get_link
-};
+ switch(cmd) {
+ case SIOCETHTOOL:
+ return ns83820_ethtool_ioctl(dev, rq->ifr_data);
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
static void ns83820_mib_isr(struct ns83820 *dev)
{
static void ns83820_set_multicast(struct net_device *ndev)
{
struct ns83820 *dev = PRIV(ndev);
- u8 __iomem *rfcr = dev->base + RFCR;
+ u8 *rfcr = dev->base + RFCR;
u32 and_mask = 0xffffffff;
u32 or_mask = 0;
u32 val;
dev->IMR_cache = 0;
- setup_ee_mem_bitbanger(&dev->ee, dev->base + MEAR, 3, 2, 1, 0,
+ setup_ee_mem_bitbanger(&dev->ee, (long)dev->base + MEAR, 3, 2, 1, 0,
0);
err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ,
ndev->get_stats = ns83820_get_stats;
ndev->change_mtu = ns83820_change_mtu;
ndev->set_multicast_list = ns83820_set_multicast;
- SET_ETHTOOL_OPS(ndev, &ops);
+ ndev->do_ioctl = ns83820_ioctl;
ndev->tx_timeout = ns83820_tx_timeout;
ndev->watchdog_timeo = 5 * HZ;
+
pci_set_drvdata(pci_dev, ndev);
ns83820_do_reset(dev, CR_RST);
* a ping with a VLAN header) then the card, strips the 4 byte VLAN
* tag and then checks the packet size, so if RXCFG_ARP is not enabled,
* it discrards it!. These guys......
- * also turn on tag stripping if hardware acceleration is enabled
*/
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
-#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN|VRCR_VTREN)
-#else
-#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN)
-#endif
- writel(VRCR_INIT_VALUE, dev->base + VRCR);
+ writel(VRCR_IPEN | VRCR_VTDEN, dev->base + VRCR);
- /* Enable per-packet TCP/UDP/IP checksumming
- * and per packet vlan tag insertion if
- * vlan hardware acceleration is enabled
- */
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
-#define VTCR_INIT_VALUE (VTCR_PPCHK|VTCR_VPPTI)
-#else
-#define VTCR_INIT_VALUE VTCR_PPCHK
-#endif
- writel(VTCR_INIT_VALUE, dev->base + VTCR);
+ /* Enable per-packet TCP/UDP/IP checksumming */
+ writel(VTCR_PPCHK, dev->base + VTCR);
/* Ramit : Enable async and sync pause frames */
/* writel(0, dev->base + PCR); */
ndev->features |= NETIF_F_SG;
ndev->features |= NETIF_F_IP_CSUM;
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
- /* We also support hardware vlan acceleration */
- ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- ndev->vlan_rx_register = ns83820_vlan_rx_register;
- ndev->vlan_rx_kill_vid = ns83820_vlan_rx_kill_vid;
-#endif
-
if (using_dac) {
printk(KERN_INFO "%s: using 64 bit addressing.\n",
ndev->name);
MODULE_DEVICE_TABLE(pci, ns83820_pci_tbl);
-module_param(lnksts, int, 0);
+MODULE_PARM(lnksts, "i");
MODULE_PARM_DESC(lnksts, "Polarity of LNKSTS bit");
-module_param(ihr, int, 0);
+MODULE_PARM(ihr, "i");
MODULE_PARM_DESC(ihr, "Time in 100 us increments to delay interrupts (range 0-127)");
-module_param(reset_phy, int, 0);
+MODULE_PARM(reset_phy, "i");
MODULE_PARM_DESC(reset_phy, "Set to 1 to reset the PHY on startup");
module_init(ns83820_init);