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