-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drivers: net: xgene: Add support for Classifier engine
Signed-off-by: Iyappan Subramanian <isubramanian@apm.com> Signed-off-by: Khuong Dinh <kdinh@apm.com> Signed-off-by: Tanmay Inamdar <tinamdar@apm.com> Tested-by: Toan Le <toanle@apm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Iyappan Subramanian
authored and
David S. Miller
committed
Feb 18, 2016
1 parent
e4999f2
commit 76f94a9
Showing
6 changed files
with
649 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,357 @@ | ||
/* Applied Micro X-Gene SoC Ethernet Classifier structures | ||
* | ||
* Copyright (c) 2016, Applied Micro Circuits Corporation | ||
* Authors: Khuong Dinh <kdinh@apm.com> | ||
* Tanmay Inamdar <tinamdar@apm.com> | ||
* Iyappan Subramanian <isubramanian@apm.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License as published by the | ||
* Free Software Foundation; either version 2 of the License, or (at your | ||
* option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include "xgene_enet_main.h" | ||
|
||
static void xgene_cle_dbptr_to_hw(struct xgene_enet_pdata *pdata, | ||
struct xgene_cle_dbptr *dbptr, u32 *buf) | ||
{ | ||
buf[4] = SET_VAL(CLE_FPSEL, dbptr->fpsel) | | ||
SET_VAL(CLE_DSTQIDL, dbptr->dstqid); | ||
|
||
buf[5] = SET_VAL(CLE_DSTQIDH, (u32)dbptr->dstqid >> CLE_DSTQIDL_LEN) | | ||
SET_VAL(CLE_PRIORITY, dbptr->cle_priority); | ||
} | ||
|
||
static void xgene_cle_kn_to_hw(struct xgene_cle_ptree_kn *kn, u32 *buf) | ||
{ | ||
u32 i, j = 0; | ||
u32 data; | ||
|
||
buf[j++] = SET_VAL(CLE_TYPE, kn->node_type); | ||
for (i = 0; i < kn->num_keys; i++) { | ||
struct xgene_cle_ptree_key *key = &kn->key[i]; | ||
|
||
if (!(i % 2)) { | ||
buf[j] = SET_VAL(CLE_KN_PRIO, key->priority) | | ||
SET_VAL(CLE_KN_RPTR, key->result_pointer); | ||
} else { | ||
data = SET_VAL(CLE_KN_PRIO, key->priority) | | ||
SET_VAL(CLE_KN_RPTR, key->result_pointer); | ||
buf[j++] |= (data << 16); | ||
} | ||
} | ||
} | ||
|
||
static void xgene_cle_dn_to_hw(struct xgene_cle_ptree_ewdn *dn, | ||
u32 *buf, u32 jb) | ||
{ | ||
struct xgene_cle_ptree_branch *br; | ||
u32 i, j = 0; | ||
u32 npp; | ||
|
||
buf[j++] = SET_VAL(CLE_DN_TYPE, dn->node_type) | | ||
SET_VAL(CLE_DN_LASTN, dn->last_node) | | ||
SET_VAL(CLE_DN_HLS, dn->hdr_len_store) | | ||
SET_VAL(CLE_DN_EXT, dn->hdr_extn) | | ||
SET_VAL(CLE_DN_BSTOR, dn->byte_store) | | ||
SET_VAL(CLE_DN_SBSTOR, dn->search_byte_store) | | ||
SET_VAL(CLE_DN_RPTR, dn->result_pointer); | ||
|
||
for (i = 0; i < dn->num_branches; i++) { | ||
br = &dn->branch[i]; | ||
npp = br->next_packet_pointer; | ||
|
||
if ((br->jump_rel == JMP_ABS) && (npp < CLE_PKTRAM_SIZE)) | ||
npp += jb; | ||
|
||
buf[j++] = SET_VAL(CLE_BR_VALID, br->valid) | | ||
SET_VAL(CLE_BR_NPPTR, npp) | | ||
SET_VAL(CLE_BR_JB, br->jump_bw) | | ||
SET_VAL(CLE_BR_JR, br->jump_rel) | | ||
SET_VAL(CLE_BR_OP, br->operation) | | ||
SET_VAL(CLE_BR_NNODE, br->next_node) | | ||
SET_VAL(CLE_BR_NBR, br->next_branch); | ||
|
||
buf[j++] = SET_VAL(CLE_BR_DATA, br->data) | | ||
SET_VAL(CLE_BR_MASK, br->mask); | ||
} | ||
} | ||
|
||
static int xgene_cle_poll_cmd_done(void __iomem *base, | ||
enum xgene_cle_cmd_type cmd) | ||
{ | ||
u32 status, loop = 10; | ||
int ret = -EBUSY; | ||
|
||
while (loop--) { | ||
status = ioread32(base + INDCMD_STATUS); | ||
if (status & cmd) { | ||
ret = 0; | ||
break; | ||
} | ||
usleep_range(1000, 2000); | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
static int xgene_cle_dram_wr(struct xgene_enet_cle *cle, u32 *data, u8 nregs, | ||
u32 index, enum xgene_cle_dram_type type, | ||
enum xgene_cle_cmd_type cmd) | ||
{ | ||
enum xgene_cle_parser parser = cle->active_parser; | ||
void __iomem *base = cle->base; | ||
u32 i, j, ind_addr; | ||
u8 port, nparsers; | ||
int ret = 0; | ||
|
||
/* PTREE_RAM onwards, DRAM regions are common for all parsers */ | ||
nparsers = (type >= PTREE_RAM) ? 1 : cle->parsers; | ||
|
||
for (i = 0; i < nparsers; i++) { | ||
port = i; | ||
if ((type < PTREE_RAM) && (parser != PARSER_ALL)) | ||
port = parser; | ||
|
||
ind_addr = XGENE_CLE_DRAM(type + (port * 4)) | index; | ||
iowrite32(ind_addr, base + INDADDR); | ||
for (j = 0; j < nregs; j++) | ||
iowrite32(data[j], base + DATA_RAM0 + (j * 4)); | ||
iowrite32(cmd, base + INDCMD); | ||
|
||
ret = xgene_cle_poll_cmd_done(base, cmd); | ||
if (ret) | ||
break; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
static void xgene_cle_enable_ptree(struct xgene_enet_pdata *pdata, | ||
struct xgene_enet_cle *cle) | ||
{ | ||
struct xgene_cle_ptree *ptree = &cle->ptree; | ||
void __iomem *addr, *base = cle->base; | ||
u32 offset = CLE_PORT_OFFSET; | ||
u32 i; | ||
|
||
/* 1G port has to advance 4 bytes and 10G has to advance 8 bytes */ | ||
ptree->start_pkt += cle->jump_bytes; | ||
for (i = 0; i < cle->parsers; i++) { | ||
if (cle->active_parser != PARSER_ALL) | ||
addr = base + cle->active_parser * offset; | ||
else | ||
addr = base + (i * offset); | ||
|
||
iowrite32(ptree->start_node & 0x3fff, addr + SNPTR0); | ||
iowrite32(ptree->start_pkt & 0x1ff, addr + SPPTR0); | ||
} | ||
} | ||
|
||
static int xgene_cle_setup_dbptr(struct xgene_enet_pdata *pdata, | ||
struct xgene_enet_cle *cle) | ||
{ | ||
struct xgene_cle_ptree *ptree = &cle->ptree; | ||
u32 buf[CLE_DRAM_REGS]; | ||
u32 i; | ||
int ret; | ||
|
||
memset(buf, 0, sizeof(buf)); | ||
for (i = 0; i < ptree->num_dbptr; i++) { | ||
xgene_cle_dbptr_to_hw(pdata, &ptree->dbptr[i], buf); | ||
ret = xgene_cle_dram_wr(cle, buf, 6, i + ptree->start_dbptr, | ||
DB_RAM, CLE_CMD_WR); | ||
if (ret) | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int xgene_cle_setup_node(struct xgene_enet_pdata *pdata, | ||
struct xgene_enet_cle *cle) | ||
{ | ||
struct xgene_cle_ptree *ptree = &cle->ptree; | ||
struct xgene_cle_ptree_ewdn *dn = ptree->dn; | ||
struct xgene_cle_ptree_kn *kn = ptree->kn; | ||
u32 buf[CLE_DRAM_REGS]; | ||
int i, j, ret; | ||
|
||
memset(buf, 0, sizeof(buf)); | ||
for (i = 0; i < ptree->num_dn; i++) { | ||
xgene_cle_dn_to_hw(&dn[i], buf, cle->jump_bytes); | ||
ret = xgene_cle_dram_wr(cle, buf, 17, i + ptree->start_node, | ||
PTREE_RAM, CLE_CMD_WR); | ||
if (ret) | ||
return ret; | ||
} | ||
|
||
/* continue node index for key node */ | ||
memset(buf, 0, sizeof(buf)); | ||
for (j = i; j < (ptree->num_kn + ptree->num_dn); j++) { | ||
xgene_cle_kn_to_hw(&kn[j - ptree->num_dn], buf); | ||
ret = xgene_cle_dram_wr(cle, buf, 17, j + ptree->start_node, | ||
PTREE_RAM, CLE_CMD_WR); | ||
if (ret) | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int xgene_cle_setup_ptree(struct xgene_enet_pdata *pdata, | ||
struct xgene_enet_cle *cle) | ||
{ | ||
int ret; | ||
|
||
ret = xgene_cle_setup_node(pdata, cle); | ||
if (ret) | ||
return ret; | ||
|
||
ret = xgene_cle_setup_dbptr(pdata, cle); | ||
if (ret) | ||
return ret; | ||
|
||
xgene_cle_enable_ptree(pdata, cle); | ||
|
||
return 0; | ||
} | ||
|
||
static void xgene_cle_setup_def_dbptr(struct xgene_enet_pdata *pdata, | ||
struct xgene_enet_cle *enet_cle, | ||
struct xgene_cle_dbptr *dbptr, | ||
u32 index, u8 priority) | ||
{ | ||
void __iomem *base = enet_cle->base; | ||
void __iomem *base_addr; | ||
u32 buf[CLE_DRAM_REGS]; | ||
u32 def_cls, offset; | ||
u32 i, j; | ||
|
||
memset(buf, 0, sizeof(buf)); | ||
xgene_cle_dbptr_to_hw(pdata, dbptr, buf); | ||
|
||
for (i = 0; i < enet_cle->parsers; i++) { | ||
if (enet_cle->active_parser != PARSER_ALL) { | ||
offset = enet_cle->active_parser * | ||
CLE_PORT_OFFSET; | ||
} else { | ||
offset = i * CLE_PORT_OFFSET; | ||
} | ||
|
||
base_addr = base + DFCLSRESDB00 + offset; | ||
for (j = 0; j < 6; j++) | ||
iowrite32(buf[j], base_addr + (j * 4)); | ||
|
||
def_cls = ((priority & 0x7) << 10) | (index & 0x3ff); | ||
iowrite32(def_cls, base + DFCLSRESDBPTR0 + offset); | ||
} | ||
} | ||
|
||
static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata) | ||
{ | ||
struct xgene_enet_cle *enet_cle = &pdata->cle; | ||
struct xgene_cle_dbptr dbptr[DB_MAX_PTRS]; | ||
u32 def_qid, def_fpsel, pool_id; | ||
struct xgene_cle_ptree *ptree; | ||
struct xgene_cle_ptree_kn kn; | ||
struct xgene_cle_ptree_ewdn ptree_dn[] = { | ||
{ | ||
/* PKT_TYPE_NODE */ | ||
.node_type = EWDN, | ||
.last_node = 0, | ||
.hdr_len_store = 0, | ||
.hdr_extn = NO_BYTE, | ||
.byte_store = NO_BYTE, | ||
.search_byte_store = NO_BYTE, | ||
.result_pointer = DB_RES_DROP, | ||
.num_branches = 1, | ||
.branch = { | ||
{ | ||
/* Allow all packet type */ | ||
.valid = 0, | ||
.next_packet_pointer = 0, | ||
.jump_bw = JMP_FW, | ||
.jump_rel = JMP_ABS, | ||
.operation = EQT, | ||
.next_node = LAST_NODE, | ||
.next_branch = 0, | ||
.data = 0x0, | ||
.mask = 0xffff | ||
} | ||
} | ||
}, | ||
{ | ||
/* LAST NODE */ | ||
.node_type = EWDN, | ||
.last_node = 1, | ||
.hdr_len_store = 0, | ||
.hdr_extn = NO_BYTE, | ||
.byte_store = NO_BYTE, | ||
.search_byte_store = NO_BYTE, | ||
.result_pointer = DB_RES_DROP, | ||
.num_branches = 1, | ||
.branch = { | ||
{ | ||
.valid = 0, | ||
.next_packet_pointer = 0, | ||
.jump_bw = JMP_FW, | ||
.jump_rel = JMP_ABS, | ||
.operation = EQT, | ||
.next_node = MAX_NODES, | ||
.next_branch = 0, | ||
.data = 0, | ||
.mask = 0xffff | ||
} | ||
} | ||
} | ||
}; | ||
|
||
ptree = &enet_cle->ptree; | ||
ptree->start_pkt = 12; /* Ethertype */ | ||
|
||
def_qid = xgene_enet_dst_ring_num(pdata->rx_ring); | ||
pool_id = pdata->rx_ring->buf_pool->id; | ||
def_fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20; | ||
|
||
memset(dbptr, 0, sizeof(struct xgene_cle_dbptr) * DB_MAX_PTRS); | ||
dbptr[DB_RES_ACCEPT].fpsel = def_fpsel; | ||
dbptr[DB_RES_ACCEPT].dstqid = def_qid; | ||
dbptr[DB_RES_ACCEPT].cle_priority = 1; | ||
|
||
dbptr[DB_RES_DEF].fpsel = def_fpsel; | ||
dbptr[DB_RES_DEF].dstqid = def_qid; | ||
dbptr[DB_RES_DEF].cle_priority = 7; | ||
xgene_cle_setup_def_dbptr(pdata, enet_cle, &dbptr[DB_RES_DEF], | ||
DB_RES_ACCEPT, 7); | ||
|
||
dbptr[DB_RES_DROP].drop = 1; | ||
|
||
memset(&kn, 0, sizeof(kn)); | ||
kn.node_type = KN; | ||
kn.num_keys = 1; | ||
kn.key[0].priority = 0; | ||
kn.key[0].result_pointer = DB_RES_ACCEPT; | ||
|
||
ptree->dn = ptree_dn; | ||
ptree->kn = &kn; | ||
ptree->dbptr = dbptr; | ||
ptree->num_dn = MAX_NODES; | ||
ptree->num_kn = 1; | ||
ptree->num_dbptr = DB_MAX_PTRS; | ||
|
||
return xgene_cle_setup_ptree(pdata, enet_cle); | ||
} | ||
|
||
struct xgene_cle_ops xgene_cle3in_ops = { | ||
.cle_init = xgene_enet_cle_init, | ||
}; |
Oops, something went wrong.