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:
parent
6d28968ed1
commit
cad78ca238
@ -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)
|
||||
{
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user