drivers: net: xgene: Add support for RSS

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>
This commit is contained in:
Iyappan Subramanian 2016-02-17 15:00:40 -08:00 committed by David S. Miller
parent 76f94a9c77
commit fc4262d2aa
2 changed files with 422 additions and 5 deletions

View File

@ -21,6 +21,25 @@
#include "xgene_enet_main.h"
/* interfaces to convert structures to HW recognized bit formats */
static void xgene_cle_sband_to_hw(u8 frag, enum xgene_cle_prot_version ver,
enum xgene_cle_prot_type type, u32 len,
u32 *reg)
{
*reg = SET_VAL(SB_IPFRAG, frag) |
SET_VAL(SB_IPPROT, type) |
SET_VAL(SB_IPVER, ver) |
SET_VAL(SB_HDRLEN, len);
}
static void xgene_cle_idt_to_hw(u32 dstqid, u32 fpsel,
u32 nfpsel, u32 *idt_reg)
{
*idt_reg = SET_VAL(IDT_DSTQID, dstqid) |
SET_VAL(IDT_FPSEL, fpsel) |
SET_VAL(IDT_NFPSEL, nfpsel);
}
static void xgene_cle_dbptr_to_hw(struct xgene_enet_pdata *pdata,
struct xgene_cle_dbptr *dbptr, u32 *buf)
{
@ -257,29 +276,372 @@ static void xgene_cle_setup_def_dbptr(struct xgene_enet_pdata *pdata,
}
}
static int xgene_cle_set_rss_sband(struct xgene_enet_cle *cle)
{
u32 idx = CLE_PKTRAM_SIZE / sizeof(u32);
u32 mac_hdr_len = ETH_HLEN;
u32 sband, reg = 0;
u32 ipv4_ihl = 5;
u32 hdr_len;
int ret;
/* Sideband: IPV4/TCP packets */
hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_TCP, hdr_len, &reg);
sband = reg;
/* Sideband: IPv4/UDP packets */
hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
xgene_cle_sband_to_hw(1, XGENE_CLE_IPV4, XGENE_CLE_UDP, hdr_len, &reg);
sband |= (reg << 16);
ret = xgene_cle_dram_wr(cle, &sband, 1, idx, PKT_RAM, CLE_CMD_WR);
if (ret)
return ret;
/* Sideband: IPv4/RAW packets */
hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_OTHER,
hdr_len, &reg);
sband = reg;
/* Sideband: Ethernet II/RAW packets */
hdr_len = (mac_hdr_len << 5);
xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_OTHER,
hdr_len, &reg);
sband |= (reg << 16);
ret = xgene_cle_dram_wr(cle, &sband, 1, idx + 1, PKT_RAM, CLE_CMD_WR);
if (ret)
return ret;
return 0;
}
static int xgene_cle_set_rss_skeys(struct xgene_enet_cle *cle)
{
u32 secret_key_ipv4[4]; /* 16 Bytes*/
int ret = 0;
get_random_bytes(secret_key_ipv4, 16);
ret = xgene_cle_dram_wr(cle, secret_key_ipv4, 4, 0,
RSS_IPV4_HASH_SKEY, CLE_CMD_WR);
return ret;
}
static int xgene_cle_set_rss_idt(struct xgene_enet_pdata *pdata)
{
u32 fpsel, dstqid, nfpsel, idt_reg;
int i, ret = 0;
u16 pool_id;
for (i = 0; i < XGENE_CLE_IDT_ENTRIES; i++) {
pool_id = pdata->rx_ring->buf_pool->id;
fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20;
dstqid = xgene_enet_dst_ring_num(pdata->rx_ring);
nfpsel = 0;
idt_reg = 0;
xgene_cle_idt_to_hw(dstqid, fpsel, nfpsel, &idt_reg);
ret = xgene_cle_dram_wr(&pdata->cle, &idt_reg, 1, i,
RSS_IDT, CLE_CMD_WR);
if (ret)
return ret;
}
ret = xgene_cle_set_rss_skeys(&pdata->cle);
if (ret)
return ret;
return 0;
}
static int xgene_cle_setup_rss(struct xgene_enet_pdata *pdata)
{
struct xgene_enet_cle *cle = &pdata->cle;
void __iomem *base = cle->base;
u32 offset, val = 0;
int i, ret = 0;
offset = CLE_PORT_OFFSET;
for (i = 0; i < cle->parsers; i++) {
if (cle->active_parser != PARSER_ALL)
offset = cle->active_parser * CLE_PORT_OFFSET;
else
offset = i * CLE_PORT_OFFSET;
/* enable RSS */
val = (RSS_IPV4_12B << 1) | 0x1;
writel(val, base + RSS_CTRL0 + offset);
}
/* setup sideband data */
ret = xgene_cle_set_rss_sband(cle);
if (ret)
return ret;
/* setup indirection table */
ret = xgene_cle_set_rss_idt(pdata);
if (ret)
return ret;
return 0;
}
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];
struct xgene_cle_ptree_branch *br;
u32 def_qid, def_fpsel, pool_id;
struct xgene_cle_ptree *ptree;
struct xgene_cle_ptree_kn kn;
int ret;
struct xgene_cle_ptree_ewdn ptree_dn[] = {
{
/* PKT_TYPE_NODE */
.node_type = EWDN,
.last_node = 0,
.hdr_len_store = 0,
.hdr_len_store = 1,
.hdr_extn = NO_BYTE,
.byte_store = NO_BYTE,
.search_byte_store = NO_BYTE,
.result_pointer = DB_RES_DROP,
.num_branches = 1,
.num_branches = 2,
.branch = {
{
/* Allow all packet type */
/* IPV4 */
.valid = 0,
.next_packet_pointer = 0,
.next_packet_pointer = 22,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = PKT_PROT_NODE,
.next_branch = 0,
.data = 0x8,
.mask = 0xffff
},
{
.valid = 0,
.next_packet_pointer = 262,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = LAST_NODE,
.next_branch = 0,
.data = 0x0,
.mask = 0xffff
}
},
},
{
/* PKT_PROT_NODE */
.node_type = EWDN,
.last_node = 0,
.hdr_len_store = 1,
.hdr_extn = NO_BYTE,
.byte_store = NO_BYTE,
.search_byte_store = NO_BYTE,
.result_pointer = DB_RES_DROP,
.num_branches = 3,
.branch = {
{
/* TCP */
.valid = 1,
.next_packet_pointer = 26,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_TCP_NODE,
.next_branch = 0,
.data = 0x0600,
.mask = 0xffff
},
{
/* UDP */
.valid = 1,
.next_packet_pointer = 26,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_UDP_NODE,
.next_branch = 0,
.data = 0x1100,
.mask = 0xffff
},
{
.valid = 0,
.next_packet_pointer = 260,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = LAST_NODE,
.next_branch = 0,
.data = 0x0,
.mask = 0xffff
}
}
},
{
/* RSS_IPV4_TCP_NODE */
.node_type = EWDN,
.last_node = 0,
.hdr_len_store = 1,
.hdr_extn = NO_BYTE,
.byte_store = NO_BYTE,
.search_byte_store = BOTH_BYTES,
.result_pointer = DB_RES_DROP,
.num_branches = 6,
.branch = {
{
/* SRC IPV4 B01 */
.valid = 0,
.next_packet_pointer = 28,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_TCP_NODE,
.next_branch = 1,
.data = 0x0,
.mask = 0xffff
},
{
/* SRC IPV4 B23 */
.valid = 0,
.next_packet_pointer = 30,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_TCP_NODE,
.next_branch = 2,
.data = 0x0,
.mask = 0xffff
},
{
/* DST IPV4 B01 */
.valid = 0,
.next_packet_pointer = 32,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_TCP_NODE,
.next_branch = 3,
.data = 0x0,
.mask = 0xffff
},
{
/* DST IPV4 B23 */
.valid = 0,
.next_packet_pointer = 34,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_TCP_NODE,
.next_branch = 4,
.data = 0x0,
.mask = 0xffff
},
{
/* TCP SRC Port */
.valid = 0,
.next_packet_pointer = 36,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_TCP_NODE,
.next_branch = 5,
.data = 0x0,
.mask = 0xffff
},
{
/* TCP DST Port */
.valid = 0,
.next_packet_pointer = 256,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = LAST_NODE,
.next_branch = 0,
.data = 0x0,
.mask = 0xffff
}
}
},
{
/* RSS_IPV4_UDP_NODE */
.node_type = EWDN,
.last_node = 0,
.hdr_len_store = 1,
.hdr_extn = NO_BYTE,
.byte_store = NO_BYTE,
.search_byte_store = BOTH_BYTES,
.result_pointer = DB_RES_DROP,
.num_branches = 6,
.branch = {
{
/* SRC IPV4 B01 */
.valid = 0,
.next_packet_pointer = 28,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_UDP_NODE,
.next_branch = 1,
.data = 0x0,
.mask = 0xffff
},
{
/* SRC IPV4 B23 */
.valid = 0,
.next_packet_pointer = 30,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_UDP_NODE,
.next_branch = 2,
.data = 0x0,
.mask = 0xffff
},
{
/* DST IPV4 B01 */
.valid = 0,
.next_packet_pointer = 32,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_UDP_NODE,
.next_branch = 3,
.data = 0x0,
.mask = 0xffff
},
{
/* DST IPV4 B23 */
.valid = 0,
.next_packet_pointer = 34,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_UDP_NODE,
.next_branch = 4,
.data = 0x0,
.mask = 0xffff
},
{
/* TCP SRC Port */
.valid = 0,
.next_packet_pointer = 36,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
.next_node = RSS_IPV4_UDP_NODE,
.next_branch = 5,
.data = 0x0,
.mask = 0xffff
},
{
/* TCP DST Port */
.valid = 0,
.next_packet_pointer = 256,
.jump_bw = JMP_FW,
.jump_rel = JMP_ABS,
.operation = EQT,
@ -294,7 +656,7 @@ static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)
/* LAST NODE */
.node_type = EWDN,
.last_node = 1,
.hdr_len_store = 0,
.hdr_len_store = 1,
.hdr_extn = NO_BYTE,
.byte_store = NO_BYTE,
.search_byte_store = NO_BYTE,
@ -318,6 +680,20 @@ static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)
ptree = &enet_cle->ptree;
ptree->start_pkt = 12; /* Ethertype */
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
ret = xgene_cle_setup_rss(pdata);
if (ret) {
netdev_err(pdata->ndev, "RSS initialization failed\n");
return ret;
}
} else {
br = &ptree_dn[PKT_PROT_NODE].branch[0];
br->valid = 0;
br->next_packet_pointer = 260;
br->next_node = LAST_NODE;
br->data = 0x0000;
br->mask = 0xffff;
}
def_qid = xgene_enet_dst_ring_num(pdata->rx_ring);
pool_id = pdata->rx_ring->buf_pool->id;

View File

@ -34,6 +34,7 @@
#define SPPTR0 0x0104
#define DFCLSRESDBPTR0 0x0108
#define DFCLSRESDB00 0x010c
#define RSS_CTRL0 0x0000013c
#define CLE_CMD_TO 10 /* ms */
#define CLE_PKTRAM_SIZE 256 /* bytes */
@ -98,6 +99,9 @@
enum xgene_cle_ptree_nodes {
PKT_TYPE_NODE,
PKT_PROT_NODE,
RSS_IPV4_TCP_NODE,
RSS_IPV4_UDP_NODE,
LAST_NODE,
MAX_NODES
};
@ -137,6 +141,8 @@ enum xgene_cle_parser {
#define XGENE_CLE_DRAM(type) (((type) & 0xf) << 28)
enum xgene_cle_dram_type {
PKT_RAM,
RSS_IDT,
RSS_IPV4_HASH_SKEY,
PTREE_RAM = 0xc,
AVL_RAM,
DB_RAM
@ -150,6 +156,22 @@ enum xgene_cle_cmd_type {
CLE_CMD_AVL_SRCH = 32
};
enum xgene_cle_ipv4_rss_hashtype {
RSS_IPV4_8B,
RSS_IPV4_12B,
};
enum xgene_cle_prot_type {
XGENE_CLE_TCP,
XGENE_CLE_UDP,
XGENE_CLE_ESP,
XGENE_CLE_OTHER
};
enum xgene_cle_prot_version {
XGENE_CLE_IPV4,
};
enum xgene_cle_ptree_dbptrs {
DB_RES_DROP,
DB_RES_DEF,
@ -157,6 +179,25 @@ enum xgene_cle_ptree_dbptrs {
DB_MAX_PTRS
};
/* RSS sideband signal info */
#define SB_IPFRAG_POS 0
#define SB_IPFRAG_LEN 1
#define SB_IPPROT_POS 1
#define SB_IPPROT_LEN 2
#define SB_IPVER_POS 3
#define SB_IPVER_LEN 1
#define SB_HDRLEN_POS 4
#define SB_HDRLEN_LEN 12
/* RSS indirection table */
#define XGENE_CLE_IDT_ENTRIES 128
#define IDT_DSTQID_POS 0
#define IDT_DSTQID_LEN 12
#define IDT_FPSEL_POS 12
#define IDT_FPSEL_LEN 4
#define IDT_NFPSEL_POS 16
#define IDT_NFPSEL_LEN 4
struct xgene_cle_ptree_branch {
bool valid;
u16 next_packet_pointer;