net: qfec: Add multicast support
This adds multicast support to the qfec driver. The driver
is Level 2 compliant. It can send and receive multicast traffic.
Acked-by: Kaushik Sikdar <ksikdar@qualcomm.com>
Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>
diff --git a/drivers/net/qfec.c b/drivers/net/qfec.c
index 71ddcff..d554fec 100644
--- a/drivers/net/qfec.c
+++ b/drivers/net/qfec.c
@@ -704,6 +704,56 @@
}
/*
+ * set up the RX filter
+ */
+static void qfec_set_rx_mode(struct net_device *dev)
+{
+ struct qfec_priv *priv = netdev_priv(dev);
+ uint32_t filter_conf;
+ int index;
+
+ /* Clear address filter entries */
+ for (index = 1; index < MAC_ADR_MAX; ++index) {
+ qfec_reg_write(priv, MAC_ADR_HIGH_REG_N(index), 0);
+ qfec_reg_write(priv, MAC_ADR_LOW_REG_N(index), 0);
+ }
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Receive all frames */
+ filter_conf = MAC_FR_FILTER_RA;
+ } else if ((dev->flags & IFF_MULTICAST) == 0) {
+ /* Unicast filtering only */
+ filter_conf = MAC_FR_FILTER_HPF;
+ } else if ((netdev_mc_count(dev) > MAC_ADR_MAX - 1) ||
+ (dev->flags & IFF_ALLMULTI)) {
+ /* Unicast filtering is enabled, Pass all multicast frames */
+ filter_conf = MAC_FR_FILTER_HPF | MAC_FR_FILTER_PM;
+ } else {
+ struct netdev_hw_addr *ha;
+
+ /* Both unicast and multicast filtering are enabled */
+ filter_conf = MAC_FR_FILTER_HPF;
+
+ index = 1;
+
+ netdev_for_each_mc_addr(ha, dev) {
+ uint32_t high, low;
+
+ high = (1 << 31) | (ha->addr[5] << 8) | (ha->addr[4]);
+ low = (ha->addr[3] << 24) | (ha->addr[2] << 16) |
+ (ha->addr[1] << 8) | (ha->addr[0]);
+
+ qfec_reg_write(priv, MAC_ADR_HIGH_REG_N(index), high);
+ qfec_reg_write(priv, MAC_ADR_LOW_REG_N(index), low);
+
+ index++;
+ }
+ }
+
+ qfec_reg_write(priv, MAC_FR_FILTER_REG, filter_conf);
+}
+
+/*
* reset the controller
*/
@@ -1782,6 +1832,7 @@
/* get/set (primary) MAC address */
qfec_set_adr_regs(priv, dev->dev_addr);
+ qfec_set_rx_mode(dev);
/* start phy monitor */
QFEC_LOG(QFEC_LOG_DBG, " %s: start timer\n", __func__);
@@ -1955,6 +2006,8 @@
QFEC_LOG(QFEC_LOG_DBG2, "qfec_stats:\n");
+ priv->stats.multicast = qfec_reg_read(priv, NUM_MULTCST_FRM_RCVD_G);
+
return &priv->stats;
}
@@ -2009,6 +2062,7 @@
.ndo_do_ioctl = qfec_do_ioctl,
.ndo_tx_timeout = qfec_tx_timeout,
.ndo_set_mac_address = qfec_set_mac_address,
+ .ndo_set_multicast_list = qfec_set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/qfec.h b/drivers/net/qfec.h
index 6328804..310406a 100644
--- a/drivers/net/qfec.h
+++ b/drivers/net/qfec.h
@@ -529,6 +529,12 @@
# define MAC_ADR_0_HIGH_REG 0x0040
# define MAC_ADR_0_LOW_REG 0x0044
/* additional pairs of registers for MAC addresses 1-15 */
+# define MAC_ADR_HIGH_REG_N(n) (((n) < 16) ? \
+ (MAC_ADR_0_HIGH_REG + (n) * 8) : \
+ (MAC_ADR16_HIGH_REG + ((n) - 16) * 8))
+# define MAC_ADR_LOW_REG_N(n) (((n) < 16) ? \
+ (MAC_ADR_0_LOW_REG + (n) * 8) : \
+ (MAC_ADR16_LOW_REG + ((n) - 16) * 8))
# define AN_CONTROL_REG 0x00c0
@@ -586,6 +592,7 @@
# define MMC_INTR_TX_REG 0x0108
# define MMC_INTR_MASK_RX_REG 0x010C
# define MMC_INTR_MASK_TX_REG 0x0110
+# define NUM_MULTCST_FRM_RCVD_G 0x0190
/* 0x0300-0x06fc reserved */