Commit 40a1578d authored by Claudiu Manoil's avatar Claudiu Manoil Committed by David S. Miller

ocelot: Dont allocate another multicast list, use __dev_mc_sync

Doing kmalloc in atomic context is always an issue,
more so for a list that can grow significantly.
Turns out that the driver only uses the duplicated
list of multicast mac addresses to keep track of
what addresses to delete from h/w before committing
the new list from kernel to h/w back again via set_rx_mode,
every time this list gets updated by the kernel.
Given that the h/w knows how to add and delete mac addresses
based on the mac address value alone, __dev_mc_sync should be
the much better choice of kernel API for these operations
avoiding the considerable overhead of maintaining a duplicated
list in the driver.
Signed-off-by: default avatarClaudiu Manoil <claudiu.manoil@nxp.com>
Tested-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Acked-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7dc2bcca
...@@ -593,45 +593,25 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -593,45 +593,25 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static void ocelot_mact_mc_reset(struct ocelot_port *port) static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr)
{ {
struct ocelot *ocelot = port->ocelot; struct ocelot_port *port = netdev_priv(dev);
struct netdev_hw_addr *ha, *n;
/* Free and forget all the MAC addresses stored in the port private mc return ocelot_mact_forget(port->ocelot, addr, port->pvid);
* list. These are mc addresses that were previously added by calling
* ocelot_mact_mc_add().
*/
list_for_each_entry_safe(ha, n, &port->mc, list) {
ocelot_mact_forget(ocelot, ha->addr, port->pvid);
list_del(&ha->list);
kfree(ha);
}
} }
static int ocelot_mact_mc_add(struct ocelot_port *port, static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr)
struct netdev_hw_addr *hw_addr)
{ {
struct ocelot *ocelot = port->ocelot; struct ocelot_port *port = netdev_priv(dev);
struct netdev_hw_addr *ha = kzalloc(sizeof(*ha), GFP_ATOMIC);
if (!ha)
return -ENOMEM;
memcpy(ha, hw_addr, sizeof(*ha));
list_add_tail(&ha->list, &port->mc);
ocelot_mact_learn(ocelot, PGID_CPU, ha->addr, port->pvid, return ocelot_mact_learn(port->ocelot, PGID_CPU, addr, port->pvid,
ENTRYTYPE_LOCKED); ENTRYTYPE_LOCKED);
return 0;
} }
static void ocelot_set_rx_mode(struct net_device *dev) static void ocelot_set_rx_mode(struct net_device *dev)
{ {
struct ocelot_port *port = netdev_priv(dev); struct ocelot_port *port = netdev_priv(dev);
struct ocelot *ocelot = port->ocelot; struct ocelot *ocelot = port->ocelot;
struct netdev_hw_addr *ha;
int i; int i;
u32 val; u32 val;
...@@ -643,13 +623,7 @@ static void ocelot_set_rx_mode(struct net_device *dev) ...@@ -643,13 +623,7 @@ static void ocelot_set_rx_mode(struct net_device *dev)
for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++) for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++)
ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i); ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i);
/* Handle the device multicast addresses. First remove all the __dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
* previously installed addresses and then add the latest ones to the
* mac table.
*/
ocelot_mact_mc_reset(port);
netdev_for_each_mc_addr(ha, dev)
ocelot_mact_mc_add(port, ha);
} }
static int ocelot_port_get_phys_port_name(struct net_device *dev, static int ocelot_port_get_phys_port_name(struct net_device *dev,
...@@ -1657,7 +1631,6 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, ...@@ -1657,7 +1631,6 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
ocelot_port->regs = regs; ocelot_port->regs = regs;
ocelot_port->chip_port = port; ocelot_port->chip_port = port;
ocelot_port->phy = phy; ocelot_port->phy = phy;
INIT_LIST_HEAD(&ocelot_port->mc);
ocelot->ports[port] = ocelot_port; ocelot->ports[port] = ocelot_port;
dev->netdev_ops = &ocelot_port_netdev_ops; dev->netdev_ops = &ocelot_port_netdev_ops;
......
...@@ -441,10 +441,6 @@ struct ocelot_port { ...@@ -441,10 +441,6 @@ struct ocelot_port {
struct phy_device *phy; struct phy_device *phy;
void __iomem *regs; void __iomem *regs;
u8 chip_port; u8 chip_port;
/* Keep a track of the mc addresses added to the mac table, so that they
* can be removed when needed.
*/
struct list_head mc;
/* Ingress default VLAN (pvid) */ /* Ingress default VLAN (pvid) */
u16 pvid; u16 pvid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment