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: Claudiu Manoil <claudiu.manoil@nxp.com> Tested-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7dc2bccab0
commit
40a1578d63
|
@ -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 ocelot_mact_learn(port->ocelot, PGID_CPU, addr, port->pvid,
|
||||||
return -ENOMEM;
|
ENTRYTYPE_LOCKED);
|
||||||
|
|
||||||
memcpy(ha, hw_addr, sizeof(*ha));
|
|
||||||
list_add_tail(&ha->list, &port->mc);
|
|
||||||
|
|
||||||
ocelot_mact_learn(ocelot, PGID_CPU, ha->addr, port->pvid,
|
|
||||||
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)
|
||||||
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,
|
||||||
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 {
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue