18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 58c2ecf20Sopenharmony_ci#include <linux/bitops.h> 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/string.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "prestera_dsa.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_CMD GENMASK(31, 30) 128c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_IS_TAGGED BIT(29) 138c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_DEV_NUM GENMASK(28, 24) 148c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_PORT_NUM GENMASK(23, 19) 158c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_VPT GENMASK(15, 13) 168c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_EXT_BIT BIT(12) 178c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_VID GENMASK(11, 0) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W1_EXT_BIT BIT(31) 208c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W1_CFI_BIT BIT(30) 218c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W1_PORT_NUM GENMASK(11, 10) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W2_EXT_BIT BIT(31) 248c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W2_PORT_NUM BIT(20) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W3_VID GENMASK(30, 27) 278c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W3_DST_EPORT GENMASK(23, 7) 288c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W3_DEV_NUM GENMASK(6, 0) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define PRESTERA_DSA_VID GENMASK(15, 12) 318c2ecf20Sopenharmony_ci#define PRESTERA_DSA_DEV_NUM GENMASK(11, 5) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciint prestera_dsa_parse(struct prestera_dsa *dsa, const u8 *dsa_buf) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci __be32 *dsa_words = (__be32 *)dsa_buf; 368c2ecf20Sopenharmony_ci enum prestera_dsa_cmd cmd; 378c2ecf20Sopenharmony_ci u32 words[4]; 388c2ecf20Sopenharmony_ci u32 field; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci words[0] = ntohl(dsa_words[0]); 418c2ecf20Sopenharmony_ci words[1] = ntohl(dsa_words[1]); 428c2ecf20Sopenharmony_ci words[2] = ntohl(dsa_words[2]); 438c2ecf20Sopenharmony_ci words[3] = ntohl(dsa_words[3]); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* set the common parameters */ 468c2ecf20Sopenharmony_ci cmd = (enum prestera_dsa_cmd)FIELD_GET(PRESTERA_DSA_W0_CMD, words[0]); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* only to CPU is supported */ 498c2ecf20Sopenharmony_ci if (unlikely(cmd != PRESTERA_DSA_CMD_TO_CPU)) 508c2ecf20Sopenharmony_ci return -EINVAL; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (FIELD_GET(PRESTERA_DSA_W0_EXT_BIT, words[0]) == 0) 538c2ecf20Sopenharmony_ci return -EINVAL; 548c2ecf20Sopenharmony_ci if (FIELD_GET(PRESTERA_DSA_W1_EXT_BIT, words[1]) == 0) 558c2ecf20Sopenharmony_ci return -EINVAL; 568c2ecf20Sopenharmony_ci if (FIELD_GET(PRESTERA_DSA_W2_EXT_BIT, words[2]) == 0) 578c2ecf20Sopenharmony_ci return -EINVAL; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci field = FIELD_GET(PRESTERA_DSA_W3_VID, words[3]); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci dsa->vlan.is_tagged = FIELD_GET(PRESTERA_DSA_W0_IS_TAGGED, words[0]); 628c2ecf20Sopenharmony_ci dsa->vlan.cfi_bit = FIELD_GET(PRESTERA_DSA_W1_CFI_BIT, words[1]); 638c2ecf20Sopenharmony_ci dsa->vlan.vpt = FIELD_GET(PRESTERA_DSA_W0_VPT, words[0]); 648c2ecf20Sopenharmony_ci dsa->vlan.vid = FIELD_GET(PRESTERA_DSA_W0_VID, words[0]); 658c2ecf20Sopenharmony_ci dsa->vlan.vid &= ~PRESTERA_DSA_VID; 668c2ecf20Sopenharmony_ci dsa->vlan.vid |= FIELD_PREP(PRESTERA_DSA_VID, field); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci field = FIELD_GET(PRESTERA_DSA_W3_DEV_NUM, words[3]); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci dsa->hw_dev_num = FIELD_GET(PRESTERA_DSA_W0_DEV_NUM, words[0]); 718c2ecf20Sopenharmony_ci dsa->hw_dev_num |= FIELD_PREP(PRESTERA_DSA_DEV_NUM, field); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci dsa->port_num = (FIELD_GET(PRESTERA_DSA_W0_PORT_NUM, words[0]) << 0) | 748c2ecf20Sopenharmony_ci (FIELD_GET(PRESTERA_DSA_W1_PORT_NUM, words[1]) << 5) | 758c2ecf20Sopenharmony_ci (FIELD_GET(PRESTERA_DSA_W2_PORT_NUM, words[2]) << 7); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciint prestera_dsa_build(const struct prestera_dsa *dsa, u8 *dsa_buf) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci __be32 *dsa_words = (__be32 *)dsa_buf; 838c2ecf20Sopenharmony_ci u32 dev_num = dsa->hw_dev_num; 848c2ecf20Sopenharmony_ci u32 words[4] = { 0 }; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci words[0] |= FIELD_PREP(PRESTERA_DSA_W0_CMD, PRESTERA_DSA_CMD_FROM_CPU); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci words[0] |= FIELD_PREP(PRESTERA_DSA_W0_DEV_NUM, dev_num); 898c2ecf20Sopenharmony_ci dev_num = FIELD_GET(PRESTERA_DSA_DEV_NUM, dev_num); 908c2ecf20Sopenharmony_ci words[3] |= FIELD_PREP(PRESTERA_DSA_W3_DEV_NUM, dev_num); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci words[3] |= FIELD_PREP(PRESTERA_DSA_W3_DST_EPORT, dsa->port_num); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci words[0] |= FIELD_PREP(PRESTERA_DSA_W0_EXT_BIT, 1); 958c2ecf20Sopenharmony_ci words[1] |= FIELD_PREP(PRESTERA_DSA_W1_EXT_BIT, 1); 968c2ecf20Sopenharmony_ci words[2] |= FIELD_PREP(PRESTERA_DSA_W2_EXT_BIT, 1); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci dsa_words[0] = htonl(words[0]); 998c2ecf20Sopenharmony_ci dsa_words[1] = htonl(words[1]); 1008c2ecf20Sopenharmony_ci dsa_words[2] = htonl(words[2]); 1018c2ecf20Sopenharmony_ci dsa_words[3] = htonl(words[3]); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 105