diff options
Diffstat (limited to 'drivers/net/ethernet/sgi/meth.c')
| -rw-r--r-- | drivers/net/ethernet/sgi/meth.c | 79 |
1 files changed, 53 insertions, 26 deletions
diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c index 60135aa5580..5564a5fa338 100644 --- a/drivers/net/ethernet/sgi/meth.c +++ b/drivers/net/ethernet/sgi/meth.c @@ -10,7 +10,6 @@ */ #include <linux/delay.h> #include <linux/dma-mapping.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -28,6 +27,7 @@ #include <linux/tcp.h> /* struct tcphdr */ #include <linux/skbuff.h> #include <linux/mii.h> /* MII definitions */ +#include <linux/crc32.h> #include <asm/ip32/mace.h> #include <asm/ip32/ip32_ints.h> @@ -58,12 +58,19 @@ static int timeout = TX_TIMEOUT; module_param(timeout, int, 0); /* + * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + * MACE Ethernet uses a 64 element hash table based on the Ethernet CRC. + */ +#define METH_MCF_LIMIT 32 + +/* * This structure is private to each device. It is used to pass * packets in and out, so there is place for a packet */ struct meth_private { /* in-memory copy of MAC Control register */ - unsigned long mac_ctrl; + u64 mac_ctrl; + /* in-memory copy of DMA Control register */ unsigned long dma_ctrl; /* address of PHY, used by mdio_* functions, initialized in mdio_probe */ @@ -79,6 +86,9 @@ struct meth_private { struct sk_buff *rx_skbs[RX_RING_ENTRIES]; unsigned long rx_write; + /* Multicast filter. */ + u64 mcast_filter; + spinlock_t meth_lock; }; @@ -201,11 +211,11 @@ static void meth_check_link(struct net_device *dev) static int meth_init_tx_ring(struct meth_private *priv) { /* Init TX ring */ - priv->tx_ring = dma_alloc_coherent(NULL, TX_RING_BUFFER_SIZE, - &priv->tx_ring_dma, GFP_ATOMIC); + priv->tx_ring = dma_zalloc_coherent(NULL, TX_RING_BUFFER_SIZE, + &priv->tx_ring_dma, GFP_ATOMIC); if (!priv->tx_ring) return -ENOMEM; - memset(priv->tx_ring, 0, TX_RING_BUFFER_SIZE); + priv->tx_count = priv->tx_read = priv->tx_write = 0; mace->eth.tx_ring_base = priv->tx_ring_dma; /* Now init skb save area */ @@ -765,6 +775,40 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } +static void meth_set_rx_mode(struct net_device *dev) +{ + struct meth_private *priv = netdev_priv(dev); + unsigned long flags; + + netif_stop_queue(dev); + spin_lock_irqsave(&priv->meth_lock, flags); + priv->mac_ctrl &= ~METH_PROMISC; + + if (dev->flags & IFF_PROMISC) { + priv->mac_ctrl |= METH_PROMISC; + priv->mcast_filter = 0xffffffffffffffffUL; + } else if ((netdev_mc_count(dev) > METH_MCF_LIMIT) || + (dev->flags & IFF_ALLMULTI)) { + priv->mac_ctrl |= METH_ACCEPT_AMCAST; + priv->mcast_filter = 0xffffffffffffffffUL; + } else { + struct netdev_hw_addr *ha; + priv->mac_ctrl |= METH_ACCEPT_MCAST; + + netdev_for_each_mc_addr(ha, dev) + set_bit((ether_crc(ETH_ALEN, ha->addr) >> 26), + (volatile unsigned long *)&priv->mcast_filter); + } + + /* Write the changes to the chip registers. */ + mace->eth.mac_ctrl = priv->mac_ctrl; + mace->eth.mcast_filter = priv->mcast_filter; + + /* Done! */ + spin_unlock_irqrestore(&priv->meth_lock, flags); + netif_wake_queue(dev); +} + static const struct net_device_ops meth_netdev_ops = { .ndo_open = meth_open, .ndo_stop = meth_release, @@ -774,12 +818,13 @@ static const struct net_device_ops meth_netdev_ops = { .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, + .ndo_set_rx_mode = meth_set_rx_mode, }; /* * The init function. */ -static int __devinit meth_probe(struct platform_device *pdev) +static int meth_probe(struct platform_device *pdev) { struct net_device *dev; struct meth_private *priv; @@ -793,7 +838,7 @@ static int __devinit meth_probe(struct platform_device *pdev) dev->watchdog_timeo = timeout; dev->irq = MACE_ETHERNET_IRQ; dev->base_addr = (unsigned long)&mace->eth; - memcpy(dev->dev_addr, o2meth_eaddr, 6); + memcpy(dev->dev_addr, o2meth_eaddr, ETH_ALEN); priv = netdev_priv(dev); spin_lock_init(&priv->meth_lock); @@ -816,7 +861,6 @@ static int __exit meth_remove(struct platform_device *pdev) unregister_netdev(dev); free_netdev(dev); - platform_set_drvdata(pdev, NULL); return 0; } @@ -830,24 +874,7 @@ static struct platform_driver meth_driver = { } }; -static int __init meth_init_module(void) -{ - int err; - - err = platform_driver_register(&meth_driver); - if (err) - printk(KERN_ERR "Driver registration failed\n"); - - return err; -} - -static void __exit meth_exit_module(void) -{ - platform_driver_unregister(&meth_driver); -} - -module_init(meth_init_module); -module_exit(meth_exit_module); +module_platform_driver(meth_driver); MODULE_AUTHOR("Ilya Volynets <ilya@theIlya.com>"); MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver"); |
