| /* |
| * 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; |
| } |