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
183{183{
184 struct lan966x_mac_entry *mac_entry;184 struct lan966x_mac_entry *mac_entry;
185 185
186 mac_entry = kzalloc(sizeof(*mac_entry), GFP_KERNEL);186 mac_entry = kzalloc(sizeof(*mac_entry), GFP_ATOMIC);
187 if (!mac_entry)187 if (!mac_entry)
188 return NULL;188 return NULL;
189 189
@@ -310,8 +310,8 @@ void lan966x_mac_purge_entries(struct lan966x *lan966x) · 120 unmodified lines
310 spin_lock(&lan966x->mac_lock);310 spin_lock(&lan966x->mac_lock);
311 list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,311 list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
312 list) {312 list) {
313 lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,313 lan966x_mac_forget_locked(lan966x, mac_entry->mac,
314 ENTRYTYPE_LOCKED);314 mac_entry->vid, ENTRYTYPE_LOCKED);
315 315
316 list_del(&mac_entry->list);316 list_del(&mac_entry->list);
317 kfree(mac_entry);317 kfree(mac_entry);
@@ -427,13 +427,14 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row, · 109 unmodified lines
427 if (WARN_ON(dest_idx >= lan966x->num_phys_ports))427 if (WARN_ON(dest_idx >= lan966x->num_phys_ports))
428 continue;428 continue;
429 429
430 spin_lock(&lan966x->mac_lock);
430 mac_entry = lan966x_mac_alloc_entry(mac, vid, dest_idx);431 mac_entry = lan966x_mac_alloc_entry(mac, vid, dest_idx);
431 if (!mac_entry)432 if (!mac_entry) {
433 spin_unlock(&lan966x->mac_lock);
432 return;434 return;
435 }
433 436
434 mac_entry->row = row;437 mac_entry->row = row;
435
436 spin_lock(&lan966x->mac_lock);
437 list_add_tail(&mac_entry->list, &lan966x->mac_entries);438 list_add_tail(&mac_entry->list, &lan966x->mac_entries);
438 spin_unlock(&lan966x->mac_lock);439 spin_unlock(&lan966x->mac_lock);
439 440
@@ -455,6 +456,7 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x) · 15 unmodified lines
455 lan966x, ANA_MACTINDX);456 lan966x, ANA_MACTINDX);
456 457
457 while (1) {458 while (1) {
459 spin_lock(&lan966x->mac_lock);
458 lan_rmw(ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_SYNC_GET_NEXT),460 lan_rmw(ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_SYNC_GET_NEXT),
459 ANA_MACACCESS_MAC_TABLE_CMD,461 ANA_MACACCESS_MAC_TABLE_CMD,
460 lan966x, ANA_MACACCESS);462 lan966x, ANA_MACACCESS);
@@ -478,12 +480,15 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x) · 17 unmodified lines
478 stop = false;480 stop = false;
479 481
480 if (column == LAN966X_MAC_COLUMNS - 1 &&482 if (column == LAN966X_MAC_COLUMNS - 1 &&
481 index == 0 && stop)483 index == 0 && stop) {
484 spin_unlock(&lan966x->mac_lock);
482 break;485 break;
486 }
483 487
484 entry[column].mach = lan_rd(lan966x, ANA_MACHDATA);488 entry[column].mach = lan_rd(lan966x, ANA_MACHDATA);
485 entry[column].macl = lan_rd(lan966x, ANA_MACLDATA);489 entry[column].macl = lan_rd(lan966x, ANA_MACLDATA);
486 entry[column].maca = lan_rd(lan966x, ANA_MACACCESS);490 entry[column].maca = lan_rd(lan966x, ANA_MACACCESS);
491 spin_unlock(&lan966x->mac_lock);
487 492
488 /* Once all the columns are read process them */493 /* Once all the columns are read process them */
489 if (column == LAN966X_MAC_COLUMNS - 1) {494 if (column == LAN966X_MAC_COLUMNS - 1) {