| Author | Tokens | Token Proportion | Commits | Commit Proportion |
|---|---|---|---|---|
| Cedric Jehasse | 1120 | 76.76% | 1 | 4.35% |
| Vivien Didelot | 273 | 18.71% | 10 | 43.48% |
| Andrew Lunn | 34 | 2.33% | 6 | 26.09% |
| Lennert Buytenhek | 13 | 0.89% | 1 | 4.35% |
| Pavana Sharma | 8 | 0.55% | 1 | 4.35% |
| Guenter Roeck | 7 | 0.48% | 1 | 4.35% |
| Brandon Streiff | 2 | 0.14% | 1 | 4.35% |
| Thomas Gleixner | 1 | 0.07% | 1 | 4.35% |
| Marek Behún | 1 | 0.07% | 1 | 4.35% |
| Total | 1459 | 23 |
// SPDX-License-Identifier: GPL-2.0-or-later /* * Marvell 88E6xxx Switch TCAM support * * Copyright (c) 2026 Luminex Network Intelligence */ #include "linux/list.h" #include "chip.h" #include "tcam.h" /* TCAM operatation register */ #define MV88E6XXX_TCAM_OP 0x00 #define MV88E6XXX_TCAM_OP_BUSY 0x8000 #define MV88E6XXX_TCAM_OP_OP_MASK 0x7000 #define MV88E6XXX_TCAM_OP_OP_FLUSH_ALL 0x1000 #define MV88E6XXX_TCAM_OP_OP_FLUSH 0x2000 #define MV88E6XXX_TCAM_OP_OP_LOAD 0x3000 #define MV88E6XXX_TCAM_OP_OP_GET_NEXT 0x4000 #define MV88E6XXX_TCAM_OP_OP_READ 0x5000 /* TCAM extension register */ #define MV88E6XXX_TCAM_EXTENSION 0x01 /* TCAM keys register 1 */ #define MV88E6XXX_TCAM_KEYS1 0x02 #define MV88E6XXX_TCAM_KEYS1_FT_MASK 0xC000 #define MV88E6XXX_TCAM_KEYS1_SPV_MASK 0x0007 #define MV88E6XXX_TCAM_KEYS1_SPV_MASK_MASK 0x0700 /* TCAM keys register 2 */ #define MV88E6XXX_TCAM_KEYS2 0x03 #define MV88E6XXX_TCAM_KEYS2_SPV_MASK 0x00ff #define MV88E6XXX_TCAM_KEYS2_SPV_MASK_MASK 0xff00 #define MV88E6XXX_TCAM_ING_ACT3 0x04 #define MV88E6XXX_TCAM_ING_ACT3_SF 0x0800 #define MV88E6XXX_TCAM_ING_ACT3_DPV_MASK 0x07ff #define MV88E6XXX_TCAM_ING_ACT5 0x06 #define MV88E6XXX_TCAM_ING_ACT5_DPV_MODE_MASK 0xc000 static int mv88e6xxx_tcam_write(struct mv88e6xxx_chip *chip, int reg, u16 val) { return mv88e6xxx_write(chip, chip->info->tcam_addr, reg, val); } static int mv88e6xxx_tcam_wait(struct mv88e6xxx_chip *chip) { int bit = __bf_shf(MV88E6XXX_TCAM_OP_BUSY); return mv88e6xxx_wait_bit(chip, chip->info->tcam_addr, MV88E6XXX_TCAM_OP, bit, 0); } static int mv88e6xxx_tcam_read_page(struct mv88e6xxx_chip *chip, u8 page, u8 entry) { u16 val = MV88E6XXX_TCAM_OP_BUSY | MV88E6XXX_TCAM_OP_OP_READ | (page & 0x3) << 10 | entry; int err; err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_OP, val); if (err) return err; return mv88e6xxx_tcam_wait(chip); } static int mv88e6xxx_tcam_load_page(struct mv88e6xxx_chip *chip, u8 page, u8 entry) { u16 val = MV88E6XXX_TCAM_OP_BUSY | MV88E6XXX_TCAM_OP_OP_LOAD | (page & 0x3) << 10 | entry; int err; err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_OP, val); if (err) return err; return mv88e6xxx_tcam_wait(chip); } static int mv88e6xxx_tcam_flush_entry(struct mv88e6xxx_chip *chip, u8 entry) { u16 val = MV88E6XXX_TCAM_OP_BUSY | MV88E6XXX_TCAM_OP_OP_FLUSH | entry; int err; err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_OP, val); if (err) return err; return mv88e6xxx_tcam_wait(chip); } static int mv88e6xxx_tcam_flush_all(struct mv88e6xxx_chip *chip) { u16 val = MV88E6XXX_TCAM_OP_BUSY | MV88E6XXX_TCAM_OP_OP_FLUSH_ALL; int err; err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_OP, val); if (err) return err; return mv88e6xxx_tcam_wait(chip); } struct mv88e6xxx_tcam_entry * mv88e6xxx_tcam_entry_find(struct mv88e6xxx_chip *chip, unsigned long cookie) { struct mv88e6xxx_tcam_entry *entry; list_for_each_entry(entry, &chip->tcam.entries, list) if (entry->cookie == cookie) return entry; return NULL; } /* insert tcam entry in ordered list and move existing entries if necessary */ static int mv88e6xxx_tcam_insert_entry(struct mv88e6xxx_chip *chip, struct mv88e6xxx_tcam_entry *entry) { struct mv88e6xxx_tcam_entry *elem; struct list_head *hpos; int err; list_for_each_prev(hpos, &chip->tcam.entries) { u8 move_idx; elem = list_entry(hpos, struct mv88e6xxx_tcam_entry, list); if (entry->prio >= elem->prio) break; move_idx = elem->hw_idx + 1; err = mv88e6xxx_tcam_flush_entry(chip, move_idx); if (err) return err; err = chip->info->ops->tcam_ops->entry_add(chip, elem, move_idx); if (err) return err; elem->hw_idx = move_idx; } if (list_is_head(hpos, &chip->tcam.entries)) { entry->hw_idx = 0; } else { elem = list_entry(hpos, struct mv88e6xxx_tcam_entry, list); entry->hw_idx = elem->hw_idx + 1; } list_add(&entry->list, hpos); return 0; } int mv88e6xxx_tcam_entry_add(struct mv88e6xxx_chip *chip, struct mv88e6xxx_tcam_entry *entry) { int err; struct mv88e6xxx_tcam_entry *last; last = list_last_entry_or_null(&chip->tcam.entries, struct mv88e6xxx_tcam_entry, list); if (last && last->hw_idx == chip->info->num_tcam_entries - 1) return -ENOSPC; err = mv88e6xxx_tcam_insert_entry(chip, entry); if (err) return err; err = mv88e6xxx_tcam_flush_entry(chip, entry->hw_idx); if (err) goto unlink_out; err = chip->info->ops->tcam_ops->entry_add(chip, entry, entry->hw_idx); if (err) goto unlink_out; return 0; unlink_out: list_del(&entry->list); return err; } int mv88e6xxx_tcam_entry_del(struct mv88e6xxx_chip *chip, struct mv88e6xxx_tcam_entry *entry) { struct mv88e6xxx_tcam_entry *elem = entry; u8 move_idx = entry->hw_idx; int err; err = mv88e6xxx_tcam_flush_entry(chip, entry->hw_idx); if (err) return err; /* move entries that come after the deleted entry forward */ list_for_each_entry_continue(elem, &chip->tcam.entries, list) { u8 tmp_idx = elem->hw_idx; err = mv88e6xxx_tcam_flush_entry(chip, move_idx); if (err) break; err = chip->info->ops->tcam_ops->entry_add(chip, elem, move_idx); if (err) break; elem->hw_idx = move_idx; move_idx = tmp_idx; /* flush the last entry after moving entries */ if (list_is_last(&elem->list, &chip->tcam.entries)) err = mv88e6xxx_tcam_flush_entry(chip, tmp_idx); } list_del(&entry->list); kfree(entry); return err; } static int mv88e6390_tcam_entry_add(struct mv88e6xxx_chip *chip, struct mv88e6xxx_tcam_entry *entry, u8 idx) { int err = 0; int i; u16 val, spv_mask, spv; err = mv88e6xxx_tcam_read_page(chip, 2, idx); if (err) return err; if (entry->action.dpv_mode != 0) { val = MV88E6XXX_TCAM_ING_ACT3_SF | (entry->action.dpv & MV88E6XXX_TCAM_ING_ACT3_DPV_MASK); err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_ING_ACT3, val); if (err) return err; val = entry->action.dpv_mode << 14; err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_ING_ACT5, val); if (err) return err; } err = mv88e6xxx_tcam_load_page(chip, 2, idx); if (err) return err; err = mv88e6xxx_tcam_read_page(chip, 1, idx); if (err) return err; for (i = PAGE0_MATCH_SIZE; i < PAGE0_MATCH_SIZE + PAGE1_MATCH_SIZE; i++) { if (entry->key.frame_mask[i]) { val = entry->key.frame_mask[i] << 8 | entry->key.frame_data[i]; err = mv88e6xxx_tcam_write(chip, i - PAGE0_MATCH_SIZE + 2, val); if (err) return err; } } err = mv88e6xxx_tcam_load_page(chip, 1, idx); if (err) return err; err = mv88e6xxx_tcam_read_page(chip, 0, idx); if (err) return err; for (i = 0; i < PAGE0_MATCH_SIZE; i++) { if (entry->key.frame_mask[i]) { val = entry->key.frame_mask[i] << 8 | entry->key.frame_data[i]; err = mv88e6xxx_tcam_write(chip, i + 6, val); if (err) return err; } } spv_mask = entry->key.spv_mask & mv88e6xxx_port_mask(chip); spv = entry->key.spv & mv88e6xxx_port_mask(chip); /* frame type mask bits must be set for a valid entry */ val = MV88E6XXX_TCAM_KEYS1_FT_MASK | (spv_mask & MV88E6XXX_TCAM_KEYS1_SPV_MASK_MASK) | ((spv >> 8) & MV88E6XXX_TCAM_KEYS1_SPV_MASK); err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_KEYS1, val); if (err) return err; val = ((spv_mask << 8) & MV88E6XXX_TCAM_KEYS2_SPV_MASK_MASK) | (spv & MV88E6XXX_TCAM_KEYS2_SPV_MASK); err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_KEYS2, val); if (err) return err; err = mv88e6xxx_tcam_load_page(chip, 0, idx); if (err) return err; entry->hw_idx = idx; return 0; } static int mv88e6393_tcam_entry_add(struct mv88e6xxx_chip *chip, struct mv88e6xxx_tcam_entry *entry, u8 idx) { int err; /* select block 0 port 0, then adding an entry is the same as 6390 as * other blocks aren't used at the moment */ err = mv88e6xxx_tcam_write(chip, MV88E6XXX_TCAM_EXTENSION, 0x00); if (err) return err; return mv88e6390_tcam_entry_add(chip, entry, idx); } const struct mv88e6xxx_tcam_ops mv88e6390_tcam_ops = { .entry_add = mv88e6390_tcam_entry_add, .flush_tcam = mv88e6xxx_tcam_flush_all, }; const struct mv88e6xxx_tcam_ops mv88e6393_tcam_ops = { .entry_add = mv88e6393_tcam_entry_add, .flush_tcam = mv88e6xxx_tcam_flush_all, };
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1