aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ixl/ixl_pf_qmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ixl/ixl_pf_qmgr.c')
-rw-r--r--sys/dev/ixl/ixl_pf_qmgr.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/sys/dev/ixl/ixl_pf_qmgr.c b/sys/dev/ixl/ixl_pf_qmgr.c
new file mode 100644
index 000000000000..f2842e584dc4
--- /dev/null
+++ b/sys/dev/ixl/ixl_pf_qmgr.c
@@ -0,0 +1,308 @@
+/******************************************************************************
+
+ Copyright (c) 2013-2015, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+/*$FreeBSD$*/
+
+
+#include "ixl_pf_qmgr.h"
+
+static int ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num);
+
+int
+ixl_pf_qmgr_init(struct ixl_pf_qmgr *qmgr, u16 num_queues)
+{
+ if (num_queues < 1)
+ return (EINVAL);
+
+ qmgr->num_queues = num_queues;
+ qmgr->qinfo = malloc(num_queues * sizeof(struct ixl_pf_qmgr_qinfo),
+ M_IXL, M_ZERO | M_WAITOK);
+ if (qmgr->qinfo == NULL)
+ return ENOMEM;
+
+ return (0);
+}
+
+int
+ixl_pf_qmgr_alloc_contiguous(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
+{
+ int i;
+ int avail;
+ int block_start;
+ u16 alloc_size;
+
+ if (qtag == NULL || num < 1)
+ return (EINVAL);
+
+ /* We have to allocate in power-of-two chunks, so get next power of two */
+ alloc_size = (u16)next_power_of_two(num);
+
+ /* Don't try if there aren't enough queues */
+ avail = ixl_pf_qmgr_get_num_free(qmgr);
+ if (avail < alloc_size)
+ return (ENOSPC);
+
+ block_start = ixl_pf_qmgr_find_free_contiguous_block(qmgr, alloc_size);
+ if (block_start < 0)
+ return (ENOSPC);
+
+ /* Mark queues as allocated */
+ for (i = block_start; i < block_start + alloc_size; i++)
+ qmgr->qinfo[i].allocated = true;
+
+ bzero(qtag, sizeof(*qtag));
+ qtag->qmgr = qmgr;
+ qtag->type = IXL_PF_QALLOC_CONTIGUOUS;
+ qtag->qidx[0] = block_start;
+ qtag->num_allocated = num;
+ qtag->num_active = alloc_size;
+
+ return (0);
+}
+
+/*
+ * NB: indices is u16 because this is the queue index width used in the Add VSI AQ command
+ */
+int
+ixl_pf_qmgr_alloc_scattered(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
+{
+ int i;
+ int avail, count = 0;
+ u16 alloc_size;
+
+ if (qtag == NULL || num < 1 || num > 16)
+ return (EINVAL);
+
+ /* We have to allocate in power-of-two chunks, so get next power of two */
+ alloc_size = (u16)next_power_of_two(num);
+
+ avail = ixl_pf_qmgr_get_num_free(qmgr);
+ if (avail < alloc_size)
+ return (ENOSPC);
+
+ bzero(qtag, sizeof(*qtag));
+ qtag->qmgr = qmgr;
+ qtag->type = IXL_PF_QALLOC_SCATTERED;
+ qtag->num_active = num;
+ qtag->num_allocated = alloc_size;
+
+ for (i = 0; i < qmgr->num_queues; i++) {
+ if (!qmgr->qinfo[i].allocated) {
+ qtag->qidx[count] = i;
+ count++;
+ qmgr->qinfo[i].allocated = true;
+ if (count == alloc_size)
+ return (0);
+ }
+ }
+
+ // Shouldn't get here
+ return (EDOOFUS);
+}
+
+int
+ixl_pf_qmgr_release(struct ixl_pf_qmgr *qmgr, struct ixl_pf_qtag *qtag)
+{
+ u16 i, qidx;
+
+ if (qtag == NULL)
+ return (EINVAL);
+
+ if (qtag->type == IXL_PF_QALLOC_SCATTERED) {
+ for (i = 0; i < qtag->num_allocated; i++) {
+ qidx = qtag->qidx[i];
+ bzero(&qmgr->qinfo[qidx], sizeof(qmgr->qinfo[qidx]));
+ }
+ } else {
+ u16 first_index = qtag->qidx[0];
+ for (i = first_index; i < first_index + qtag->num_allocated; i++)
+ bzero(&qmgr->qinfo[i], sizeof(qmgr->qinfo[qidx]));
+ }
+
+ qtag->qmgr = NULL;
+ return (0);
+}
+
+int
+ixl_pf_qmgr_get_num_queues(struct ixl_pf_qmgr *qmgr)
+{
+ return (qmgr->num_queues);
+}
+
+/*
+ * ERJ: This assumes the info array isn't longer than INT_MAX.
+ * This assumption might cause a y3k bug or something, I'm sure.
+ */
+int
+ixl_pf_qmgr_get_num_free(struct ixl_pf_qmgr *qmgr)
+{
+ int count = 0;
+
+ for (int i = 0; i < qmgr->num_queues; i++) {
+ if (!qmgr->qinfo[i].allocated)
+ count++;
+ }
+
+ return (count);
+}
+
+int
+ixl_pf_qmgr_get_first_free(struct ixl_pf_qmgr *qmgr, u16 start)
+{
+ int i;
+
+ if (start > qmgr->num_queues - 1)
+ return (-EINVAL);
+
+ for (i = start; i < qmgr->num_queues; i++) {
+ if (qmgr->qinfo[i].allocated)
+ continue;
+ else
+ return (i);
+ }
+
+ // No free queues
+ return (-ENOSPC);
+}
+
+void
+ixl_pf_qmgr_destroy(struct ixl_pf_qmgr *qmgr)
+{
+ free(qmgr->qinfo, M_IXL);
+ qmgr->qinfo = NULL;
+}
+
+void
+ixl_pf_qmgr_mark_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
+{
+ MPASS(qtag != NULL);
+
+ struct ixl_pf_qmgr *qmgr = qtag->qmgr;
+ u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
+ if (tx)
+ qmgr->qinfo[pf_qidx].tx_enabled = true;
+ else
+ qmgr->qinfo[pf_qidx].rx_enabled = true;
+}
+
+void
+ixl_pf_qmgr_mark_queue_disabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
+{
+ MPASS(qtag != NULL);
+
+ struct ixl_pf_qmgr *qmgr = qtag->qmgr;
+ u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
+ if (tx)
+ qmgr->qinfo[pf_qidx].tx_enabled = false;
+ else
+ qmgr->qinfo[pf_qidx].rx_enabled = false;
+}
+
+void
+ixl_pf_qmgr_mark_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
+{
+ MPASS(qtag != NULL);
+
+ struct ixl_pf_qmgr *qmgr = qtag->qmgr;
+ u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
+ if (tx)
+ qmgr->qinfo[pf_qidx].tx_configured = true;
+ else
+ qmgr->qinfo[pf_qidx].rx_configured = true;
+}
+
+bool
+ixl_pf_qmgr_is_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
+{
+ MPASS(qtag != NULL);
+
+ struct ixl_pf_qmgr *qmgr = qtag->qmgr;
+ u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
+ if (tx)
+ return (qmgr->qinfo[pf_qidx].tx_enabled);
+ else
+ return (qmgr->qinfo[pf_qidx].rx_enabled);
+}
+
+bool
+ixl_pf_qmgr_is_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
+{
+ MPASS(qtag != NULL);
+
+ struct ixl_pf_qmgr *qmgr = qtag->qmgr;
+ u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
+ if (tx)
+ return (qmgr->qinfo[pf_qidx].tx_configured);
+ else
+ return (qmgr->qinfo[pf_qidx].rx_configured);
+}
+
+u16
+ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag *qtag, u16 index)
+{
+ MPASS(index < qtag->num_allocated);
+
+ if (qtag->type == IXL_PF_QALLOC_CONTIGUOUS)
+ return qtag->qidx[0] + index;
+ else
+ return qtag->qidx[index];
+}
+
+/* Static Functions */
+
+static int
+ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num)
+{
+ int i;
+ int count = 0;
+ bool block_started = false;
+ int possible_start;
+
+ for (i = 0; i < qmgr->num_queues; i++) {
+ if (!qmgr->qinfo[i].allocated) {
+ if (!block_started) {
+ block_started = true;
+ possible_start = i;
+ }
+ count++;
+ if (count == num)
+ return (possible_start);
+ } else { /* this queue is already allocated */
+ block_started = false;
+ count = 0;
+ }
+ }
+
+ /* Can't find a contiguous block of the requested size */
+ return (-1);
+}
+