aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/renesas
diff options
context:
space:
mode:
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>2012-02-15 12:55:03 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-16 17:08:09 -0500
commit6743fe6df43b4dc5950f605edfeee086d0a80f06 (patch)
tree38b3406e6d9f9b1b48ef87dee8c07c442e099b54 /drivers/net/ethernet/renesas
parent6ba88021c36516c26c11eff8c6d7d9a045faecd3 (diff)
net: sh_eth: add support for multicast filtering
Some controllers have TSU. It can filter multicast by hardware. This patch supports it. Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/renesas')
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c282
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h9
2 files changed, 286 insertions, 5 deletions
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 8bd0e5897424..99d8ce8379c8 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -1604,18 +1604,289 @@ static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq,
1604} 1604}
1605 1605
1606#if defined(SH_ETH_HAS_TSU) 1606#if defined(SH_ETH_HAS_TSU)
1607/* For TSU_POSTn. Please refer to the manual about this (strange) bitfields */
1608static void *sh_eth_tsu_get_post_reg_offset(struct sh_eth_private *mdp,
1609 int entry)
1610{
1611 return sh_eth_tsu_get_offset(mdp, TSU_POST1) + (entry / 8 * 4);
1612}
1613
1614static u32 sh_eth_tsu_get_post_mask(int entry)
1615{
1616 return 0x0f << (28 - ((entry % 8) * 4));
1617}
1618
1619static u32 sh_eth_tsu_get_post_bit(struct sh_eth_private *mdp, int entry)
1620{
1621 return (0x08 >> (mdp->port << 1)) << (28 - ((entry % 8) * 4));
1622}
1623
1624static void sh_eth_tsu_enable_cam_entry_post(struct net_device *ndev,
1625 int entry)
1626{
1627 struct sh_eth_private *mdp = netdev_priv(ndev);
1628 u32 tmp;
1629 void *reg_offset;
1630
1631 reg_offset = sh_eth_tsu_get_post_reg_offset(mdp, entry);
1632 tmp = ioread32(reg_offset);
1633 iowrite32(tmp | sh_eth_tsu_get_post_bit(mdp, entry), reg_offset);
1634}
1635
1636static bool sh_eth_tsu_disable_cam_entry_post(struct net_device *ndev,
1637 int entry)
1638{
1639 struct sh_eth_private *mdp = netdev_priv(ndev);
1640 u32 post_mask, ref_mask, tmp;
1641 void *reg_offset;
1642
1643 reg_offset = sh_eth_tsu_get_post_reg_offset(mdp, entry);
1644 post_mask = sh_eth_tsu_get_post_mask(entry);
1645 ref_mask = sh_eth_tsu_get_post_bit(mdp, entry) & ~post_mask;
1646
1647 tmp = ioread32(reg_offset);
1648 iowrite32(tmp & ~post_mask, reg_offset);
1649
1650 /* If other port enables, the function returns "true" */
1651 return tmp & ref_mask;
1652}
1653
1654static int sh_eth_tsu_busy(struct net_device *ndev)
1655{
1656 int timeout = SH_ETH_TSU_TIMEOUT_MS * 100;
1657 struct sh_eth_private *mdp = netdev_priv(ndev);
1658
1659 while ((sh_eth_tsu_read(mdp, TSU_ADSBSY) & TSU_ADSBSY_0)) {
1660 udelay(10);
1661 timeout--;
1662 if (timeout <= 0) {
1663 dev_err(&ndev->dev, "%s: timeout\n", __func__);
1664 return -ETIMEDOUT;
1665 }
1666 }
1667
1668 return 0;
1669}
1670
1671static int sh_eth_tsu_write_entry(struct net_device *ndev, void *reg,
1672 const u8 *addr)
1673{
1674 u32 val;
1675
1676 val = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3];
1677 iowrite32(val, reg);
1678 if (sh_eth_tsu_busy(ndev) < 0)
1679 return -EBUSY;
1680
1681 val = addr[4] << 8 | addr[5];
1682 iowrite32(val, reg + 4);
1683 if (sh_eth_tsu_busy(ndev) < 0)
1684 return -EBUSY;
1685
1686 return 0;
1687}
1688
1689static void sh_eth_tsu_read_entry(void *reg, u8 *addr)
1690{
1691 u32 val;
1692
1693 val = ioread32(reg);
1694 addr[0] = (val >> 24) & 0xff;
1695 addr[1] = (val >> 16) & 0xff;
1696 addr[2] = (val >> 8) & 0xff;
1697 addr[3] = val & 0xff;
1698 val = ioread32(reg + 4);
1699 addr[4] = (val >> 8) & 0xff;
1700 addr[5] = val & 0xff;
1701}
1702
1703
1704static int sh_eth_tsu_find_entry(struct net_device *ndev, const u8 *addr)
1705{
1706 struct sh_eth_private *mdp = netdev_priv(ndev);
1707 void *reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
1708 int i;
1709 u8 c_addr[ETH_ALEN];
1710
1711 for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) {
1712 sh_eth_tsu_read_entry(reg_offset, c_addr);
1713 if (memcmp(addr, c_addr, ETH_ALEN) == 0)
1714 return i;
1715 }
1716
1717 return -ENOENT;
1718}
1719
1720static int sh_eth_tsu_find_empty(struct net_device *ndev)
1721{
1722 u8 blank[ETH_ALEN];
1723 int entry;
1724
1725 memset(blank, 0, sizeof(blank));
1726 entry = sh_eth_tsu_find_entry(ndev, blank);
1727 return (entry < 0) ? -ENOMEM : entry;
1728}
1729
1730static int sh_eth_tsu_disable_cam_entry_table(struct net_device *ndev,
1731 int entry)
1732{
1733 struct sh_eth_private *mdp = netdev_priv(ndev);
1734 void *reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
1735 int ret;
1736 u8 blank[ETH_ALEN];
1737
1738 sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) &
1739 ~(1 << (31 - entry)), TSU_TEN);
1740
1741 memset(blank, 0, sizeof(blank));
1742 ret = sh_eth_tsu_write_entry(ndev, reg_offset + entry * 8, blank);
1743 if (ret < 0)
1744 return ret;
1745 return 0;
1746}
1747
1748static int sh_eth_tsu_add_entry(struct net_device *ndev, const u8 *addr)
1749{
1750 struct sh_eth_private *mdp = netdev_priv(ndev);
1751 void *reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
1752 int i, ret;
1753
1754 if (!mdp->cd->tsu)
1755 return 0;
1756
1757 i = sh_eth_tsu_find_entry(ndev, addr);
1758 if (i < 0) {
1759 /* No entry found, create one */
1760 i = sh_eth_tsu_find_empty(ndev);
1761 if (i < 0)
1762 return -ENOMEM;
1763 ret = sh_eth_tsu_write_entry(ndev, reg_offset + i * 8, addr);
1764 if (ret < 0)
1765 return ret;
1766
1767 /* Enable the entry */
1768 sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) |
1769 (1 << (31 - i)), TSU_TEN);
1770 }
1771
1772 /* Entry found or created, enable POST */
1773 sh_eth_tsu_enable_cam_entry_post(ndev, i);
1774
1775 return 0;
1776}
1777
1778static int sh_eth_tsu_del_entry(struct net_device *ndev, const u8 *addr)
1779{
1780 struct sh_eth_private *mdp = netdev_priv(ndev);
1781 int i, ret;
1782
1783 if (!mdp->cd->tsu)
1784 return 0;
1785
1786 i = sh_eth_tsu_find_entry(ndev, addr);
1787 if (i) {
1788 /* Entry found */
1789 if (sh_eth_tsu_disable_cam_entry_post(ndev, i))
1790 goto done;
1791
1792 /* Disable the entry if both ports was disabled */
1793 ret = sh_eth_tsu_disable_cam_entry_table(ndev, i);
1794 if (ret < 0)
1795 return ret;
1796 }
1797done:
1798 return 0;
1799}
1800
1801static int sh_eth_tsu_purge_all(struct net_device *ndev)
1802{
1803 struct sh_eth_private *mdp = netdev_priv(ndev);
1804 int i, ret;
1805
1806 if (unlikely(!mdp->cd->tsu))
1807 return 0;
1808
1809 for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++) {
1810 if (sh_eth_tsu_disable_cam_entry_post(ndev, i))
1811 continue;
1812
1813 /* Disable the entry if both ports was disabled */
1814 ret = sh_eth_tsu_disable_cam_entry_table(ndev, i);
1815 if (ret < 0)
1816 return ret;
1817 }
1818
1819 return 0;
1820}
1821
1822static void sh_eth_tsu_purge_mcast(struct net_device *ndev)
1823{
1824 struct sh_eth_private *mdp = netdev_priv(ndev);
1825 u8 addr[ETH_ALEN];
1826 void *reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
1827 int i;
1828
1829 if (unlikely(!mdp->cd->tsu))
1830 return;
1831
1832 for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) {
1833 sh_eth_tsu_read_entry(reg_offset, addr);
1834 if (is_multicast_ether_addr(addr))
1835 sh_eth_tsu_del_entry(ndev, addr);
1836 }
1837}
1838
1607/* Multicast reception directions set */ 1839/* Multicast reception directions set */
1608static void sh_eth_set_multicast_list(struct net_device *ndev) 1840static void sh_eth_set_multicast_list(struct net_device *ndev)
1609{ 1841{
1842 struct sh_eth_private *mdp = netdev_priv(ndev);
1843 u32 ecmr_bits;
1844 int mcast_all = 0;
1845 unsigned long flags;
1846
1847 spin_lock_irqsave(&mdp->lock, flags);
1848 /*
1849 * Initial condition is MCT = 1, PRM = 0.
1850 * Depending on ndev->flags, set PRM or clear MCT
1851 */
1852 ecmr_bits = (sh_eth_read(ndev, ECMR) & ~ECMR_PRM) | ECMR_MCT;
1853
1854 if (!(ndev->flags & IFF_MULTICAST)) {
1855 sh_eth_tsu_purge_mcast(ndev);
1856 mcast_all = 1;
1857 }
1858 if (ndev->flags & IFF_ALLMULTI) {
1859 sh_eth_tsu_purge_mcast(ndev);
1860 ecmr_bits &= ~ECMR_MCT;
1861 mcast_all = 1;
1862 }
1863
1610 if (ndev->flags & IFF_PROMISC) { 1864 if (ndev->flags & IFF_PROMISC) {
1611 /* Set promiscuous. */ 1865 sh_eth_tsu_purge_all(ndev);
1612 sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_MCT) | 1866 ecmr_bits = (ecmr_bits & ~ECMR_MCT) | ECMR_PRM;
1613 ECMR_PRM, ECMR); 1867 } else if (mdp->cd->tsu) {
1868 struct netdev_hw_addr *ha;
1869 netdev_for_each_mc_addr(ha, ndev) {
1870 if (mcast_all && is_multicast_ether_addr(ha->addr))
1871 continue;
1872
1873 if (sh_eth_tsu_add_entry(ndev, ha->addr) < 0) {
1874 if (!mcast_all) {
1875 sh_eth_tsu_purge_mcast(ndev);
1876 ecmr_bits &= ~ECMR_MCT;
1877 mcast_all = 1;
1878 }
1879 }
1880 }
1614 } else { 1881 } else {
1615 /* Normal, unicast/broadcast-only mode. */ 1882 /* Normal, unicast/broadcast-only mode. */
1616 sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_PRM) | 1883 ecmr_bits = (ecmr_bits & ~ECMR_PRM) | ECMR_MCT;
1617 ECMR_MCT, ECMR);
1618 } 1884 }
1885
1886 /* update the ethernet mode */
1887 sh_eth_write(ndev, ecmr_bits, ECMR);
1888
1889 spin_unlock_irqrestore(&mdp->lock, flags);
1619} 1890}
1620#endif /* SH_ETH_HAS_TSU */ 1891#endif /* SH_ETH_HAS_TSU */
1621 1892
@@ -1869,6 +2140,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
1869 } 2140 }
1870 mdp->tsu_addr = ioremap(rtsu->start, 2141 mdp->tsu_addr = ioremap(rtsu->start,
1871 resource_size(rtsu)); 2142 resource_size(rtsu));
2143 mdp->port = devno % 2;
1872 } 2144 }
1873 2145
1874 /* initialize first or needed device */ 2146 /* initialize first or needed device */
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index cb07add8638f..86b392e22c01 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -29,6 +29,8 @@
29#define RX_RING_SIZE 64 /* Rx ring size */ 29#define RX_RING_SIZE 64 /* Rx ring size */
30#define ETHERSMALL 60 30#define ETHERSMALL 60
31#define PKT_BUF_SZ 1538 31#define PKT_BUF_SZ 1538
32#define SH_ETH_TSU_TIMEOUT_MS 500
33#define SH_ETH_TSU_CAM_ENTRIES 32
32 34
33enum { 35enum {
34 /* E-DMAC registers */ 36 /* E-DMAC registers */
@@ -778,6 +780,7 @@ struct sh_eth_private {
778 char post_rx; /* POST receive */ 780 char post_rx; /* POST receive */
779 char post_fw; /* POST forward */ 781 char post_fw; /* POST forward */
780 struct net_device_stats tsu_stats; /* TSU forward status */ 782 struct net_device_stats tsu_stats; /* TSU forward status */
783 int port; /* for TSU */
781 784
782 unsigned no_ether_link:1; 785 unsigned no_ether_link:1;
783 unsigned ether_link_active_low:1; 786 unsigned ether_link_active_low:1;
@@ -811,6 +814,12 @@ static inline unsigned long sh_eth_read(struct net_device *ndev,
811 return ioread32(mdp->addr + mdp->reg_offset[enum_index]); 814 return ioread32(mdp->addr + mdp->reg_offset[enum_index]);
812} 815}
813 816
817static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp,
818 int enum_index)
819{
820 return mdp->tsu_addr + mdp->reg_offset[enum_index];
821}
822
814static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, 823static inline void sh_eth_tsu_write(struct sh_eth_private *mdp,
815 unsigned long data, int enum_index) 824 unsigned long data, int enum_index)
816{ 825{