blob: d294831b5c36c411f98a525a79ff590f5337565e [file] [log] [blame]
/*
* Copyright (c) 2007-2008 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* */
/* Module Name : queue.c */
/* */
/* Abstract */
/* This module contains queue management functions. */
/* */
/* NOTES */
/* None */
/* */
/************************************************************************/
#include "cprecomp.h"
#include "queue.h"
struct zsQueue* zfQueueCreate(zdev_t* dev, u16_t size)
{
struct zsQueue* q;
if ((q = (struct zsQueue*)zfwMemAllocate(dev, sizeof(struct zsQueue)
+ (sizeof(struct zsQueueCell)*(size-1)))) != NULL)
{
q->size = size;
q->sizeMask = size-1;
q->head = 0;
q->tail = 0;
}
return q;
}
void zfQueueDestroy(zdev_t* dev, struct zsQueue* q)
{
u16_t size = sizeof(struct zsQueue) + (sizeof(struct zsQueueCell)*(q->size-1));
zfQueueFlush(dev, q);
zfwMemFree(dev, q, size);
return;
}
u16_t zfQueuePutNcs(zdev_t* dev, struct zsQueue* q, zbuf_t* buf, u32_t tick)
{
u16_t ret = ZM_ERR_QUEUE_FULL;
zm_msg0_mm(ZM_LV_1, "zfQueuePutNcs()");
if (((q->tail+1)&q->sizeMask) != q->head)
{
q->cell[q->tail].buf = buf;
q->cell[q->tail].tick = tick;
q->tail = (q->tail+1) & q->sizeMask;
ret = ZM_SUCCESS;
}
return ret;
}
u16_t zfQueuePut(zdev_t* dev, struct zsQueue* q, zbuf_t* buf, u32_t tick)
{
u16_t ret;
zmw_declare_for_critical_section();
zmw_enter_critical_section(dev);
ret = zfQueuePutNcs(dev, q, buf, tick);
zmw_leave_critical_section(dev);
return ret;
}
zbuf_t* zfQueueGet(zdev_t* dev, struct zsQueue* q)
{
zbuf_t* buf = NULL;
zmw_declare_for_critical_section();
zmw_enter_critical_section(dev);
if (q->head != q->tail)
{
buf = q->cell[q->head].buf;
q->head = (q->head+1) & q->sizeMask;
}
zmw_leave_critical_section(dev);
return buf;
}
u16_t zfCompareDstwithBuf(zdev_t* dev, zbuf_t* buf, u8_t* addr)
{
u16_t i;
u8_t dst[6];
for (i=0; i<6; i++)
{
dst[i] = zmw_buf_readb(dev, buf, i);
if (dst[i] != addr[i])
{
return 1+i;
}
}
return 0;
}
zbuf_t* zfQueueGetWithMac(zdev_t* dev, struct zsQueue* q, u8_t* addr, u8_t* mb)
{
zbuf_t* buf;
zbuf_t* retBuf = NULL;
u16_t index, next;
zmw_declare_for_critical_section();
*mb = 0;
zmw_enter_critical_section(dev);
index = q->head;
while (1)
{
if (index != q->tail)
{
buf = q->cell[index].buf;
//if buf's detination address == input addr
if (zfCompareDstwithBuf(dev, buf, addr) == 0)
{
retBuf = buf;
//Get it, and trace the whole queue to calculate more bit
while ((next =((index+1)&q->sizeMask)) != q->tail)
{
q->cell[index].buf = q->cell[next].buf;
q->cell[index].tick = q->cell[next].tick;
if ((*mb == 0) && (zfCompareDstwithBuf(dev,
q->cell[next].buf, addr) == 0))
{
*mb = 1;
}
index = next;
}
q->tail = (q->tail-1) & q->sizeMask;
zmw_leave_critical_section(dev);
return retBuf;
}
index = (index + 1) & q->sizeMask;
} //if (index != q->tail)
else
{
break;
}
}
zmw_leave_critical_section(dev);
return retBuf;
}
void zfQueueFlush(zdev_t* dev, struct zsQueue* q)
{
zbuf_t* buf;
while ((buf = zfQueueGet(dev, q)) != NULL)
{
zfwBufFree(dev, buf, 0);
}
return;
}
void zfQueueAge(zdev_t* dev, struct zsQueue* q, u32_t tick, u32_t msAge)
{
zbuf_t* buf;
u32_t buftick;
zmw_declare_for_critical_section();
while (1)
{
buf = NULL;
zmw_enter_critical_section(dev);
if (q->head != q->tail)
{
buftick = q->cell[q->head].tick;
if (((tick - buftick)*ZM_MS_PER_TICK) > msAge)
{
buf = q->cell[q->head].buf;
q->head = (q->head+1) & q->sizeMask;
}
}
zmw_leave_critical_section(dev);
if (buf != NULL)
{
zm_msg0_mm(ZM_LV_0, "Age frame in queue!");
zfwBufFree(dev, buf, 0);
}
else
{
break;
}
}
return;
}
u8_t zfQueueRemovewithIndex(zdev_t* dev, struct zsQueue* q, u16_t index, u8_t* addr)
{
u16_t next;
u8_t mb = 0;
//trace the whole queue to calculate more bit
while ((next =((index+1)&q->sizeMask)) != q->tail)
{
q->cell[index].buf = q->cell[next].buf;
q->cell[index].tick = q->cell[next].tick;
if ((mb == 0) && (zfCompareDstwithBuf(dev,
q->cell[next].buf, addr) == 0))
{
mb = 1;
}
index = next;
}
q->tail = (q->tail-1) & q->sizeMask;
return mb;
}
void zfQueueGenerateUapsdTim(zdev_t* dev, struct zsQueue* q,
u8_t* uniBitMap, u16_t* highestByte)
{
zbuf_t* psBuf;
u8_t dst[6];
u16_t id, aid, index, i;
u16_t bitPosition;
u16_t bytePosition;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
zmw_enter_critical_section(dev);
index = q->head;
while (index != q->tail)
{
psBuf = q->cell[index].buf;
for (i=0; i<6; i++)
{
dst[i] = zmw_buf_readb(dev, psBuf, i);
}
/* TODO : use u8_t* fot MAC address */
if (((id = zfApFindSta(dev, (u16_t*)dst)) != 0xffff)
&& (wd->ap.staTable[id].psMode != 0))
{
/* Calculate PVB only when all AC are delivery-enabled */
if ((wd->ap.staTable[id].qosInfo & 0xf) == 0xf)
{
aid = id + 1;
bitPosition = (1 << (aid & 0x7));
bytePosition = (aid >> 3);
uniBitMap[bytePosition] |= bitPosition;
if (bytePosition>*highestByte)
{
*highestByte = bytePosition;
}
}
index = (index+1) & q->sizeMask;
}
else
{
/* Free garbage UAPSD frame */
zfQueueRemovewithIndex(dev, q, index, dst);
zfwBufFree(dev, psBuf, 0);
}
}
zmw_leave_critical_section(dev);
return;
}