|
@@ -28,6 +28,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>
|
|
@@ -57,13 +58,20 @@ static const char *meth_str="SGI O2 Fast Ethernet";
|
|
|
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 +87,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;
|
|
|
};
|
|
|
|
|
@@ -765,6 +776,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,6 +819,7 @@ 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,
|
|
|
};
|
|
|
|
|
|
/*
|