History

net: lan966x: Fix usage of lan966x->mac_lock inside lan966x_mac_irq_handler

The problem with this spin lock is that it was just protecting the list of the MAC entries in SW and not also the access to the MAC entries in HW. Because the access to HW is indirect, then it could happen to have race conditions. For example when SW introduced an entry in MAC table and the irq mac is trying to read something from the MAC. Update such that also the access to MAC entries in HW is protected by this lock.

Horatiu Vultur committed 4 years ago

Commit c1924681 parent 99343cf1 file · +12 −7Browse files

Unified · Split

drivers/net/ethernet/microchip/lan966x/lan966x_mac.c+12−7
@@ -183,7 +183,7 @@ static struct lan966x_mac_entry *lan966x_mac_alloc_entry(const unsigned char *ma · 182 unmodified lines
183183 {
184184 struct lan966x_mac_entry *mac_entry;
185185
186− mac_entry = kzalloc(sizeof(*mac_entry), GFP_KERNEL);
186+ mac_entry = kzalloc(sizeof(*mac_entry), GFP_ATOMIC);
187187 if (!mac_entry)
188188 return NULL;
189189
@@ -310,8 +310,8 @@ void lan966x_mac_purge_entries(struct lan966x *lan966x) · 120 unmodified lines
310310 spin_lock(&lan966x->mac_lock);
311311 list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
312312 list) {
313− lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
314− ENTRYTYPE_LOCKED);
313+ lan966x_mac_forget_locked(lan966x, mac_entry->mac,
314+ mac_entry->vid, ENTRYTYPE_LOCKED);
315315
316316 list_del(&mac_entry->list);
317317 kfree(mac_entry);
@@ -427,13 +427,14 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row, · 109 unmodified lines
427427 if (WARN_ON(dest_idx >= lan966x->num_phys_ports))
428428 continue;
429429
430+ spin_lock(&lan966x->mac_lock);
430431 mac_entry = lan966x_mac_alloc_entry(mac, vid, dest_idx);
431− if (!mac_entry)
432+ if (!mac_entry) {
433+ spin_unlock(&lan966x->mac_lock);
432434 return;
435+ }
433436
434437 mac_entry->row = row;
435−
436− spin_lock(&lan966x->mac_lock);
437438 list_add_tail(&mac_entry->list, &lan966x->mac_entries);
438439 spin_unlock(&lan966x->mac_lock);
439440
@@ -455,6 +456,7 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x) · 15 unmodified lines
455456 lan966x, ANA_MACTINDX);
456457
457458 while (1) {
459+ spin_lock(&lan966x->mac_lock);
458460 lan_rmw(ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_SYNC_GET_NEXT),
459461 ANA_MACACCESS_MAC_TABLE_CMD,
460462 lan966x, ANA_MACACCESS);
@@ -478,12 +480,15 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x) · 17 unmodified lines
478480 stop = false;
479481
480482 if (column == LAN966X_MAC_COLUMNS - 1 &&
481− index == 0 && stop)
483+ index == 0 && stop) {
484+ spin_unlock(&lan966x->mac_lock);
482485 break;
486+ }
483487
484488 entry[column].mach = lan_rd(lan966x, ANA_MACHDATA);
485489 entry[column].macl = lan_rd(lan966x, ANA_MACLDATA);
486490 entry[column].maca = lan_rd(lan966x, ANA_MACACCESS);
491+ spin_unlock(&lan966x->mac_lock);
487492
488493 /* Once all the columns are read process them */
489494 if (column == LAN966X_MAC_COLUMNS - 1) {