1618 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell MCS driver3 *4 * Copyright (C) 2022 Marvell.5 */6 7#include <linux/bitfield.h>8#include <linux/delay.h>9#include <linux/device.h>10#include <linux/module.h>11#include <linux/pci.h>12 13#include "mcs.h"14#include "mcs_reg.h"15 16#define DRV_NAME "Marvell MCS Driver"17 18#define PCI_CFG_REG_BAR_NUM 019 20static const struct pci_device_id mcs_id_table[] = {21 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_MCS) },22 { 0, } /* end of table */23};24 25static LIST_HEAD(mcs_list);26 27void mcs_get_tx_secy_stats(struct mcs *mcs, struct mcs_secy_stats *stats, int id)28{29 u64 reg;30 31 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTCTLBCPKTSX(id);32 stats->ctl_pkt_bcast_cnt = mcs_reg_read(mcs, reg);33 34 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTCTLMCPKTSX(id);35 stats->ctl_pkt_mcast_cnt = mcs_reg_read(mcs, reg);36 37 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTCTLOCTETSX(id);38 stats->ctl_octet_cnt = mcs_reg_read(mcs, reg);39 40 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTCTLUCPKTSX(id);41 stats->ctl_pkt_ucast_cnt = mcs_reg_read(mcs, reg);42 43 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTUNCTLBCPKTSX(id);44 stats->unctl_pkt_bcast_cnt = mcs_reg_read(mcs, reg);45 46 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTUNCTLMCPKTSX(id);47 stats->unctl_pkt_mcast_cnt = mcs_reg_read(mcs, reg);48 49 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTUNCTLOCTETSX(id);50 stats->unctl_octet_cnt = mcs_reg_read(mcs, reg);51 52 reg = MCSX_CSE_TX_MEM_SLAVE_IFOUTUNCTLUCPKTSX(id);53 stats->unctl_pkt_ucast_cnt = mcs_reg_read(mcs, reg);54 55 reg = MCSX_CSE_TX_MEM_SLAVE_OUTOCTETSSECYENCRYPTEDX(id);56 stats->octet_encrypted_cnt = mcs_reg_read(mcs, reg);57 58 reg = MCSX_CSE_TX_MEM_SLAVE_OUTOCTETSSECYPROTECTEDX(id);59 stats->octet_protected_cnt = mcs_reg_read(mcs, reg);60 61 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSECYNOACTIVESAX(id);62 stats->pkt_noactivesa_cnt = mcs_reg_read(mcs, reg);63 64 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSECYTOOLONGX(id);65 stats->pkt_toolong_cnt = mcs_reg_read(mcs, reg);66 67 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSECYUNTAGGEDX(id);68 stats->pkt_untagged_cnt = mcs_reg_read(mcs, reg);69}70 71void mcs_get_rx_secy_stats(struct mcs *mcs, struct mcs_secy_stats *stats, int id)72{73 u64 reg;74 75 reg = MCSX_CSE_RX_MEM_SLAVE_IFINCTLBCPKTSX(id);76 stats->ctl_pkt_bcast_cnt = mcs_reg_read(mcs, reg);77 78 reg = MCSX_CSE_RX_MEM_SLAVE_IFINCTLMCPKTSX(id);79 stats->ctl_pkt_mcast_cnt = mcs_reg_read(mcs, reg);80 81 reg = MCSX_CSE_RX_MEM_SLAVE_IFINCTLOCTETSX(id);82 stats->ctl_octet_cnt = mcs_reg_read(mcs, reg);83 84 reg = MCSX_CSE_RX_MEM_SLAVE_IFINCTLUCPKTSX(id);85 stats->ctl_pkt_ucast_cnt = mcs_reg_read(mcs, reg);86 87 reg = MCSX_CSE_RX_MEM_SLAVE_IFINUNCTLBCPKTSX(id);88 stats->unctl_pkt_bcast_cnt = mcs_reg_read(mcs, reg);89 90 reg = MCSX_CSE_RX_MEM_SLAVE_IFINUNCTLMCPKTSX(id);91 stats->unctl_pkt_mcast_cnt = mcs_reg_read(mcs, reg);92 93 reg = MCSX_CSE_RX_MEM_SLAVE_IFINUNCTLOCTETSX(id);94 stats->unctl_octet_cnt = mcs_reg_read(mcs, reg);95 96 reg = MCSX_CSE_RX_MEM_SLAVE_IFINUNCTLUCPKTSX(id);97 stats->unctl_pkt_ucast_cnt = mcs_reg_read(mcs, reg);98 99 reg = MCSX_CSE_RX_MEM_SLAVE_INOCTETSSECYDECRYPTEDX(id);100 stats->octet_decrypted_cnt = mcs_reg_read(mcs, reg);101 102 reg = MCSX_CSE_RX_MEM_SLAVE_INOCTETSSECYVALIDATEX(id);103 stats->octet_validated_cnt = mcs_reg_read(mcs, reg);104 105 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSCTRLPORTDISABLEDX(id);106 stats->pkt_port_disabled_cnt = mcs_reg_read(mcs, reg);107 108 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYBADTAGX(id);109 stats->pkt_badtag_cnt = mcs_reg_read(mcs, reg);110 111 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYNOSAX(id);112 stats->pkt_nosa_cnt = mcs_reg_read(mcs, reg);113 114 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYNOSAERRORX(id);115 stats->pkt_nosaerror_cnt = mcs_reg_read(mcs, reg);116 117 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYTAGGEDCTLX(id);118 stats->pkt_tagged_ctl_cnt = mcs_reg_read(mcs, reg);119 120 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYUNTAGGEDX(id);121 stats->pkt_untaged_cnt = mcs_reg_read(mcs, reg);122 123 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYCTLX(id);124 stats->pkt_ctl_cnt = mcs_reg_read(mcs, reg);125 126 if (mcs->hw->mcs_blks > 1) {127 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYNOTAGX(id);128 stats->pkt_notag_cnt = mcs_reg_read(mcs, reg);129 }130}131 132void mcs_get_flowid_stats(struct mcs *mcs, struct mcs_flowid_stats *stats,133 int id, int dir)134{135 u64 reg;136 137 if (dir == MCS_RX)138 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSFLOWIDTCAMHITX(id);139 else140 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSFLOWIDTCAMHITX(id);141 142 stats->tcam_hit_cnt = mcs_reg_read(mcs, reg);143}144 145void mcs_get_port_stats(struct mcs *mcs, struct mcs_port_stats *stats,146 int id, int dir)147{148 u64 reg;149 150 if (dir == MCS_RX) {151 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSFLOWIDTCAMMISSX(id);152 stats->tcam_miss_cnt = mcs_reg_read(mcs, reg);153 154 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSPARSEERRX(id);155 stats->parser_err_cnt = mcs_reg_read(mcs, reg);156 if (mcs->hw->mcs_blks > 1) {157 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSEARLYPREEMPTERRX(id);158 stats->preempt_err_cnt = mcs_reg_read(mcs, reg);159 }160 } else {161 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSFLOWIDTCAMMISSX(id);162 stats->tcam_miss_cnt = mcs_reg_read(mcs, reg);163 164 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSPARSEERRX(id);165 stats->parser_err_cnt = mcs_reg_read(mcs, reg);166 167 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSECTAGINSERTIONERRX(id);168 stats->sectag_insert_err_cnt = mcs_reg_read(mcs, reg);169 }170}171 172void mcs_get_sa_stats(struct mcs *mcs, struct mcs_sa_stats *stats, int id, int dir)173{174 u64 reg;175 176 if (dir == MCS_RX) {177 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSAINVALIDX(id);178 stats->pkt_invalid_cnt = mcs_reg_read(mcs, reg);179 180 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSANOTUSINGSAERRORX(id);181 stats->pkt_nosaerror_cnt = mcs_reg_read(mcs, reg);182 183 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSANOTVALIDX(id);184 stats->pkt_notvalid_cnt = mcs_reg_read(mcs, reg);185 186 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSAOKX(id);187 stats->pkt_ok_cnt = mcs_reg_read(mcs, reg);188 189 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSAUNUSEDSAX(id);190 stats->pkt_nosa_cnt = mcs_reg_read(mcs, reg);191 } else {192 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSAENCRYPTEDX(id);193 stats->pkt_encrypt_cnt = mcs_reg_read(mcs, reg);194 195 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSAPROTECTEDX(id);196 stats->pkt_protected_cnt = mcs_reg_read(mcs, reg);197 }198}199 200void mcs_get_sc_stats(struct mcs *mcs, struct mcs_sc_stats *stats,201 int id, int dir)202{203 u64 reg;204 205 if (dir == MCS_RX) {206 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSCCAMHITX(id);207 stats->hit_cnt = mcs_reg_read(mcs, reg);208 209 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSCINVALIDX(id);210 stats->pkt_invalid_cnt = mcs_reg_read(mcs, reg);211 212 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSCLATEORDELAYEDX(id);213 stats->pkt_late_cnt = mcs_reg_read(mcs, reg);214 215 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSCNOTVALIDX(id);216 stats->pkt_notvalid_cnt = mcs_reg_read(mcs, reg);217 218 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSCUNCHECKEDX(id);219 stats->pkt_unchecked_cnt = mcs_reg_read(mcs, reg);220 221 if (mcs->hw->mcs_blks > 1) {222 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSCDELAYEDX(id);223 stats->pkt_delay_cnt = mcs_reg_read(mcs, reg);224 225 reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSCOKX(id);226 stats->pkt_ok_cnt = mcs_reg_read(mcs, reg);227 }228 if (mcs->hw->mcs_blks == 1) {229 reg = MCSX_CSE_RX_MEM_SLAVE_INOCTETSSCDECRYPTEDX(id);230 stats->octet_decrypt_cnt = mcs_reg_read(mcs, reg);231 232 reg = MCSX_CSE_RX_MEM_SLAVE_INOCTETSSCVALIDATEX(id);233 stats->octet_validate_cnt = mcs_reg_read(mcs, reg);234 }235 } else {236 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSCENCRYPTEDX(id);237 stats->pkt_encrypt_cnt = mcs_reg_read(mcs, reg);238 239 reg = MCSX_CSE_TX_MEM_SLAVE_OUTPKTSSCPROTECTEDX(id);240 stats->pkt_protected_cnt = mcs_reg_read(mcs, reg);241 242 if (mcs->hw->mcs_blks == 1) {243 reg = MCSX_CSE_TX_MEM_SLAVE_OUTOCTETSSCENCRYPTEDX(id);244 stats->octet_encrypt_cnt = mcs_reg_read(mcs, reg);245 246 reg = MCSX_CSE_TX_MEM_SLAVE_OUTOCTETSSCPROTECTEDX(id);247 stats->octet_protected_cnt = mcs_reg_read(mcs, reg);248 }249 }250}251 252void mcs_clear_stats(struct mcs *mcs, u8 type, u8 id, int dir)253{254 struct mcs_flowid_stats flowid_st;255 struct mcs_port_stats port_st;256 struct mcs_secy_stats secy_st;257 struct mcs_sc_stats sc_st;258 struct mcs_sa_stats sa_st;259 u64 reg;260 261 if (dir == MCS_RX)262 reg = MCSX_CSE_RX_SLAVE_CTRL;263 else264 reg = MCSX_CSE_TX_SLAVE_CTRL;265 266 mcs_reg_write(mcs, reg, BIT_ULL(0));267 268 switch (type) {269 case MCS_FLOWID_STATS:270 mcs_get_flowid_stats(mcs, &flowid_st, id, dir);271 break;272 case MCS_SECY_STATS:273 if (dir == MCS_RX)274 mcs_get_rx_secy_stats(mcs, &secy_st, id);275 else276 mcs_get_tx_secy_stats(mcs, &secy_st, id);277 break;278 case MCS_SC_STATS:279 mcs_get_sc_stats(mcs, &sc_st, id, dir);280 break;281 case MCS_SA_STATS:282 mcs_get_sa_stats(mcs, &sa_st, id, dir);283 break;284 case MCS_PORT_STATS:285 mcs_get_port_stats(mcs, &port_st, id, dir);286 break;287 }288 289 mcs_reg_write(mcs, reg, 0x0);290}291 292int mcs_clear_all_stats(struct mcs *mcs, u16 pcifunc, int dir)293{294 struct mcs_rsrc_map *map;295 int id;296 297 if (dir == MCS_RX)298 map = &mcs->rx;299 else300 map = &mcs->tx;301 302 /* Clear FLOWID stats */303 for (id = 0; id < map->flow_ids.max; id++) {304 if (map->flowid2pf_map[id] != pcifunc)305 continue;306 mcs_clear_stats(mcs, MCS_FLOWID_STATS, id, dir);307 }308 309 /* Clear SECY stats */310 for (id = 0; id < map->secy.max; id++) {311 if (map->secy2pf_map[id] != pcifunc)312 continue;313 mcs_clear_stats(mcs, MCS_SECY_STATS, id, dir);314 }315 316 /* Clear SC stats */317 for (id = 0; id < map->secy.max; id++) {318 if (map->sc2pf_map[id] != pcifunc)319 continue;320 mcs_clear_stats(mcs, MCS_SC_STATS, id, dir);321 }322 323 /* Clear SA stats */324 for (id = 0; id < map->sa.max; id++) {325 if (map->sa2pf_map[id] != pcifunc)326 continue;327 mcs_clear_stats(mcs, MCS_SA_STATS, id, dir);328 }329 return 0;330}331 332void mcs_pn_table_write(struct mcs *mcs, u8 pn_id, u64 next_pn, u8 dir)333{334 u64 reg;335 336 if (dir == MCS_RX)337 reg = MCSX_CPM_RX_SLAVE_SA_PN_TABLE_MEMX(pn_id);338 else339 reg = MCSX_CPM_TX_SLAVE_SA_PN_TABLE_MEMX(pn_id);340 mcs_reg_write(mcs, reg, next_pn);341}342 343void cn10kb_mcs_tx_sa_mem_map_write(struct mcs *mcs, struct mcs_tx_sc_sa_map *map)344{345 u64 reg, val;346 347 val = (map->sa_index0 & 0xFF) |348 (map->sa_index1 & 0xFF) << 9 |349 (map->rekey_ena & 0x1) << 18 |350 (map->sa_index0_vld & 0x1) << 19 |351 (map->sa_index1_vld & 0x1) << 20 |352 (map->tx_sa_active & 0x1) << 21 |353 map->sectag_sci << 22;354 reg = MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(map->sc_id);355 mcs_reg_write(mcs, reg, val);356 357 val = map->sectag_sci >> 42;358 reg = MCSX_CPM_TX_SLAVE_SA_MAP_MEM_1X(map->sc_id);359 mcs_reg_write(mcs, reg, val);360}361 362void cn10kb_mcs_rx_sa_mem_map_write(struct mcs *mcs, struct mcs_rx_sc_sa_map *map)363{364 u64 val, reg;365 366 val = (map->sa_index & 0xFF) | map->sa_in_use << 9;367 368 reg = MCSX_CPM_RX_SLAVE_SA_MAP_MEMX((4 * map->sc_id) + map->an);369 mcs_reg_write(mcs, reg, val);370}371 372void mcs_sa_plcy_write(struct mcs *mcs, u64 *plcy, int sa_id, int dir)373{374 int reg_id;375 u64 reg;376 377 if (dir == MCS_RX) {378 for (reg_id = 0; reg_id < 8; reg_id++) {379 reg = MCSX_CPM_RX_SLAVE_SA_PLCY_MEMX(reg_id, sa_id);380 mcs_reg_write(mcs, reg, plcy[reg_id]);381 }382 } else {383 for (reg_id = 0; reg_id < 9; reg_id++) {384 reg = MCSX_CPM_TX_SLAVE_SA_PLCY_MEMX(reg_id, sa_id);385 mcs_reg_write(mcs, reg, plcy[reg_id]);386 }387 }388}389 390void mcs_ena_dis_sc_cam_entry(struct mcs *mcs, int sc_id, int ena)391{392 u64 reg, val;393 394 reg = MCSX_CPM_RX_SLAVE_SC_CAM_ENA(0);395 if (sc_id > 63)396 reg = MCSX_CPM_RX_SLAVE_SC_CAM_ENA(1);397 398 if (ena)399 val = mcs_reg_read(mcs, reg) | BIT_ULL(sc_id);400 else401 val = mcs_reg_read(mcs, reg) & ~BIT_ULL(sc_id);402 403 mcs_reg_write(mcs, reg, val);404}405 406void mcs_rx_sc_cam_write(struct mcs *mcs, u64 sci, u64 secy, int sc_id)407{408 mcs_reg_write(mcs, MCSX_CPM_RX_SLAVE_SC_CAMX(0, sc_id), sci);409 mcs_reg_write(mcs, MCSX_CPM_RX_SLAVE_SC_CAMX(1, sc_id), secy);410 /* Enable SC CAM */411 mcs_ena_dis_sc_cam_entry(mcs, sc_id, true);412}413 414void mcs_secy_plcy_write(struct mcs *mcs, u64 plcy, int secy_id, int dir)415{416 u64 reg;417 418 if (dir == MCS_RX)419 reg = MCSX_CPM_RX_SLAVE_SECY_PLCY_MEM_0X(secy_id);420 else421 reg = MCSX_CPM_TX_SLAVE_SECY_PLCY_MEMX(secy_id);422 423 mcs_reg_write(mcs, reg, plcy);424 425 if (mcs->hw->mcs_blks == 1 && dir == MCS_RX)426 mcs_reg_write(mcs, MCSX_CPM_RX_SLAVE_SECY_PLCY_MEM_1X(secy_id), 0x0ull);427}428 429void cn10kb_mcs_flowid_secy_map(struct mcs *mcs, struct secy_mem_map *map, int dir)430{431 u64 reg, val;432 433 val = (map->secy & 0x7F) | (map->ctrl_pkt & 0x1) << 8;434 if (dir == MCS_RX) {435 reg = MCSX_CPM_RX_SLAVE_SECY_MAP_MEMX(map->flow_id);436 } else {437 val |= (map->sc & 0x7F) << 9;438 reg = MCSX_CPM_TX_SLAVE_SECY_MAP_MEM_0X(map->flow_id);439 }440 441 mcs_reg_write(mcs, reg, val);442}443 444void mcs_ena_dis_flowid_entry(struct mcs *mcs, int flow_id, int dir, int ena)445{446 u64 reg, val;447 448 if (dir == MCS_RX) {449 reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_ENA_0;450 if (flow_id > 63)451 reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_ENA_1;452 } else {453 reg = MCSX_CPM_TX_SLAVE_FLOWID_TCAM_ENA_0;454 if (flow_id > 63)455 reg = MCSX_CPM_TX_SLAVE_FLOWID_TCAM_ENA_1;456 }457 458 /* Enable/Disable the tcam entry */459 if (ena)460 val = mcs_reg_read(mcs, reg) | BIT_ULL(flow_id);461 else462 val = mcs_reg_read(mcs, reg) & ~BIT_ULL(flow_id);463 464 mcs_reg_write(mcs, reg, val);465}466 467void mcs_flowid_entry_write(struct mcs *mcs, u64 *data, u64 *mask, int flow_id, int dir)468{469 int reg_id;470 u64 reg;471 472 if (dir == MCS_RX) {473 for (reg_id = 0; reg_id < 4; reg_id++) {474 reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_DATAX(reg_id, flow_id);475 mcs_reg_write(mcs, reg, data[reg_id]);476 }477 for (reg_id = 0; reg_id < 4; reg_id++) {478 reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_MASKX(reg_id, flow_id);479 mcs_reg_write(mcs, reg, mask[reg_id]);480 }481 } else {482 for (reg_id = 0; reg_id < 4; reg_id++) {483 reg = MCSX_CPM_TX_SLAVE_FLOWID_TCAM_DATAX(reg_id, flow_id);484 mcs_reg_write(mcs, reg, data[reg_id]);485 }486 for (reg_id = 0; reg_id < 4; reg_id++) {487 reg = MCSX_CPM_TX_SLAVE_FLOWID_TCAM_MASKX(reg_id, flow_id);488 mcs_reg_write(mcs, reg, mask[reg_id]);489 }490 }491}492 493int mcs_install_flowid_bypass_entry(struct mcs *mcs)494{495 int flow_id, secy_id, reg_id;496 struct secy_mem_map map;497 u64 reg, plcy = 0;498 499 /* Flow entry */500 flow_id = mcs->hw->tcam_entries - MCS_RSRC_RSVD_CNT;501 __set_bit(flow_id, mcs->rx.flow_ids.bmap);502 __set_bit(flow_id, mcs->tx.flow_ids.bmap);503 504 for (reg_id = 0; reg_id < 4; reg_id++) {505 reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_MASKX(reg_id, flow_id);506 mcs_reg_write(mcs, reg, GENMASK_ULL(63, 0));507 }508 for (reg_id = 0; reg_id < 4; reg_id++) {509 reg = MCSX_CPM_TX_SLAVE_FLOWID_TCAM_MASKX(reg_id, flow_id);510 mcs_reg_write(mcs, reg, GENMASK_ULL(63, 0));511 }512 /* secy */513 secy_id = mcs->hw->secy_entries - MCS_RSRC_RSVD_CNT;514 __set_bit(secy_id, mcs->rx.secy.bmap);515 __set_bit(secy_id, mcs->tx.secy.bmap);516 517 /* Set validate frames to NULL and enable control port */518 plcy = 0x7ull;519 if (mcs->hw->mcs_blks > 1)520 plcy = BIT_ULL(0) | 0x3ull << 4;521 mcs_secy_plcy_write(mcs, plcy, secy_id, MCS_RX);522 523 /* Enable control port and set mtu to max */524 plcy = BIT_ULL(0) | GENMASK_ULL(43, 28);525 if (mcs->hw->mcs_blks > 1)526 plcy = BIT_ULL(0) | GENMASK_ULL(63, 48);527 mcs_secy_plcy_write(mcs, plcy, secy_id, MCS_TX);528 529 /* Map flowid to secy */530 map.secy = secy_id;531 map.ctrl_pkt = 0;532 map.flow_id = flow_id;533 mcs->mcs_ops->mcs_flowid_secy_map(mcs, &map, MCS_RX);534 map.sc = secy_id;535 mcs->mcs_ops->mcs_flowid_secy_map(mcs, &map, MCS_TX);536 537 /* Enable Flowid entry */538 mcs_ena_dis_flowid_entry(mcs, flow_id, MCS_RX, true);539 mcs_ena_dis_flowid_entry(mcs, flow_id, MCS_TX, true);540 541 return 0;542}543 544void mcs_clear_secy_plcy(struct mcs *mcs, int secy_id, int dir)545{546 struct mcs_rsrc_map *map;547 int flow_id;548 549 if (dir == MCS_RX)550 map = &mcs->rx;551 else552 map = &mcs->tx;553 554 /* Clear secy memory to zero */555 mcs_secy_plcy_write(mcs, 0, secy_id, dir);556 557 /* Disable the tcam entry using this secy */558 for (flow_id = 0; flow_id < map->flow_ids.max; flow_id++) {559 if (map->flowid2secy_map[flow_id] != secy_id)560 continue;561 mcs_ena_dis_flowid_entry(mcs, flow_id, dir, false);562 }563}564 565int mcs_alloc_ctrlpktrule(struct rsrc_bmap *rsrc, u16 *pf_map, u16 offset, u16 pcifunc)566{567 int rsrc_id;568 569 if (!rsrc->bmap)570 return -EINVAL;571 572 rsrc_id = bitmap_find_next_zero_area(rsrc->bmap, rsrc->max, offset, 1, 0);573 if (rsrc_id >= rsrc->max)574 return -ENOSPC;575 576 bitmap_set(rsrc->bmap, rsrc_id, 1);577 pf_map[rsrc_id] = pcifunc;578 579 return rsrc_id;580}581 582int mcs_free_ctrlpktrule(struct mcs *mcs, struct mcs_free_ctrl_pkt_rule_req *req)583{584 u16 pcifunc = req->hdr.pcifunc;585 struct mcs_rsrc_map *map;586 u64 dis, reg;587 int id, rc;588 589 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_RULE_ENABLE : MCSX_PEX_TX_SLAVE_RULE_ENABLE;590 map = (req->dir == MCS_RX) ? &mcs->rx : &mcs->tx;591 592 if (req->all) {593 for (id = 0; id < map->ctrlpktrule.max; id++) {594 if (map->ctrlpktrule2pf_map[id] != pcifunc)595 continue;596 mcs_free_rsrc(&map->ctrlpktrule, map->ctrlpktrule2pf_map, id, pcifunc);597 dis = mcs_reg_read(mcs, reg);598 dis &= ~BIT_ULL(id);599 mcs_reg_write(mcs, reg, dis);600 }601 return 0;602 }603 604 rc = mcs_free_rsrc(&map->ctrlpktrule, map->ctrlpktrule2pf_map, req->rule_idx, pcifunc);605 dis = mcs_reg_read(mcs, reg);606 dis &= ~BIT_ULL(req->rule_idx);607 mcs_reg_write(mcs, reg, dis);608 609 return rc;610}611 612int mcs_ctrlpktrule_write(struct mcs *mcs, struct mcs_ctrl_pkt_rule_write_req *req)613{614 u64 reg, enb;615 u64 idx;616 617 switch (req->rule_type) {618 case MCS_CTRL_PKT_RULE_TYPE_ETH:619 req->data0 &= GENMASK(15, 0);620 if (req->data0 != ETH_P_PAE)621 return -EINVAL;622 623 idx = req->rule_idx - MCS_CTRLPKT_ETYPE_RULE_OFFSET;624 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_RULE_ETYPE_CFGX(idx) :625 MCSX_PEX_TX_SLAVE_RULE_ETYPE_CFGX(idx);626 627 mcs_reg_write(mcs, reg, req->data0);628 break;629 case MCS_CTRL_PKT_RULE_TYPE_DA:630 if (!(req->data0 & BIT_ULL(40)))631 return -EINVAL;632 633 idx = req->rule_idx - MCS_CTRLPKT_DA_RULE_OFFSET;634 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_RULE_DAX(idx) :635 MCSX_PEX_TX_SLAVE_RULE_DAX(idx);636 637 mcs_reg_write(mcs, reg, req->data0 & GENMASK_ULL(47, 0));638 break;639 case MCS_CTRL_PKT_RULE_TYPE_RANGE:640 if (!(req->data0 & BIT_ULL(40)) || !(req->data1 & BIT_ULL(40)))641 return -EINVAL;642 643 idx = req->rule_idx - MCS_CTRLPKT_DA_RANGE_RULE_OFFSET;644 if (req->dir == MCS_RX) {645 reg = MCSX_PEX_RX_SLAVE_RULE_DA_RANGE_MINX(idx);646 mcs_reg_write(mcs, reg, req->data0 & GENMASK_ULL(47, 0));647 reg = MCSX_PEX_RX_SLAVE_RULE_DA_RANGE_MAXX(idx);648 mcs_reg_write(mcs, reg, req->data1 & GENMASK_ULL(47, 0));649 } else {650 reg = MCSX_PEX_TX_SLAVE_RULE_DA_RANGE_MINX(idx);651 mcs_reg_write(mcs, reg, req->data0 & GENMASK_ULL(47, 0));652 reg = MCSX_PEX_TX_SLAVE_RULE_DA_RANGE_MAXX(idx);653 mcs_reg_write(mcs, reg, req->data1 & GENMASK_ULL(47, 0));654 }655 break;656 case MCS_CTRL_PKT_RULE_TYPE_COMBO:657 req->data2 &= GENMASK(15, 0);658 if (req->data2 != ETH_P_PAE || !(req->data0 & BIT_ULL(40)) ||659 !(req->data1 & BIT_ULL(40)))660 return -EINVAL;661 662 idx = req->rule_idx - MCS_CTRLPKT_COMBO_RULE_OFFSET;663 if (req->dir == MCS_RX) {664 reg = MCSX_PEX_RX_SLAVE_RULE_COMBO_MINX(idx);665 mcs_reg_write(mcs, reg, req->data0 & GENMASK_ULL(47, 0));666 reg = MCSX_PEX_RX_SLAVE_RULE_COMBO_MAXX(idx);667 mcs_reg_write(mcs, reg, req->data1 & GENMASK_ULL(47, 0));668 reg = MCSX_PEX_RX_SLAVE_RULE_COMBO_ETX(idx);669 mcs_reg_write(mcs, reg, req->data2);670 } else {671 reg = MCSX_PEX_TX_SLAVE_RULE_COMBO_MINX(idx);672 mcs_reg_write(mcs, reg, req->data0 & GENMASK_ULL(47, 0));673 reg = MCSX_PEX_TX_SLAVE_RULE_COMBO_MAXX(idx);674 mcs_reg_write(mcs, reg, req->data1 & GENMASK_ULL(47, 0));675 reg = MCSX_PEX_TX_SLAVE_RULE_COMBO_ETX(idx);676 mcs_reg_write(mcs, reg, req->data2);677 }678 break;679 case MCS_CTRL_PKT_RULE_TYPE_MAC:680 if (!(req->data0 & BIT_ULL(40)))681 return -EINVAL;682 683 idx = req->rule_idx - MCS_CTRLPKT_MAC_EN_RULE_OFFSET;684 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_RULE_MAC :685 MCSX_PEX_TX_SLAVE_RULE_MAC;686 687 mcs_reg_write(mcs, reg, req->data0 & GENMASK_ULL(47, 0));688 break;689 }690 691 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_RULE_ENABLE : MCSX_PEX_TX_SLAVE_RULE_ENABLE;692 693 enb = mcs_reg_read(mcs, reg);694 enb |= BIT_ULL(req->rule_idx);695 mcs_reg_write(mcs, reg, enb);696 697 return 0;698}699 700int mcs_free_rsrc(struct rsrc_bmap *rsrc, u16 *pf_map, int rsrc_id, u16 pcifunc)701{702 /* Check if the rsrc_id is mapped to PF/VF */703 if (pf_map[rsrc_id] != pcifunc)704 return -EINVAL;705 706 rvu_free_rsrc(rsrc, rsrc_id);707 pf_map[rsrc_id] = 0;708 return 0;709}710 711/* Free all the cam resources mapped to pf */712int mcs_free_all_rsrc(struct mcs *mcs, int dir, u16 pcifunc)713{714 struct mcs_rsrc_map *map;715 int id;716 717 if (dir == MCS_RX)718 map = &mcs->rx;719 else720 map = &mcs->tx;721 722 /* free tcam entries */723 for (id = 0; id < map->flow_ids.max; id++) {724 if (map->flowid2pf_map[id] != pcifunc)725 continue;726 mcs_free_rsrc(&map->flow_ids, map->flowid2pf_map,727 id, pcifunc);728 mcs_ena_dis_flowid_entry(mcs, id, dir, false);729 }730 731 /* free secy entries */732 for (id = 0; id < map->secy.max; id++) {733 if (map->secy2pf_map[id] != pcifunc)734 continue;735 mcs_free_rsrc(&map->secy, map->secy2pf_map,736 id, pcifunc);737 mcs_clear_secy_plcy(mcs, id, dir);738 }739 740 /* free sc entries */741 for (id = 0; id < map->secy.max; id++) {742 if (map->sc2pf_map[id] != pcifunc)743 continue;744 mcs_free_rsrc(&map->sc, map->sc2pf_map, id, pcifunc);745 746 /* Disable SC CAM only on RX side */747 if (dir == MCS_RX)748 mcs_ena_dis_sc_cam_entry(mcs, id, false);749 }750 751 /* free sa entries */752 for (id = 0; id < map->sa.max; id++) {753 if (map->sa2pf_map[id] != pcifunc)754 continue;755 mcs_free_rsrc(&map->sa, map->sa2pf_map, id, pcifunc);756 }757 return 0;758}759 760int mcs_alloc_rsrc(struct rsrc_bmap *rsrc, u16 *pf_map, u16 pcifunc)761{762 int rsrc_id;763 764 rsrc_id = rvu_alloc_rsrc(rsrc);765 if (rsrc_id < 0)766 return -ENOMEM;767 pf_map[rsrc_id] = pcifunc;768 return rsrc_id;769}770 771int mcs_alloc_all_rsrc(struct mcs *mcs, u8 *flow_id, u8 *secy_id,772 u8 *sc_id, u8 *sa1_id, u8 *sa2_id, u16 pcifunc, int dir)773{774 struct mcs_rsrc_map *map;775 int id;776 777 if (dir == MCS_RX)778 map = &mcs->rx;779 else780 map = &mcs->tx;781 782 id = mcs_alloc_rsrc(&map->flow_ids, map->flowid2pf_map, pcifunc);783 if (id < 0)784 return -ENOMEM;785 *flow_id = id;786 787 id = mcs_alloc_rsrc(&map->secy, map->secy2pf_map, pcifunc);788 if (id < 0)789 return -ENOMEM;790 *secy_id = id;791 792 id = mcs_alloc_rsrc(&map->sc, map->sc2pf_map, pcifunc);793 if (id < 0)794 return -ENOMEM;795 *sc_id = id;796 797 id = mcs_alloc_rsrc(&map->sa, map->sa2pf_map, pcifunc);798 if (id < 0)799 return -ENOMEM;800 *sa1_id = id;801 802 id = mcs_alloc_rsrc(&map->sa, map->sa2pf_map, pcifunc);803 if (id < 0)804 return -ENOMEM;805 *sa2_id = id;806 807 return 0;808}809 810static void cn10kb_mcs_tx_pn_wrapped_handler(struct mcs *mcs)811{812 struct mcs_intr_event event = { 0 };813 struct rsrc_bmap *sc_bmap;814 u64 val;815 int sc;816 817 sc_bmap = &mcs->tx.sc;818 819 event.mcs_id = mcs->mcs_id;820 event.intr_mask = MCS_CPM_TX_PACKET_XPN_EQ0_INT;821 822 for_each_set_bit(sc, sc_bmap->bmap, mcs->hw->sc_entries) {823 val = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(sc));824 825 if (mcs->tx_sa_active[sc])826 /* SA_index1 was used and got expired */827 event.sa_id = (val >> 9) & 0xFF;828 else829 /* SA_index0 was used and got expired */830 event.sa_id = val & 0xFF;831 832 event.pcifunc = mcs->tx.sa2pf_map[event.sa_id];833 mcs_add_intr_wq_entry(mcs, &event);834 }835}836 837static void cn10kb_mcs_tx_pn_thresh_reached_handler(struct mcs *mcs)838{839 struct mcs_intr_event event = { 0 };840 struct rsrc_bmap *sc_bmap;841 u64 val, status;842 int sc;843 844 sc_bmap = &mcs->tx.sc;845 846 event.mcs_id = mcs->mcs_id;847 event.intr_mask = MCS_CPM_TX_PN_THRESH_REACHED_INT;848 849 /* TX SA interrupt is raised only if autorekey is enabled.850 * MCS_CPM_TX_SLAVE_SA_MAP_MEM_0X[sc].tx_sa_active bit gets toggled if851 * one of two SAs mapped to SC gets expired. If tx_sa_active=0 implies852 * SA in SA_index1 got expired else SA in SA_index0 got expired.853 */854 for_each_set_bit(sc, sc_bmap->bmap, mcs->hw->sc_entries) {855 val = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(sc));856 /* Auto rekey is enable */857 if (!((val >> 18) & 0x1))858 continue;859 860 status = (val >> 21) & 0x1;861 862 /* Check if tx_sa_active status had changed */863 if (status == mcs->tx_sa_active[sc])864 continue;865 /* SA_index0 is expired */866 if (status)867 event.sa_id = val & 0xFF;868 else869 event.sa_id = (val >> 9) & 0xFF;870 871 event.pcifunc = mcs->tx.sa2pf_map[event.sa_id];872 mcs_add_intr_wq_entry(mcs, &event);873 }874}875 876static void mcs_rx_pn_thresh_reached_handler(struct mcs *mcs)877{878 struct mcs_intr_event event = { 0 };879 int sa, reg;880 u64 intr;881 882 /* Check expired SAs */883 for (reg = 0; reg < (mcs->hw->sa_entries / 64); reg++) {884 /* Bit high in *PN_THRESH_REACHEDX implies885 * corresponding SAs are expired.886 */887 intr = mcs_reg_read(mcs, MCSX_CPM_RX_SLAVE_PN_THRESH_REACHEDX(reg));888 for (sa = 0; sa < 64; sa++) {889 if (!(intr & BIT_ULL(sa)))890 continue;891 892 event.mcs_id = mcs->mcs_id;893 event.intr_mask = MCS_CPM_RX_PN_THRESH_REACHED_INT;894 event.sa_id = sa + (reg * 64);895 event.pcifunc = mcs->rx.sa2pf_map[event.sa_id];896 mcs_add_intr_wq_entry(mcs, &event);897 }898 }899}900 901static void mcs_rx_misc_intr_handler(struct mcs *mcs, u64 intr)902{903 struct mcs_intr_event event = { 0 };904 905 event.mcs_id = mcs->mcs_id;906 event.pcifunc = mcs->pf_map[0];907 908 if (intr & MCS_CPM_RX_INT_SECTAG_V_EQ1)909 event.intr_mask = MCS_CPM_RX_SECTAG_V_EQ1_INT;910 if (intr & MCS_CPM_RX_INT_SECTAG_E_EQ0_C_EQ1)911 event.intr_mask |= MCS_CPM_RX_SECTAG_E_EQ0_C_EQ1_INT;912 if (intr & MCS_CPM_RX_INT_SL_GTE48)913 event.intr_mask |= MCS_CPM_RX_SECTAG_SL_GTE48_INT;914 if (intr & MCS_CPM_RX_INT_ES_EQ1_SC_EQ1)915 event.intr_mask |= MCS_CPM_RX_SECTAG_ES_EQ1_SC_EQ1_INT;916 if (intr & MCS_CPM_RX_INT_SC_EQ1_SCB_EQ1)917 event.intr_mask |= MCS_CPM_RX_SECTAG_SC_EQ1_SCB_EQ1_INT;918 if (intr & MCS_CPM_RX_INT_PACKET_XPN_EQ0)919 event.intr_mask |= MCS_CPM_RX_PACKET_XPN_EQ0_INT;920 921 mcs_add_intr_wq_entry(mcs, &event);922}923 924static void mcs_tx_misc_intr_handler(struct mcs *mcs, u64 intr)925{926 struct mcs_intr_event event = { 0 };927 928 if (!(intr & MCS_CPM_TX_INT_SA_NOT_VALID))929 return;930 931 event.mcs_id = mcs->mcs_id;932 event.pcifunc = mcs->pf_map[0];933 934 event.intr_mask = MCS_CPM_TX_SA_NOT_VALID_INT;935 936 mcs_add_intr_wq_entry(mcs, &event);937}938 939void cn10kb_mcs_bbe_intr_handler(struct mcs *mcs, u64 intr,940 enum mcs_direction dir)941{942 u64 val, reg;943 int lmac;944 945 if (!(intr & 0x6ULL))946 return;947 948 if (intr & BIT_ULL(1))949 reg = (dir == MCS_RX) ? MCSX_BBE_RX_SLAVE_DFIFO_OVERFLOW_0 :950 MCSX_BBE_TX_SLAVE_DFIFO_OVERFLOW_0;951 else952 reg = (dir == MCS_RX) ? MCSX_BBE_RX_SLAVE_PLFIFO_OVERFLOW_0 :953 MCSX_BBE_TX_SLAVE_PLFIFO_OVERFLOW_0;954 val = mcs_reg_read(mcs, reg);955 956 /* policy/data over flow occurred */957 for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++) {958 if (!(val & BIT_ULL(lmac)))959 continue;960 dev_warn(mcs->dev, "BEE:Policy or data overflow occurred on lmac:%d\n", lmac);961 }962}963 964void cn10kb_mcs_pab_intr_handler(struct mcs *mcs, u64 intr,965 enum mcs_direction dir)966{967 int lmac;968 969 if (!(intr & 0xFFFFFULL))970 return;971 972 for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++) {973 if (intr & BIT_ULL(lmac))974 dev_warn(mcs->dev, "PAB: overflow occurred on lmac:%d\n", lmac);975 }976}977 978static irqreturn_t mcs_ip_intr_handler(int irq, void *mcs_irq)979{980 struct mcs *mcs = (struct mcs *)mcs_irq;981 u64 intr, cpm_intr, bbe_intr, pab_intr;982 983 /* Disable the interrupt */984 mcs_reg_write(mcs, MCSX_IP_INT_ENA_W1C, BIT_ULL(0));985 986 /* Check which block has interrupt*/987 intr = mcs_reg_read(mcs, MCSX_TOP_SLAVE_INT_SUM);988 989 /* CPM RX */990 if (intr & MCS_CPM_RX_INT_ENA) {991 /* Check for PN thresh interrupt bit */992 cpm_intr = mcs_reg_read(mcs, MCSX_CPM_RX_SLAVE_RX_INT);993 994 if (cpm_intr & MCS_CPM_RX_INT_PN_THRESH_REACHED)995 mcs_rx_pn_thresh_reached_handler(mcs);996 997 if (cpm_intr & MCS_CPM_RX_INT_ALL)998 mcs_rx_misc_intr_handler(mcs, cpm_intr);999 1000 /* Clear the interrupt */1001 mcs_reg_write(mcs, MCSX_CPM_RX_SLAVE_RX_INT, cpm_intr);1002 }1003 1004 /* CPM TX */1005 if (intr & MCS_CPM_TX_INT_ENA) {1006 cpm_intr = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_TX_INT);1007 1008 if (cpm_intr & MCS_CPM_TX_INT_PN_THRESH_REACHED) {1009 if (mcs->hw->mcs_blks > 1)1010 cnf10kb_mcs_tx_pn_thresh_reached_handler(mcs);1011 else1012 cn10kb_mcs_tx_pn_thresh_reached_handler(mcs);1013 }1014 1015 if (cpm_intr & MCS_CPM_TX_INT_SA_NOT_VALID)1016 mcs_tx_misc_intr_handler(mcs, cpm_intr);1017 1018 if (cpm_intr & MCS_CPM_TX_INT_PACKET_XPN_EQ0) {1019 if (mcs->hw->mcs_blks > 1)1020 cnf10kb_mcs_tx_pn_wrapped_handler(mcs);1021 else1022 cn10kb_mcs_tx_pn_wrapped_handler(mcs);1023 }1024 /* Clear the interrupt */1025 mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_TX_INT, cpm_intr);1026 }1027 1028 /* BBE RX */1029 if (intr & MCS_BBE_RX_INT_ENA) {1030 bbe_intr = mcs_reg_read(mcs, MCSX_BBE_RX_SLAVE_BBE_INT);1031 mcs->mcs_ops->mcs_bbe_intr_handler(mcs, bbe_intr, MCS_RX);1032 1033 /* Clear the interrupt */1034 mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_BBE_INT_INTR_RW, 0);1035 mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_BBE_INT, bbe_intr);1036 }1037 1038 /* BBE TX */1039 if (intr & MCS_BBE_TX_INT_ENA) {1040 bbe_intr = mcs_reg_read(mcs, MCSX_BBE_TX_SLAVE_BBE_INT);1041 mcs->mcs_ops->mcs_bbe_intr_handler(mcs, bbe_intr, MCS_TX);1042 1043 /* Clear the interrupt */1044 mcs_reg_write(mcs, MCSX_BBE_TX_SLAVE_BBE_INT_INTR_RW, 0);1045 mcs_reg_write(mcs, MCSX_BBE_TX_SLAVE_BBE_INT, bbe_intr);1046 }1047 1048 /* PAB RX */1049 if (intr & MCS_PAB_RX_INT_ENA) {1050 pab_intr = mcs_reg_read(mcs, MCSX_PAB_RX_SLAVE_PAB_INT);1051 mcs->mcs_ops->mcs_pab_intr_handler(mcs, pab_intr, MCS_RX);1052 1053 /* Clear the interrupt */1054 mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_PAB_INT_INTR_RW, 0);1055 mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_PAB_INT, pab_intr);1056 }1057 1058 /* PAB TX */1059 if (intr & MCS_PAB_TX_INT_ENA) {1060 pab_intr = mcs_reg_read(mcs, MCSX_PAB_TX_SLAVE_PAB_INT);1061 mcs->mcs_ops->mcs_pab_intr_handler(mcs, pab_intr, MCS_TX);1062 1063 /* Clear the interrupt */1064 mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT_INTR_RW, 0);1065 mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT, pab_intr);1066 }1067 1068 /* Clear and enable the interrupt */1069 mcs_reg_write(mcs, MCSX_IP_INT, BIT_ULL(0));1070 mcs_reg_write(mcs, MCSX_IP_INT_ENA_W1S, BIT_ULL(0));1071 1072 return IRQ_HANDLED;1073}1074 1075static void *alloc_mem(struct mcs *mcs, int n)1076{1077 return devm_kcalloc(mcs->dev, n, sizeof(u16), GFP_KERNEL);1078}1079 1080static int mcs_alloc_struct_mem(struct mcs *mcs, struct mcs_rsrc_map *res)1081{1082 struct hwinfo *hw = mcs->hw;1083 int err;1084 1085 res->flowid2pf_map = alloc_mem(mcs, hw->tcam_entries);1086 if (!res->flowid2pf_map)1087 return -ENOMEM;1088 1089 res->secy2pf_map = alloc_mem(mcs, hw->secy_entries);1090 if (!res->secy2pf_map)1091 return -ENOMEM;1092 1093 res->sc2pf_map = alloc_mem(mcs, hw->sc_entries);1094 if (!res->sc2pf_map)1095 return -ENOMEM;1096 1097 res->sa2pf_map = alloc_mem(mcs, hw->sa_entries);1098 if (!res->sa2pf_map)1099 return -ENOMEM;1100 1101 res->flowid2secy_map = alloc_mem(mcs, hw->tcam_entries);1102 if (!res->flowid2secy_map)1103 return -ENOMEM;1104 1105 res->ctrlpktrule2pf_map = alloc_mem(mcs, MCS_MAX_CTRLPKT_RULES);1106 if (!res->ctrlpktrule2pf_map)1107 return -ENOMEM;1108 1109 res->flow_ids.max = hw->tcam_entries - MCS_RSRC_RSVD_CNT;1110 err = rvu_alloc_bitmap(&res->flow_ids);1111 if (err)1112 return err;1113 1114 res->secy.max = hw->secy_entries - MCS_RSRC_RSVD_CNT;1115 err = rvu_alloc_bitmap(&res->secy);1116 if (err)1117 return err;1118 1119 res->sc.max = hw->sc_entries;1120 err = rvu_alloc_bitmap(&res->sc);1121 if (err)1122 return err;1123 1124 res->sa.max = hw->sa_entries;1125 err = rvu_alloc_bitmap(&res->sa);1126 if (err)1127 return err;1128 1129 res->ctrlpktrule.max = MCS_MAX_CTRLPKT_RULES;1130 err = rvu_alloc_bitmap(&res->ctrlpktrule);1131 if (err)1132 return err;1133 1134 return 0;1135}1136 1137static int mcs_register_interrupts(struct mcs *mcs)1138{1139 int ret = 0;1140 1141 mcs->num_vec = pci_msix_vec_count(mcs->pdev);1142 1143 ret = pci_alloc_irq_vectors(mcs->pdev, mcs->num_vec,1144 mcs->num_vec, PCI_IRQ_MSIX);1145 if (ret < 0) {1146 dev_err(mcs->dev, "MCS Request for %d msix vector failed err:%d\n",1147 mcs->num_vec, ret);1148 return ret;1149 }1150 1151 ret = request_irq(pci_irq_vector(mcs->pdev, mcs->hw->ip_vec),1152 mcs_ip_intr_handler, 0, "MCS_IP", mcs);1153 if (ret) {1154 dev_err(mcs->dev, "MCS IP irq registration failed\n");1155 goto exit;1156 }1157 1158 /* MCS enable IP interrupts */1159 mcs_reg_write(mcs, MCSX_IP_INT_ENA_W1S, BIT_ULL(0));1160 1161 /* Enable CPM Rx/Tx interrupts */1162 mcs_reg_write(mcs, MCSX_TOP_SLAVE_INT_SUM_ENB,1163 MCS_CPM_RX_INT_ENA | MCS_CPM_TX_INT_ENA |1164 MCS_BBE_RX_INT_ENA | MCS_BBE_TX_INT_ENA |1165 MCS_PAB_RX_INT_ENA | MCS_PAB_TX_INT_ENA);1166 1167 mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_TX_INT_ENB, 0x7ULL);1168 mcs_reg_write(mcs, MCSX_CPM_RX_SLAVE_RX_INT_ENB, 0x7FULL);1169 1170 mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_BBE_INT_ENB, 0xFFULL);1171 mcs_reg_write(mcs, MCSX_BBE_TX_SLAVE_BBE_INT_ENB, 0xFFULL);1172 1173 mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_PAB_INT_ENB, 0xFFFFFULL);1174 mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT_ENB, 0xFFFFFULL);1175 1176 mcs->tx_sa_active = alloc_mem(mcs, mcs->hw->sc_entries);1177 if (!mcs->tx_sa_active) {1178 ret = -ENOMEM;1179 goto free_irq;1180 }1181 1182 return ret;1183 1184free_irq:1185 free_irq(pci_irq_vector(mcs->pdev, mcs->hw->ip_vec), mcs);1186exit:1187 pci_free_irq_vectors(mcs->pdev);1188 mcs->num_vec = 0;1189 return ret;1190}1191 1192int mcs_get_blkcnt(void)1193{1194 struct mcs *mcs;1195 int idmax = -ENODEV;1196 1197 /* Check MCS block is present in hardware */1198 if (!pci_dev_present(mcs_id_table))1199 return 0;1200 1201 list_for_each_entry(mcs, &mcs_list, mcs_list)1202 if (mcs->mcs_id > idmax)1203 idmax = mcs->mcs_id;1204 1205 if (idmax < 0)1206 return 0;1207 1208 return idmax + 1;1209}1210 1211struct mcs *mcs_get_pdata(int mcs_id)1212{1213 struct mcs *mcs_dev;1214 1215 list_for_each_entry(mcs_dev, &mcs_list, mcs_list) {1216 if (mcs_dev->mcs_id == mcs_id)1217 return mcs_dev;1218 }1219 return NULL;1220}1221 1222bool is_mcs_bypass(int mcs_id)1223{1224 struct mcs *mcs_dev;1225 1226 list_for_each_entry(mcs_dev, &mcs_list, mcs_list) {1227 if (mcs_dev->mcs_id == mcs_id)1228 return mcs_dev->bypass;1229 }1230 return true;1231}1232 1233void mcs_set_port_cfg(struct mcs *mcs, struct mcs_port_cfg_set_req *req)1234{1235 u64 val = 0;1236 1237 mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_PORT_CFGX(req->port_id),1238 req->port_mode & MCS_PORT_MODE_MASK);1239 1240 req->cstm_tag_rel_mode_sel &= 0x3;1241 1242 if (mcs->hw->mcs_blks > 1) {1243 req->fifo_skid &= MCS_PORT_FIFO_SKID_MASK;1244 val = (u32)req->fifo_skid << 0x10;1245 val |= req->fifo_skid;1246 mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_FIFO_SKID_CFGX(req->port_id), val);1247 mcs_reg_write(mcs, MCSX_PEX_TX_SLAVE_CUSTOM_TAG_REL_MODE_SEL(req->port_id),1248 req->cstm_tag_rel_mode_sel);1249 val = mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION);1250 1251 if (req->custom_hdr_enb)1252 val |= BIT_ULL(req->port_id);1253 else1254 val &= ~BIT_ULL(req->port_id);1255 1256 mcs_reg_write(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION, val);1257 } else {1258 val = mcs_reg_read(mcs, MCSX_PEX_TX_SLAVE_PORT_CONFIG(req->port_id));1259 val |= (req->cstm_tag_rel_mode_sel << 2);1260 mcs_reg_write(mcs, MCSX_PEX_TX_SLAVE_PORT_CONFIG(req->port_id), val);1261 }1262}1263 1264void mcs_get_port_cfg(struct mcs *mcs, struct mcs_port_cfg_get_req *req,1265 struct mcs_port_cfg_get_rsp *rsp)1266{1267 u64 reg = 0;1268 1269 rsp->port_mode = mcs_reg_read(mcs, MCSX_PAB_RX_SLAVE_PORT_CFGX(req->port_id)) &1270 MCS_PORT_MODE_MASK;1271 1272 if (mcs->hw->mcs_blks > 1) {1273 reg = MCSX_PAB_RX_SLAVE_FIFO_SKID_CFGX(req->port_id);1274 rsp->fifo_skid = mcs_reg_read(mcs, reg) & MCS_PORT_FIFO_SKID_MASK;1275 reg = MCSX_PEX_TX_SLAVE_CUSTOM_TAG_REL_MODE_SEL(req->port_id);1276 rsp->cstm_tag_rel_mode_sel = mcs_reg_read(mcs, reg) & 0x3;1277 if (mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION) & BIT_ULL(req->port_id))1278 rsp->custom_hdr_enb = 1;1279 } else {1280 reg = MCSX_PEX_TX_SLAVE_PORT_CONFIG(req->port_id);1281 rsp->cstm_tag_rel_mode_sel = mcs_reg_read(mcs, reg) >> 2;1282 }1283 1284 rsp->port_id = req->port_id;1285 rsp->mcs_id = req->mcs_id;1286}1287 1288void mcs_get_custom_tag_cfg(struct mcs *mcs, struct mcs_custom_tag_cfg_get_req *req,1289 struct mcs_custom_tag_cfg_get_rsp *rsp)1290{1291 u64 reg = 0, val = 0;1292 u8 idx;1293 1294 for (idx = 0; idx < MCS_MAX_CUSTOM_TAGS; idx++) {1295 if (mcs->hw->mcs_blks > 1)1296 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_CUSTOM_TAGX(idx) :1297 MCSX_PEX_TX_SLAVE_CUSTOM_TAGX(idx);1298 else1299 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_VLAN_CFGX(idx) :1300 MCSX_PEX_TX_SLAVE_VLAN_CFGX(idx);1301 1302 val = mcs_reg_read(mcs, reg);1303 if (mcs->hw->mcs_blks > 1) {1304 rsp->cstm_etype[idx] = val & GENMASK(15, 0);1305 rsp->cstm_indx[idx] = (val >> 0x16) & 0x3;1306 reg = (req->dir == MCS_RX) ? MCSX_PEX_RX_SLAVE_ETYPE_ENABLE :1307 MCSX_PEX_TX_SLAVE_ETYPE_ENABLE;1308 rsp->cstm_etype_en = mcs_reg_read(mcs, reg) & 0xFF;1309 } else {1310 rsp->cstm_etype[idx] = (val >> 0x1) & GENMASK(15, 0);1311 rsp->cstm_indx[idx] = (val >> 0x11) & 0x3;1312 rsp->cstm_etype_en |= (val & 0x1) << idx;1313 }1314 }1315 1316 rsp->mcs_id = req->mcs_id;1317 rsp->dir = req->dir;1318}1319 1320void mcs_reset_port(struct mcs *mcs, u8 port_id, u8 reset)1321{1322 u64 reg = MCSX_MCS_TOP_SLAVE_PORT_RESET(port_id);1323 1324 mcs_reg_write(mcs, reg, reset & 0x1);1325}1326 1327/* Set lmac to bypass/operational mode */1328void mcs_set_lmac_mode(struct mcs *mcs, int lmac_id, u8 mode)1329{1330 u64 reg;1331 int id = lmac_id * 2;1332 1333 reg = MCSX_MCS_TOP_SLAVE_CHANNEL_CFG(id);1334 mcs_reg_write(mcs, reg, (u64)mode);1335 reg = MCSX_MCS_TOP_SLAVE_CHANNEL_CFG((id + 1));1336 mcs_reg_write(mcs, reg, (u64)mode);1337}1338 1339void mcs_pn_threshold_set(struct mcs *mcs, struct mcs_set_pn_threshold *pn)1340{1341 u64 reg;1342 1343 if (pn->dir == MCS_RX)1344 reg = pn->xpn ? MCSX_CPM_RX_SLAVE_XPN_THRESHOLD : MCSX_CPM_RX_SLAVE_PN_THRESHOLD;1345 else1346 reg = pn->xpn ? MCSX_CPM_TX_SLAVE_XPN_THRESHOLD : MCSX_CPM_TX_SLAVE_PN_THRESHOLD;1347 1348 mcs_reg_write(mcs, reg, pn->threshold);1349}1350 1351void cn10kb_mcs_parser_cfg(struct mcs *mcs)1352{1353 u64 reg, val;1354 1355 /* VLAN CTag */1356 val = BIT_ULL(0) | (0x8100ull & 0xFFFF) << 1 | BIT_ULL(17);1357 /* RX */1358 reg = MCSX_PEX_RX_SLAVE_VLAN_CFGX(0);1359 mcs_reg_write(mcs, reg, val);1360 1361 /* TX */1362 reg = MCSX_PEX_TX_SLAVE_VLAN_CFGX(0);1363 mcs_reg_write(mcs, reg, val);1364 1365 /* VLAN STag */1366 val = BIT_ULL(0) | (0x88a8ull & 0xFFFF) << 1 | BIT_ULL(18);1367 /* RX */1368 reg = MCSX_PEX_RX_SLAVE_VLAN_CFGX(1);1369 mcs_reg_write(mcs, reg, val);1370 1371 /* TX */1372 reg = MCSX_PEX_TX_SLAVE_VLAN_CFGX(1);1373 mcs_reg_write(mcs, reg, val);1374}1375 1376static void mcs_lmac_init(struct mcs *mcs, int lmac_id)1377{1378 u64 reg;1379 1380 /* Port mode 25GB */1381 reg = MCSX_PAB_RX_SLAVE_PORT_CFGX(lmac_id);1382 mcs_reg_write(mcs, reg, 0);1383 1384 if (mcs->hw->mcs_blks > 1) {1385 reg = MCSX_PAB_RX_SLAVE_FIFO_SKID_CFGX(lmac_id);1386 mcs_reg_write(mcs, reg, 0xe000e);1387 return;1388 }1389 1390 reg = MCSX_PAB_TX_SLAVE_PORT_CFGX(lmac_id);1391 mcs_reg_write(mcs, reg, 0);1392}1393 1394int mcs_set_lmac_channels(int mcs_id, u16 base)1395{1396 struct mcs *mcs;1397 int lmac;1398 u64 cfg;1399 1400 mcs = mcs_get_pdata(mcs_id);1401 if (!mcs)1402 return -ENODEV;1403 for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++) {1404 cfg = mcs_reg_read(mcs, MCSX_LINK_LMACX_CFG(lmac));1405 cfg &= ~(MCSX_LINK_LMAC_BASE_MASK | MCSX_LINK_LMAC_RANGE_MASK);1406 cfg |= FIELD_PREP(MCSX_LINK_LMAC_RANGE_MASK, ilog2(16));1407 cfg |= FIELD_PREP(MCSX_LINK_LMAC_BASE_MASK, base);1408 mcs_reg_write(mcs, MCSX_LINK_LMACX_CFG(lmac), cfg);1409 base += 16;1410 }1411 return 0;1412}1413 1414static int mcs_x2p_calibration(struct mcs *mcs)1415{1416 unsigned long timeout = jiffies + usecs_to_jiffies(20000);1417 int i, err = 0;1418 u64 val;1419 1420 /* set X2P calibration */1421 val = mcs_reg_read(mcs, MCSX_MIL_GLOBAL);1422 val |= BIT_ULL(5);1423 mcs_reg_write(mcs, MCSX_MIL_GLOBAL, val);1424 1425 /* Wait for calibration to complete */1426 while (!(mcs_reg_read(mcs, MCSX_MIL_RX_GBL_STATUS) & BIT_ULL(0))) {1427 if (time_before(jiffies, timeout)) {1428 usleep_range(80, 100);1429 continue;1430 } else {1431 err = -EBUSY;1432 dev_err(mcs->dev, "MCS X2P calibration failed..ignoring\n");1433 return err;1434 }1435 }1436 1437 val = mcs_reg_read(mcs, MCSX_MIL_RX_GBL_STATUS);1438 for (i = 0; i < mcs->hw->mcs_x2p_intf; i++) {1439 if (val & BIT_ULL(1 + i))1440 continue;1441 err = -EBUSY;1442 dev_err(mcs->dev, "MCS:%d didn't respond to X2P calibration\n", i);1443 }1444 /* Clear X2P calibrate */1445 mcs_reg_write(mcs, MCSX_MIL_GLOBAL, mcs_reg_read(mcs, MCSX_MIL_GLOBAL) & ~BIT_ULL(5));1446 1447 return err;1448}1449 1450static void mcs_set_external_bypass(struct mcs *mcs, bool bypass)1451{1452 u64 val;1453 1454 /* Set MCS to external bypass */1455 val = mcs_reg_read(mcs, MCSX_MIL_GLOBAL);1456 if (bypass)1457 val |= BIT_ULL(6);1458 else1459 val &= ~BIT_ULL(6);1460 mcs_reg_write(mcs, MCSX_MIL_GLOBAL, val);1461 mcs->bypass = bypass;1462}1463 1464static void mcs_global_cfg(struct mcs *mcs)1465{1466 /* Disable external bypass */1467 mcs_set_external_bypass(mcs, false);1468 1469 /* Reset TX/RX stats memory */1470 mcs_reg_write(mcs, MCSX_CSE_RX_SLAVE_STATS_CLEAR, 0x1F);1471 mcs_reg_write(mcs, MCSX_CSE_TX_SLAVE_STATS_CLEAR, 0x1F);1472 1473 /* Set MCS to perform standard IEEE802.1AE macsec processing */1474 if (mcs->hw->mcs_blks == 1) {1475 mcs_reg_write(mcs, MCSX_IP_MODE, BIT_ULL(3));1476 return;1477 }1478 1479 mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_CAL_ENTRY, 0xe4);1480 mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_CAL_LEN, 4);1481}1482 1483void cn10kb_mcs_set_hw_capabilities(struct mcs *mcs)1484{1485 struct hwinfo *hw = mcs->hw;1486 1487 hw->tcam_entries = 128; /* TCAM entries */1488 hw->secy_entries = 128; /* SecY entries */1489 hw->sc_entries = 128; /* SC CAM entries */1490 hw->sa_entries = 256; /* SA entries */1491 hw->lmac_cnt = 20; /* lmacs/ports per mcs block */1492 hw->mcs_x2p_intf = 5; /* x2p clabration intf */1493 hw->mcs_blks = 1; /* MCS blocks */1494 hw->ip_vec = MCS_CN10KB_INT_VEC_IP; /* IP vector */1495}1496 1497static struct mcs_ops cn10kb_mcs_ops = {1498 .mcs_set_hw_capabilities = cn10kb_mcs_set_hw_capabilities,1499 .mcs_parser_cfg = cn10kb_mcs_parser_cfg,1500 .mcs_tx_sa_mem_map_write = cn10kb_mcs_tx_sa_mem_map_write,1501 .mcs_rx_sa_mem_map_write = cn10kb_mcs_rx_sa_mem_map_write,1502 .mcs_flowid_secy_map = cn10kb_mcs_flowid_secy_map,1503 .mcs_bbe_intr_handler = cn10kb_mcs_bbe_intr_handler,1504 .mcs_pab_intr_handler = cn10kb_mcs_pab_intr_handler,1505};1506 1507static int mcs_probe(struct pci_dev *pdev, const struct pci_device_id *id)1508{1509 struct device *dev = &pdev->dev;1510 int lmac, err = 0;1511 struct mcs *mcs;1512 1513 mcs = devm_kzalloc(dev, sizeof(*mcs), GFP_KERNEL);1514 if (!mcs)1515 return -ENOMEM;1516 1517 mcs->hw = devm_kzalloc(dev, sizeof(struct hwinfo), GFP_KERNEL);1518 if (!mcs->hw)1519 return -ENOMEM;1520 1521 err = pci_enable_device(pdev);1522 if (err) {1523 dev_err(dev, "Failed to enable PCI device\n");1524 pci_set_drvdata(pdev, NULL);1525 return err;1526 }1527 1528 err = pci_request_regions(pdev, DRV_NAME);1529 if (err) {1530 dev_err(dev, "PCI request regions failed 0x%x\n", err);1531 goto exit;1532 }1533 1534 mcs->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);1535 if (!mcs->reg_base) {1536 dev_err(dev, "mcs: Cannot map CSR memory space, aborting\n");1537 err = -ENOMEM;1538 goto exit;1539 }1540 1541 pci_set_drvdata(pdev, mcs);1542 mcs->pdev = pdev;1543 mcs->dev = &pdev->dev;1544 1545 if (pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_B)1546 mcs->mcs_ops = &cn10kb_mcs_ops;1547 else1548 mcs->mcs_ops = cnf10kb_get_mac_ops();1549 1550 /* Set hardware capabilities */1551 mcs->mcs_ops->mcs_set_hw_capabilities(mcs);1552 1553 mcs_global_cfg(mcs);1554 1555 /* Perform X2P clibration */1556 err = mcs_x2p_calibration(mcs);1557 if (err)1558 goto err_x2p;1559 1560 mcs->mcs_id = (pci_resource_start(pdev, PCI_CFG_REG_BAR_NUM) >> 24)1561 & MCS_ID_MASK;1562 1563 /* Set mcs tx side resources */1564 err = mcs_alloc_struct_mem(mcs, &mcs->tx);1565 if (err)1566 goto err_x2p;1567 1568 /* Set mcs rx side resources */1569 err = mcs_alloc_struct_mem(mcs, &mcs->rx);1570 if (err)1571 goto err_x2p;1572 1573 /* per port config */1574 for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++)1575 mcs_lmac_init(mcs, lmac);1576 1577 /* Parser configuration */1578 mcs->mcs_ops->mcs_parser_cfg(mcs);1579 1580 err = mcs_register_interrupts(mcs);1581 if (err)1582 goto exit;1583 1584 list_add(&mcs->mcs_list, &mcs_list);1585 mutex_init(&mcs->stats_lock);1586 1587 return 0;1588 1589err_x2p:1590 /* Enable external bypass */1591 mcs_set_external_bypass(mcs, true);1592exit:1593 pci_release_regions(pdev);1594 pci_disable_device(pdev);1595 pci_set_drvdata(pdev, NULL);1596 return err;1597}1598 1599static void mcs_remove(struct pci_dev *pdev)1600{1601 struct mcs *mcs = pci_get_drvdata(pdev);1602 1603 /* Set MCS to external bypass */1604 mcs_set_external_bypass(mcs, true);1605 free_irq(pci_irq_vector(pdev, mcs->hw->ip_vec), mcs);1606 pci_free_irq_vectors(pdev);1607 pci_release_regions(pdev);1608 pci_disable_device(pdev);1609 pci_set_drvdata(pdev, NULL);1610}1611 1612struct pci_driver mcs_driver = {1613 .name = DRV_NAME,1614 .id_table = mcs_id_table,1615 .probe = mcs_probe,1616 .remove = mcs_remove,1617};1618