net/octeontx/base: add base PKO operations

PKO is the packet output processing unit, which receives the packet
from the core and sends to the BGX interface. This patch adds the
basic PKO operation like open, close, start and stop. These operations
are implemented through mailbox messages and kernel PF driver being the
server to process the message with the logical port identifier.

Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
This commit is contained in:
Jerin Jacob 2017-10-08 18:14:13 +05:30 committed by Ferruh Yigit
parent 6d28968ed1
commit cad78ca238
2 changed files with 345 additions and 0 deletions

View File

@ -77,6 +77,334 @@ struct octeontx_pko_vf_ctl_s {
static struct octeontx_pko_vf_ctl_s pko_vf_ctl;
static void *
octeontx_pko_dq_vf_bar0(uint16_t txq)
{
int vf_ix;
vf_ix = txq / PKO_VF_NUM_DQ;
return pko_vf_ctl.pko[vf_ix].bar0;
}
static int
octeontx_pko_dq_gdq(uint16_t txq)
{
return txq % PKO_VF_NUM_DQ;
}
/**
* Open a PKO DQ.
*/
static inline
int octeontx_pko_dq_open(uint16_t txq)
{
unsigned int reg_off;
uint8_t *vf_bar0;
uint64_t rtn;
int gdq;
vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
gdq = octeontx_pko_dq_gdq(txq);
if (unlikely(gdq < 0 || vf_bar0 == NULL))
return -EINVAL;
*(volatile int64_t*)(pko_vf_ctl.fc_ctl + txq) =
PKO_DQ_FC_DEPTH_PAGES - PKO_DQ_FC_SKID;
rte_wmb();
octeontx_write64(PKO_DQ_FC_DEPTH_PAGES,
vf_bar0 + PKO_VF_DQ_FC_STATUS(gdq));
/* Set the register to return descriptor (packet) count as DEPTH */
/* KIND=1, NCB_QUERY_RSP=0 */
octeontx_write64(1ull << PKO_DQ_KIND_BIT,
vf_bar0 + PKO_VF_DQ_WM_CTL(gdq));
reg_off = PKO_VF_DQ_OP_OPEN(gdq);
rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
/* PKO_DQOP_E::OPEN */
if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x1)
return -EIO;
switch (rtn >> PKO_DQ_STATUS_BIT) {
case 0xC: /* DQALREADYCREATED */
case 0x0: /* PASS */
break;
default:
return -EIO;
}
/* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
return rtn & ((1ull << PKO_DQ_OP_BIT) - 1);
}
/**
* Close a PKO DQ
* Flush all packets pending.
*/
static inline
int octeontx_pko_dq_close(uint16_t txq)
{
unsigned int reg_off;
uint8_t *vf_bar0;
uint64_t rtn;
int res;
vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
res = octeontx_pko_dq_gdq(txq);
if (unlikely(res < 0 || vf_bar0 == NULL))
return -EINVAL;
reg_off = PKO_VF_DQ_OP_CLOSE(res);
rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
/* PKO_DQOP_E::CLOSE */
if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x2)
return -EIO;
switch (rtn >> PKO_DQ_STATUS_BIT) {
case 0xD: /* DQNOTCREATED */
case 0x0: /* PASS */
break;
default:
return -EIO;
}
res = rtn & ((1ull << PKO_DQ_OP_BIT) - 1); /* DEPTH */
return res;
}
/* Flush all packets pending on a DQ */
static inline
int octeontx_pko_dq_drain(uint16_t txq)
{
unsigned int gdq;
uint8_t *vf_bar0;
uint64_t reg;
int res, timo = PKO_DQ_DRAIN_TO;
vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
res = octeontx_pko_dq_gdq(txq);
gdq = res;
/* DRAIN=1, DRAIN_NULL_LINK=0, SW_XOFF=1 */
octeontx_write64(0x3, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
/* Wait until buffers leave DQs */
reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
while (reg && timo > 0) {
rte_delay_us(100);
timo--;
reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
}
/* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
return reg;
}
static inline int
octeontx_pko_dq_range_lookup(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
unsigned int dq_num, unsigned int dq_from)
{
unsigned int dq, dq_cnt;
unsigned int dq_base;
dq_cnt = 0;
dq = dq_from;
while (dq < RTE_DIM(ctl->dq_map)) {
dq_base = dq;
dq_cnt = 0;
while (ctl->dq_map[dq].chanid == ~chanid &&
dq < RTE_DIM(ctl->dq_map)) {
dq_cnt++;
if (dq_cnt == dq_num)
return dq_base;
dq++;
}
dq++;
}
return -1;
}
static inline void
octeontx_pko_dq_range_assign(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
unsigned int dq_base, unsigned int dq_num)
{
unsigned int dq, dq_cnt;
dq_cnt = 0;
while (dq_cnt < dq_num) {
dq = dq_base + dq_cnt;
octeontx_log_dbg("DQ# %u assigned to CHAN# %" PRIx64 "", dq,
chanid);
ctl->dq_map[dq].chanid = ~chanid;
dq_cnt++;
}
}
static inline int
octeontx_pko_dq_claim(struct octeontx_pko_vf_ctl_s *ctl, unsigned int dq_base,
unsigned int dq_num, uint64_t chanid)
{
const uint64_t null_chanid = ~0ull;
int dq;
rte_spinlock_lock(&ctl->lock);
dq = octeontx_pko_dq_range_lookup(ctl, null_chanid, dq_num, dq_base);
if (dq < 0 || (unsigned int)dq != dq_base) {
rte_spinlock_unlock(&ctl->lock);
return -1;
}
octeontx_pko_dq_range_assign(ctl, chanid, dq_base, dq_num);
rte_spinlock_unlock(&ctl->lock);
return 0;
}
static inline int
octeontx_pko_dq_free(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
{
const uint64_t null_chanid = ~0ull;
unsigned int dq = 0, dq_cnt = 0;
rte_spinlock_lock(&ctl->lock);
while (dq < RTE_DIM(ctl->dq_map)) {
if (ctl->dq_map[dq].chanid == ~chanid) {
ctl->dq_map[dq].chanid = ~null_chanid;
dq_cnt++;
}
dq++;
}
rte_spinlock_unlock(&ctl->lock);
return dq_cnt > 0 ? 0 : -EINVAL;
}
int
octeontx_pko_channel_open(int dq_base, int dq_num, int chanid)
{
struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
int res;
res = octeontx_pko_dq_claim(ctl, dq_base, dq_num, chanid);
if (res < 0)
return -1;
return 0;
}
int
octeontx_pko_channel_close(int chanid)
{
struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
int res;
res = octeontx_pko_dq_free(ctl, chanid);
if (res < 0)
return -1;
return 0;
}
static inline int
octeontx_pko_chan_start(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
{
unsigned int dq_vf;
unsigned int dq, dq_cnt;
dq_cnt = 0;
dq = 0;
while (dq < RTE_DIM(ctl->dq_map)) {
dq_vf = dq / PKO_VF_NUM_DQ;
if (!ctl->pko[dq_vf].bar0) {
dq += PKO_VF_NUM_DQ;
continue;
}
if (ctl->dq_map[dq].chanid != ~chanid) {
dq++;
continue;
}
if (octeontx_pko_dq_open(dq) < 0)
break;
dq_cnt++;
dq++;
}
return dq_cnt;
}
int
octeontx_pko_channel_start(int chanid)
{
struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
int dq_cnt;
dq_cnt = octeontx_pko_chan_start(ctl, chanid);
if (dq_cnt < 0)
return -1;
return dq_cnt;
}
static inline int
octeontx_pko_chan_stop(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
{
unsigned int dq, dq_cnt, dq_vf;
int res;
dq_cnt = 0;
dq = 0;
while (dq < RTE_DIM(ctl->dq_map)) {
dq_vf = dq / PKO_VF_NUM_DQ;
if (!ctl->pko[dq_vf].bar0) {
dq += PKO_VF_NUM_DQ;
continue;
}
if (ctl->dq_map[dq].chanid != ~chanid) {
dq++;
continue;
}
res = octeontx_pko_dq_drain(dq);
if (res > 0)
octeontx_log_err("draining DQ%d, buffers left: %x",
dq, res);
res = octeontx_pko_dq_close(dq);
if (res < 0)
octeontx_log_err("closing DQ%d failed\n", dq);
dq_cnt++;
dq++;
}
return dq_cnt;
}
int
octeontx_pko_channel_stop(int chanid)
{
struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
octeontx_pko_chan_stop(ctl, chanid);
return 0;
}
static void
octeontx_pkovf_setup(void)
{

View File

@ -60,4 +60,21 @@
#define PKO_VF_DQ_OP_CLOSE(gdq) (0x001200 | (gdq) << 17)
#define PKO_VF_DQ_OP_QUERY(gdq) (0x001300 | (gdq) << 17)
/* pko_send_hdr_s + pko_send_link */
#define PKO_CMD_SZ (2 << 1)
#define PKO_SEND_GATHER_SUBDC (0x0ull << 60)
#define PKO_SEND_GATHER_LDTYPE(x) ((x) << 58)
#define PKO_SEND_GATHER_GAUAR(x) ((x) << 24)
typedef struct octeontx_dq_s {
void *lmtline_va;
void *ioreg_va;
void *fc_status_va;
} octeontx_dq_t;
int octeontx_pko_channel_open(int dq_base, int dq_num, int chanid);
int octeontx_pko_channel_close(int chanid);
int octeontx_pko_channel_start(int chanid);
int octeontx_pko_channel_stop(int chanid);
#endif /* __OCTEONTX_PKO_H__ */