xref: /freebsd/sys/dev/ixl/ixl_pf_qmgr.c (revision 71625ec9ad2a9bc8c09784fbd23b759830e0ee5f)
14294f337SSean Bruno /******************************************************************************
24294f337SSean Bruno 
3f4cc2d17SEric Joyner   Copyright (c) 2013-2018, Intel Corporation
44294f337SSean Bruno   All rights reserved.
54294f337SSean Bruno 
64294f337SSean Bruno   Redistribution and use in source and binary forms, with or without
74294f337SSean Bruno   modification, are permitted provided that the following conditions are met:
84294f337SSean Bruno 
94294f337SSean Bruno    1. Redistributions of source code must retain the above copyright notice,
104294f337SSean Bruno       this list of conditions and the following disclaimer.
114294f337SSean Bruno 
124294f337SSean Bruno    2. Redistributions in binary form must reproduce the above copyright
134294f337SSean Bruno       notice, this list of conditions and the following disclaimer in the
144294f337SSean Bruno       documentation and/or other materials provided with the distribution.
154294f337SSean Bruno 
164294f337SSean Bruno    3. Neither the name of the Intel Corporation nor the names of its
174294f337SSean Bruno       contributors may be used to endorse or promote products derived from
184294f337SSean Bruno       this software without specific prior written permission.
194294f337SSean Bruno 
204294f337SSean Bruno   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
214294f337SSean Bruno   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224294f337SSean Bruno   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234294f337SSean Bruno   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
244294f337SSean Bruno   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
254294f337SSean Bruno   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
264294f337SSean Bruno   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
274294f337SSean Bruno   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
284294f337SSean Bruno   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
294294f337SSean Bruno   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
304294f337SSean Bruno   POSSIBILITY OF SUCH DAMAGE.
314294f337SSean Bruno 
324294f337SSean Bruno ******************************************************************************/
334294f337SSean Bruno 
344294f337SSean Bruno 
354294f337SSean Bruno #include "ixl_pf_qmgr.h"
364294f337SSean Bruno 
374294f337SSean Bruno static int	ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num);
384294f337SSean Bruno 
394294f337SSean Bruno int
ixl_pf_qmgr_init(struct ixl_pf_qmgr * qmgr,u16 num_queues)404294f337SSean Bruno ixl_pf_qmgr_init(struct ixl_pf_qmgr *qmgr, u16 num_queues)
414294f337SSean Bruno {
424294f337SSean Bruno 	if (num_queues < 1)
434294f337SSean Bruno 		return (EINVAL);
444294f337SSean Bruno 
454294f337SSean Bruno 	qmgr->num_queues = num_queues;
464294f337SSean Bruno 	qmgr->qinfo = malloc(num_queues * sizeof(struct ixl_pf_qmgr_qinfo),
47*77c1fcecSEric Joyner 	    M_IXL, M_ZERO | M_NOWAIT);
484294f337SSean Bruno 	if (qmgr->qinfo == NULL)
494294f337SSean Bruno 		return ENOMEM;
504294f337SSean Bruno 
514294f337SSean Bruno 	return (0);
524294f337SSean Bruno }
534294f337SSean Bruno 
544294f337SSean Bruno int
ixl_pf_qmgr_alloc_contiguous(struct ixl_pf_qmgr * qmgr,u16 num,struct ixl_pf_qtag * qtag)554294f337SSean Bruno ixl_pf_qmgr_alloc_contiguous(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
564294f337SSean Bruno {
574294f337SSean Bruno 	int i;
584294f337SSean Bruno 	int avail;
594294f337SSean Bruno 	int block_start;
604294f337SSean Bruno 	u16 alloc_size;
614294f337SSean Bruno 
624294f337SSean Bruno 	if (qtag == NULL || num < 1)
634294f337SSean Bruno 		return (EINVAL);
644294f337SSean Bruno 
654294f337SSean Bruno 	/* We have to allocate in power-of-two chunks, so get next power of two */
664294f337SSean Bruno 	alloc_size = (u16)next_power_of_two(num);
674294f337SSean Bruno 
684294f337SSean Bruno 	/* Don't try if there aren't enough queues */
694294f337SSean Bruno 	avail = ixl_pf_qmgr_get_num_free(qmgr);
704294f337SSean Bruno 	if (avail < alloc_size)
714294f337SSean Bruno 		return (ENOSPC);
724294f337SSean Bruno 
734294f337SSean Bruno 	block_start = ixl_pf_qmgr_find_free_contiguous_block(qmgr, alloc_size);
744294f337SSean Bruno 	if (block_start < 0)
754294f337SSean Bruno 		return (ENOSPC);
764294f337SSean Bruno 
774294f337SSean Bruno 	/* Mark queues as allocated */
784294f337SSean Bruno 	for (i = block_start; i < block_start + alloc_size; i++)
794294f337SSean Bruno 		qmgr->qinfo[i].allocated = true;
804294f337SSean Bruno 
814294f337SSean Bruno 	bzero(qtag, sizeof(*qtag));
824294f337SSean Bruno 	qtag->qmgr = qmgr;
834294f337SSean Bruno 	qtag->type = IXL_PF_QALLOC_CONTIGUOUS;
844294f337SSean Bruno 	qtag->qidx[0] = block_start;
851031d839SEric Joyner 	qtag->num_allocated = alloc_size;
861031d839SEric Joyner 	qtag->num_active = num;
874294f337SSean Bruno 
884294f337SSean Bruno 	return (0);
894294f337SSean Bruno }
904294f337SSean Bruno 
914294f337SSean Bruno /*
924294f337SSean Bruno  * NB: indices is u16 because this is the queue index width used in the Add VSI AQ command
934294f337SSean Bruno  */
944294f337SSean Bruno int
ixl_pf_qmgr_alloc_scattered(struct ixl_pf_qmgr * qmgr,u16 num,struct ixl_pf_qtag * qtag)954294f337SSean Bruno ixl_pf_qmgr_alloc_scattered(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
964294f337SSean Bruno {
974294f337SSean Bruno 	int i;
984294f337SSean Bruno 	int avail, count = 0;
994294f337SSean Bruno 	u16 alloc_size;
1004294f337SSean Bruno 
1014294f337SSean Bruno 	if (qtag == NULL || num < 1 || num > 16)
1024294f337SSean Bruno 		return (EINVAL);
1034294f337SSean Bruno 
1044294f337SSean Bruno 	/* We have to allocate in power-of-two chunks, so get next power of two */
1054294f337SSean Bruno 	alloc_size = (u16)next_power_of_two(num);
1064294f337SSean Bruno 
1074294f337SSean Bruno 	avail = ixl_pf_qmgr_get_num_free(qmgr);
1084294f337SSean Bruno 	if (avail < alloc_size)
1094294f337SSean Bruno 		return (ENOSPC);
1104294f337SSean Bruno 
1114294f337SSean Bruno 	bzero(qtag, sizeof(*qtag));
1124294f337SSean Bruno 	qtag->qmgr = qmgr;
1134294f337SSean Bruno 	qtag->type = IXL_PF_QALLOC_SCATTERED;
1144294f337SSean Bruno 	qtag->num_active = num;
1154294f337SSean Bruno 	qtag->num_allocated = alloc_size;
1164294f337SSean Bruno 
1174294f337SSean Bruno 	for (i = 0; i < qmgr->num_queues; i++) {
1184294f337SSean Bruno 		if (!qmgr->qinfo[i].allocated) {
1194294f337SSean Bruno 			qtag->qidx[count] = i;
1204294f337SSean Bruno 			count++;
1214294f337SSean Bruno 			qmgr->qinfo[i].allocated = true;
1224294f337SSean Bruno 			if (count == alloc_size)
1234294f337SSean Bruno 				return (0);
1244294f337SSean Bruno 		}
1254294f337SSean Bruno 	}
1264294f337SSean Bruno 
1274294f337SSean Bruno 	// Shouldn't get here
1284294f337SSean Bruno 	return (EDOOFUS);
1294294f337SSean Bruno }
1304294f337SSean Bruno 
1314294f337SSean Bruno int
ixl_pf_qmgr_release(struct ixl_pf_qmgr * qmgr,struct ixl_pf_qtag * qtag)1324294f337SSean Bruno ixl_pf_qmgr_release(struct ixl_pf_qmgr *qmgr, struct ixl_pf_qtag *qtag)
1334294f337SSean Bruno {
1344294f337SSean Bruno 	u16 i, qidx;
1354294f337SSean Bruno 
1364294f337SSean Bruno 	if (qtag == NULL)
1374294f337SSean Bruno 		return (EINVAL);
1384294f337SSean Bruno 
1394294f337SSean Bruno 	if (qtag->type == IXL_PF_QALLOC_SCATTERED) {
1404294f337SSean Bruno 		for (i = 0; i < qtag->num_allocated; i++) {
1414294f337SSean Bruno 			qidx = qtag->qidx[i];
1424294f337SSean Bruno 			bzero(&qmgr->qinfo[qidx], sizeof(qmgr->qinfo[qidx]));
1434294f337SSean Bruno 		}
1444294f337SSean Bruno 	} else {
1454294f337SSean Bruno 		u16 first_index = qtag->qidx[0];
1464294f337SSean Bruno 		for (i = first_index; i < first_index + qtag->num_allocated; i++)
1474294f337SSean Bruno 			bzero(&qmgr->qinfo[i], sizeof(qmgr->qinfo[qidx]));
1484294f337SSean Bruno 	}
1494294f337SSean Bruno 
1504294f337SSean Bruno 	qtag->qmgr = NULL;
1514294f337SSean Bruno 	return (0);
1524294f337SSean Bruno }
1534294f337SSean Bruno 
1544294f337SSean Bruno int
ixl_pf_qmgr_get_num_queues(struct ixl_pf_qmgr * qmgr)1554294f337SSean Bruno ixl_pf_qmgr_get_num_queues(struct ixl_pf_qmgr *qmgr)
1564294f337SSean Bruno {
1574294f337SSean Bruno 	return (qmgr->num_queues);
1584294f337SSean Bruno }
1594294f337SSean Bruno 
1604294f337SSean Bruno /*
1614294f337SSean Bruno  * ERJ: This assumes the info array isn't longer than INT_MAX.
1624294f337SSean Bruno  * This assumption might cause a y3k bug or something, I'm sure.
1634294f337SSean Bruno  */
1644294f337SSean Bruno int
ixl_pf_qmgr_get_num_free(struct ixl_pf_qmgr * qmgr)1654294f337SSean Bruno ixl_pf_qmgr_get_num_free(struct ixl_pf_qmgr *qmgr)
1664294f337SSean Bruno {
1674294f337SSean Bruno 	int count = 0;
1684294f337SSean Bruno 
1694294f337SSean Bruno 	for (int i = 0; i < qmgr->num_queues; i++) {
1704294f337SSean Bruno 		if (!qmgr->qinfo[i].allocated)
1714294f337SSean Bruno 			count++;
1724294f337SSean Bruno 	}
1734294f337SSean Bruno 
1744294f337SSean Bruno 	return (count);
1754294f337SSean Bruno }
1764294f337SSean Bruno 
1774294f337SSean Bruno int
ixl_pf_qmgr_get_first_free(struct ixl_pf_qmgr * qmgr,u16 start)1784294f337SSean Bruno ixl_pf_qmgr_get_first_free(struct ixl_pf_qmgr *qmgr, u16 start)
1794294f337SSean Bruno {
1804294f337SSean Bruno 	int i;
1814294f337SSean Bruno 
1824294f337SSean Bruno 	if (start > qmgr->num_queues - 1)
1834294f337SSean Bruno 		return (-EINVAL);
1844294f337SSean Bruno 
1854294f337SSean Bruno 	for (i = start; i < qmgr->num_queues; i++) {
1864294f337SSean Bruno 		if (qmgr->qinfo[i].allocated)
1874294f337SSean Bruno 			continue;
1884294f337SSean Bruno 		else
1894294f337SSean Bruno 			return (i);
1904294f337SSean Bruno 	}
1914294f337SSean Bruno 
1924294f337SSean Bruno 	// No free queues
1934294f337SSean Bruno 	return (-ENOSPC);
1944294f337SSean Bruno }
1954294f337SSean Bruno 
1964294f337SSean Bruno void
ixl_pf_qmgr_destroy(struct ixl_pf_qmgr * qmgr)1974294f337SSean Bruno ixl_pf_qmgr_destroy(struct ixl_pf_qmgr *qmgr)
1984294f337SSean Bruno {
1994294f337SSean Bruno 	free(qmgr->qinfo, M_IXL);
2004294f337SSean Bruno 	qmgr->qinfo = NULL;
2014294f337SSean Bruno }
2024294f337SSean Bruno 
2034294f337SSean Bruno void
ixl_pf_qmgr_mark_queue_enabled(struct ixl_pf_qtag * qtag,u16 vsi_qidx,bool tx)2044294f337SSean Bruno ixl_pf_qmgr_mark_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
2054294f337SSean Bruno {
2064294f337SSean Bruno 	MPASS(qtag != NULL);
2074294f337SSean Bruno 
2084294f337SSean Bruno 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
2094294f337SSean Bruno 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
2104294f337SSean Bruno 	if (tx)
2114294f337SSean Bruno 		qmgr->qinfo[pf_qidx].tx_enabled = true;
2124294f337SSean Bruno 	else
2134294f337SSean Bruno 		qmgr->qinfo[pf_qidx].rx_enabled = true;
2144294f337SSean Bruno }
2154294f337SSean Bruno 
2164294f337SSean Bruno void
ixl_pf_qmgr_mark_queue_disabled(struct ixl_pf_qtag * qtag,u16 vsi_qidx,bool tx)2174294f337SSean Bruno ixl_pf_qmgr_mark_queue_disabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
2184294f337SSean Bruno {
2194294f337SSean Bruno 	MPASS(qtag != NULL);
2204294f337SSean Bruno 
2214294f337SSean Bruno 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
2224294f337SSean Bruno 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
2234294f337SSean Bruno 	if (tx)
2244294f337SSean Bruno 		qmgr->qinfo[pf_qidx].tx_enabled = false;
2254294f337SSean Bruno 	else
2264294f337SSean Bruno 		qmgr->qinfo[pf_qidx].rx_enabled = false;
2274294f337SSean Bruno }
2284294f337SSean Bruno 
2294294f337SSean Bruno void
ixl_pf_qmgr_mark_queue_configured(struct ixl_pf_qtag * qtag,u16 vsi_qidx,bool tx)2304294f337SSean Bruno ixl_pf_qmgr_mark_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
2314294f337SSean Bruno {
2324294f337SSean Bruno 	MPASS(qtag != NULL);
2334294f337SSean Bruno 
2344294f337SSean Bruno 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
2354294f337SSean Bruno 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
2364294f337SSean Bruno 	if (tx)
2374294f337SSean Bruno 		qmgr->qinfo[pf_qidx].tx_configured = true;
2384294f337SSean Bruno 	else
2394294f337SSean Bruno 		qmgr->qinfo[pf_qidx].rx_configured = true;
2404294f337SSean Bruno }
2414294f337SSean Bruno 
2424294f337SSean Bruno bool
ixl_pf_qmgr_is_queue_enabled(struct ixl_pf_qtag * qtag,u16 vsi_qidx,bool tx)2434294f337SSean Bruno ixl_pf_qmgr_is_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
2444294f337SSean Bruno {
2454294f337SSean Bruno 	MPASS(qtag != NULL);
2464294f337SSean Bruno 
2474294f337SSean Bruno 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
2484294f337SSean Bruno 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
2494294f337SSean Bruno 	if (tx)
2504294f337SSean Bruno 		return (qmgr->qinfo[pf_qidx].tx_enabled);
2514294f337SSean Bruno 	else
2524294f337SSean Bruno 		return (qmgr->qinfo[pf_qidx].rx_enabled);
2534294f337SSean Bruno }
2544294f337SSean Bruno 
2554294f337SSean Bruno bool
ixl_pf_qmgr_is_queue_configured(struct ixl_pf_qtag * qtag,u16 vsi_qidx,bool tx)2564294f337SSean Bruno ixl_pf_qmgr_is_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
2574294f337SSean Bruno {
2584294f337SSean Bruno 	MPASS(qtag != NULL);
2594294f337SSean Bruno 
2604294f337SSean Bruno 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
2614294f337SSean Bruno 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
2624294f337SSean Bruno 	if (tx)
2634294f337SSean Bruno 		return (qmgr->qinfo[pf_qidx].tx_configured);
2644294f337SSean Bruno 	else
2654294f337SSean Bruno 		return (qmgr->qinfo[pf_qidx].rx_configured);
2664294f337SSean Bruno }
2674294f337SSean Bruno 
268*77c1fcecSEric Joyner void
ixl_pf_qmgr_clear_queue_flags(struct ixl_pf_qtag * qtag)269*77c1fcecSEric Joyner ixl_pf_qmgr_clear_queue_flags(struct ixl_pf_qtag *qtag)
270*77c1fcecSEric Joyner {
271*77c1fcecSEric Joyner 	MPASS(qtag != NULL);
272*77c1fcecSEric Joyner 
273*77c1fcecSEric Joyner 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
274*77c1fcecSEric Joyner 	for (u16 i = 0; i < qtag->num_allocated; i++) {
275*77c1fcecSEric Joyner 		u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, i);
276*77c1fcecSEric Joyner 
277*77c1fcecSEric Joyner 		qmgr->qinfo[pf_qidx].tx_configured = 0;
278*77c1fcecSEric Joyner 		qmgr->qinfo[pf_qidx].rx_configured = 0;
279*77c1fcecSEric Joyner 		qmgr->qinfo[pf_qidx].rx_enabled = 0;
280*77c1fcecSEric Joyner 		qmgr->qinfo[pf_qidx].tx_enabled = 0;
281*77c1fcecSEric Joyner 	}
282*77c1fcecSEric Joyner }
283*77c1fcecSEric Joyner 
2844294f337SSean Bruno u16
ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag * qtag,u16 index)2854294f337SSean Bruno ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag *qtag, u16 index)
2864294f337SSean Bruno {
2874294f337SSean Bruno 	MPASS(index < qtag->num_allocated);
2884294f337SSean Bruno 
2894294f337SSean Bruno 	if (qtag->type == IXL_PF_QALLOC_CONTIGUOUS)
290*77c1fcecSEric Joyner 		return qtag->first_qidx + index;
2914294f337SSean Bruno 	else
2924294f337SSean Bruno 		return qtag->qidx[index];
2934294f337SSean Bruno }
2944294f337SSean Bruno 
2954294f337SSean Bruno /* Static Functions */
2964294f337SSean Bruno 
2974294f337SSean Bruno static int
ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr * qmgr,int num)2984294f337SSean Bruno ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num)
2994294f337SSean Bruno {
3004294f337SSean Bruno 	int i;
3014294f337SSean Bruno 	int count = 0;
3024294f337SSean Bruno 	bool block_started = false;
3034294f337SSean Bruno 	int possible_start;
3044294f337SSean Bruno 
3054294f337SSean Bruno 	for (i = 0; i < qmgr->num_queues; i++) {
3064294f337SSean Bruno 		if (!qmgr->qinfo[i].allocated) {
3074294f337SSean Bruno 			if (!block_started) {
3084294f337SSean Bruno 				block_started = true;
3094294f337SSean Bruno 				possible_start = i;
3104294f337SSean Bruno 			}
3114294f337SSean Bruno 			count++;
3124294f337SSean Bruno 			if (count == num)
3134294f337SSean Bruno 				return (possible_start);
3144294f337SSean Bruno 		} else { /* this queue is already allocated */
3154294f337SSean Bruno 			block_started = false;
3164294f337SSean Bruno 			count = 0;
3174294f337SSean Bruno 		}
3184294f337SSean Bruno 	}
3194294f337SSean Bruno 
3204294f337SSean Bruno 	/* Can't find a contiguous block of the requested size */
3214294f337SSean Bruno 	return (-1);
3224294f337SSean Bruno }
3234294f337SSean Bruno 
324