Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixl/ixl_pf_qmgr.c
- This file was added.
/****************************************************************************** | |||||
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); | |||||
} | |||||