/********************************************************************** * Author: Cavium, Inc. * * Contact: support@cavium.com * Please include "LiquidIO" in the subject. * * Copyright (c) 2003-2016 Cavium, Inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as * published by the Free Software Foundation. * * This file is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. See the GNU General Public License for more details.
***********************************************************************/ #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> #include"liquidio_common.h" #include"octeon_droq.h" #include"octeon_iq.h" #include"response_manager.h" #include"octeon_device.h" #include"cn23xx_vf_device.h" #include"octeon_main.h" #include"octeon_mailbox.h"
u32 cn23xx_vf_get_oq_ticks(struct octeon_device *oct, u32 time_intr_in_us)
{ /* This gives the SLI clock per microsec */
u32 oqticks_per_us = (u32)oct->pfvf_hsword.coproc_tics_per_us;
/* This gives the clock cycles per millisecond */
oqticks_per_us *= 1000;
/* This gives the oq ticks (1024 core clock cycles) per millisecond */
oqticks_per_us /= 1024;
/* time_intr is in microseconds. The next 2 steps gives the oq ticks * corressponding to time_intr.
*/
oqticks_per_us *= time_intr_in_us;
oqticks_per_us /= 1000;
for (q_no = 0; q_no < num_queues; q_no++) { /* set RST bit to 1. This bit applies to both IQ and OQ */
d64 = octeon_read_csr64(oct,
CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no));
d64 |= CN23XX_PKT_INPUT_CTL_RST;
octeon_write_csr64(oct, CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no),
d64);
}
/* wait until the RST bit is clear or the RST and QUIET bits are set */ for (q_no = 0; q_no < num_queues; q_no++) {
u64 reg_val = octeon_read_csr64(oct,
CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no)); while ((READ_ONCE(reg_val) & CN23XX_PKT_INPUT_CTL_RST) &&
!(READ_ONCE(reg_val) & CN23XX_PKT_INPUT_CTL_QUIET) &&
loop) {
WRITE_ONCE(reg_val, octeon_read_csr64(
oct, CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no)));
loop--;
} if (!loop) {
dev_err(&oct->pci_dev->dev, "clearing the reset reg failed or setting the quiet reg failed for qno: %u\n",
q_no); return -1;
}
WRITE_ONCE(reg_val, READ_ONCE(reg_val) &
~CN23XX_PKT_INPUT_CTL_RST);
octeon_write_csr64(oct, CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no),
READ_ONCE(reg_val));
WRITE_ONCE(reg_val, octeon_read_csr64(
oct, CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no))); if (READ_ONCE(reg_val) & CN23XX_PKT_INPUT_CTL_RST) {
dev_err(&oct->pci_dev->dev, "clearing the reset failed for qno: %u\n",
q_no);
ret_val = -1;
}
}
/* Write the start of the input queue's ring and its size */
octeon_write_csr64(oct, CN23XX_VF_SLI_IQ_BASE_ADDR64(iq_no),
iq->base_addr_dma);
octeon_write_csr(oct, CN23XX_VF_SLI_IQ_SIZE(iq_no), iq->max_count);
/* Store the current instruction counter (used in flush_iq * calculation)
*/
pkt_in_done = readq(iq->inst_cnt_reg);
if (oct->msix_on) { /* Set CINT_ENB to enable IQ interrupt */
writeq((pkt_in_done | CN23XX_INTR_CINT_ENB),
iq->inst_cnt_reg);
}
iq->reset_instr_cnt = 0;
}
/* Get the mapped address of the pkt_sent and pkts_credit regs */
droq->pkts_sent_reg =
(u8 *)oct->mmio[0].hw_addr + CN23XX_VF_SLI_OQ_PKTS_SENT(oq_no);
droq->pkts_credit_reg =
(u8 *)oct->mmio[0].hw_addr + CN23XX_VF_SLI_OQ_PKTS_CREDIT(oq_no);
}
/* per HRM, rings can only be disabled via reset operation, * NOT via SLI_PKT()_INPUT/OUTPUT_CONTROL[ENB]
*/ if (num_queues < oct->num_oqs)
num_queues = oct->num_oqs;
memcpy((uint8_t *)&oct->pfvf_hsword, cmd->msg.s.params,
CN23XX_MAILBOX_MSGPARAM_SIZE); if (cmd->recv_len > 1) {
major = ((struct lio_version *)(cmd->data))->major;
major = major << 16;
}
vfmajor = LIQUIDIO_BASE_MAJOR_VERSION;
pfmajor = ret >> 16; if (pfmajor != vfmajor) {
dev_err(&oct->pci_dev->dev, "VF Liquidio driver (major version %d) is not compatible with Liquidio PF driver (major version %d)\n",
vfmajor, pfmajor); return 1;
}
dev_dbg(&oct->pci_dev->dev, "VF Liquidio driver (major version %d), Liquidio PF driver (major version %d)\n",
vfmajor, pfmajor);
dev_dbg(&oct->pci_dev->dev, "got data from pf pkind is %d\n",
oct->pfvf_hsword.pkind);
/* If our device has interrupted, then proceed. Also check * for all f's if interrupt was triggered on an error * and the PCI read fails.
*/ if (!pkts_sent || (pkts_sent == 0xFFFFFFFFFFFFFFFFULL)) return ret;
/* Write count reg in sli_pkt_cnts to clear these int. */ if ((pkts_sent & CN23XX_INTR_PO_INT) ||
(pkts_sent & CN23XX_INTR_PI_INT)) { if (pkts_sent & CN23XX_INTR_PO_INT)
ret |= MSIX_PO_INT;
}
if (pkts_sent & CN23XX_INTR_PI_INT) /* We will clear the count when we update the read_index. */
ret |= MSIX_PI_INT;
if (pkts_sent & CN23XX_INTR_MBOX_INT) {
cn23xx_handle_vf_mbox_intr(ioq_vector);
ret |= MSIX_MBOX_INT;
}
/* Modulo of the new index with the IQ size will give us * the new index. The iq->reset_instr_cnt is always zero for * cn23xx, so no extra adjustments are needed.
*/
new_idx = (iq->octeon_read_index +
(u32)(last_done & CN23XX_PKT_IN_DONE_CNT_MASK)) %
iq->max_count;
if (intr_flag & OCTEON_OUTPUT_INTR) { for (q_no = 0; q_no < oct->num_oqs; q_no++) { /* Set up interrupt packet and time thresholds * for all the OQs
*/
time_threshold = cn23xx_vf_get_oq_ticks(
oct, (u32)CFG_GET_OQ_INTR_TIME(cn23xx->conf));
cn23xx->conf = oct_get_config_info(oct, LIO_23XX); if (!cn23xx->conf) {
dev_err(&oct->pci_dev->dev, "%s No Config found for CN23XX\n",
__func__);
octeon_unmap_pci_barx(oct, 0); return 1;
}
if (oct->sriov_info.rings_per_vf > rings_per_vf) {
dev_warn(&oct->pci_dev->dev, "num_queues:%d greater than PF configured rings_per_vf:%d. Reducing to %d.\n",
oct->sriov_info.rings_per_vf, rings_per_vf,
rings_per_vf);
oct->sriov_info.rings_per_vf = rings_per_vf;
} else { if (rings_per_vf > num_present_cpus()) {
dev_warn(&oct->pci_dev->dev, "PF configured rings_per_vf:%d greater than num_cpu:%d. Using rings_per_vf:%d equal to num cpus\n",
rings_per_vf,
num_present_cpus(),
num_present_cpus());
oct->sriov_info.rings_per_vf =
num_present_cpus();
} else {
oct->sriov_info.rings_per_vf = rings_per_vf;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.