summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/bcmdhd/linux_osl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/linux_osl.c')
-rw-r--r--drivers/net/wireless/bcmdhd/linux_osl.c289
1 files changed, 209 insertions, 80 deletions
diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c
index 4ef7bf7b24d..5cc3a876779 100644
--- a/drivers/net/wireless/bcmdhd/linux_osl.c
+++ b/drivers/net/wireless/bcmdhd/linux_osl.c
@@ -1,9 +1,9 @@
/*
* Linux OS Independent Layer
*
- * Copyright (C) 1999-2011, Broadcom Corporation
+ * Copyright (C) 1999-2012, Broadcom Corporation
*
- * Unless you and Broadcom execute a separate written software license
+ * Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
@@ -21,10 +21,9 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 $
+ * $Id: linux_osl.c 309193 2012-01-19 00:03:57Z $
*/
-
#define LINUX_PORT
#include <typedefs.h>
@@ -40,6 +39,7 @@
#include <bcm_assert_log.h>
#endif
+
#include <linux/fs.h>
#define PCI_CFG_RETRY 10
@@ -49,7 +49,7 @@
#ifdef CONFIG_DHD_USE_STATIC_BUF
#define STATIC_BUF_MAX_NUM 16
-#define STATIC_BUF_SIZE (PAGE_SIZE * 2)
+#define STATIC_BUF_SIZE (PAGE_SIZE*2)
#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
typedef struct bcm_static_buf {
@@ -70,13 +70,14 @@ typedef struct bcm_static_pkt {
} bcm_static_pkt_t;
static bcm_static_pkt_t *bcm_static_skb = 0;
-#endif
+#endif
typedef struct bcm_mem_link {
struct bcm_mem_link *prev;
struct bcm_mem_link *next;
uint size;
int line;
+ void *osh;
char file[BCM_MEM_FILENAME_LEN];
} bcm_mem_link_t;
@@ -91,6 +92,8 @@ struct osl_info {
uint failed;
uint bustype;
bcm_mem_link_t *dbgmem_list;
+ spinlock_t dbgmem_lock;
+ spinlock_t pktalloc_lock;
};
@@ -170,14 +173,8 @@ osl_t *
osl_attach(void *pdev, uint bustype, bool pkttag)
{
osl_t *osh;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
- gfp_t flags;
- flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
- osh = kmalloc(sizeof(osl_t), flags);
-#else
osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
-#endif
ASSERT(osh);
bzero(osh, sizeof(osl_t));
@@ -189,6 +186,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
atomic_set(&osh->malloced, 0);
osh->failed = 0;
osh->dbgmem_list = NULL;
+ spin_lock_init(&(osh->dbgmem_lock));
osh->pdev = pdev;
osh->pub.pkttag = pkttag;
osh->bustype = bustype;
@@ -220,6 +218,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
else
printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf);
+
sema_init(&bcm_static_buf->static_sem, 1);
bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
@@ -231,13 +230,15 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
skb_buff_ptr = dhd_os_prealloc(osh, 4, 0);
- bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16);
+ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++)
bcm_static_skb->pkt_use[i] = 0;
sema_init(&bcm_static_skb->osl_pkt_sem, 1);
}
-#endif
+#endif
+
+ spin_lock_init(&(osh->pktalloc_lock));
return osh;
}
@@ -248,6 +249,15 @@ osl_detach(osl_t *osh)
if (osh == NULL)
return;
+#ifdef CONFIG_DHD_USE_STATIC_BUF
+ if (bcm_static_buf) {
+ bcm_static_buf = 0;
+ }
+ if (bcm_static_skb) {
+ bcm_static_skb = 0;
+ }
+#endif
+
ASSERT(osh->magic == OS_HANDLE_MAGIC);
kfree(osh);
}
@@ -255,7 +265,7 @@ osl_detach(osl_t *osh)
static struct sk_buff *osl_alloc_skb(unsigned int len)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
- gfp_t flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ gfp_t flags = GFP_ATOMIC;
return __dev_alloc_skb(len, flags);
#else
@@ -265,20 +275,31 @@ static struct sk_buff *osl_alloc_skb(unsigned int len)
#ifdef CTFPOOL
+#ifdef CTFPOOL_SPINLOCK
+#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags)
+#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags)
+#else
+#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock)
+#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock)
+#endif
+
void *
osl_ctfpool_add(osl_t *osh)
{
struct sk_buff *skb;
+#ifdef CTFPOOL_SPINLOCK
+ unsigned long flags;
+#endif
if ((osh == NULL) || (osh->ctfpool == NULL))
return NULL;
- spin_lock_bh(&osh->ctfpool->lock);
+ CTFPOOL_LOCK(osh->ctfpool, flags);
ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj);
if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) {
- spin_unlock_bh(&osh->ctfpool->lock);
+ CTFPOOL_UNLOCK(osh->ctfpool, flags);
return NULL;
}
@@ -287,7 +308,7 @@ osl_ctfpool_add(osl_t *osh)
if (skb == NULL) {
printf("%s: skb alloc of len %d failed\n", __FUNCTION__,
osh->ctfpool->obj_size);
- spin_unlock_bh(&osh->ctfpool->lock);
+ CTFPOOL_UNLOCK(osh->ctfpool, flags);
return NULL;
}
@@ -303,7 +324,7 @@ osl_ctfpool_add(osl_t *osh)
PKTFAST(osh, skb) = FASTBUF;
- spin_unlock_bh(&osh->ctfpool->lock);
+ CTFPOOL_UNLOCK(osh->ctfpool, flags);
return skb;
}
@@ -326,14 +347,7 @@ osl_ctfpool_replenish(osl_t *osh, uint thresh)
int32
osl_ctfpool_init(osl_t *osh, uint numobj, uint size)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
- gfp_t flags;
-
- flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
- osh->ctfpool = kmalloc(sizeof(ctfpool_t), flags);
-#else
osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC);
-#endif
ASSERT(osh->ctfpool);
bzero(osh->ctfpool, sizeof(ctfpool_t));
@@ -356,11 +370,14 @@ void
osl_ctfpool_cleanup(osl_t *osh)
{
struct sk_buff *skb, *nskb;
+#ifdef CTFPOOL_SPINLOCK
+ unsigned long flags;
+#endif
if ((osh == NULL) || (osh->ctfpool == NULL))
return;
- spin_lock_bh(&osh->ctfpool->lock);
+ CTFPOOL_LOCK(osh->ctfpool, flags);
skb = osh->ctfpool->head;
@@ -373,7 +390,7 @@ osl_ctfpool_cleanup(osl_t *osh)
ASSERT(osh->ctfpool->curr_obj == 0);
osh->ctfpool->head = NULL;
- spin_unlock_bh(&osh->ctfpool->lock);
+ CTFPOOL_UNLOCK(osh->ctfpool, flags);
kfree(osh->ctfpool);
osh->ctfpool = NULL;
@@ -412,16 +429,19 @@ static inline struct sk_buff *
osl_pktfastget(osl_t *osh, uint len)
{
struct sk_buff *skb;
+#ifdef CTFPOOL_SPINLOCK
+ unsigned long flags;
+#endif
if (osh->ctfpool == NULL)
return NULL;
- spin_lock_bh(&osh->ctfpool->lock);
+ CTFPOOL_LOCK(osh->ctfpool, flags);
if (osh->ctfpool->head == NULL) {
ASSERT(osh->ctfpool->curr_obj == 0);
osh->ctfpool->slow_allocs++;
- spin_unlock_bh(&osh->ctfpool->lock);
+ CTFPOOL_UNLOCK(osh->ctfpool, flags);
return NULL;
}
@@ -434,7 +454,7 @@ osl_pktfastget(osl_t *osh, uint len)
osh->ctfpool->fast_allocs++;
osh->ctfpool->curr_obj--;
ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head);
- spin_unlock_bh(&osh->ctfpool->lock);
+ CTFPOOL_UNLOCK(osh->ctfpool, flags);
skb->next = skb->prev = NULL;
@@ -450,24 +470,74 @@ osl_pktfastget(osl_t *osh, uint len)
return skb;
}
+#endif
+
+struct sk_buff * BCMFASTPATH
+osl_pkt_tonative(osl_t *osh, void *pkt)
+{
+#ifndef WL_UMK
+ struct sk_buff *nskb;
+ unsigned long flags;
#endif
+ if (osh->pub.pkttag)
+ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ);
+
+#ifndef WL_UMK
+
+ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) {
+ spin_lock_irqsave(&osh->pktalloc_lock, flags);
+ osh->pub.pktalloced--;
+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags);
+ }
+#endif
+ return (struct sk_buff *)pkt;
+}
+
+
+void * BCMFASTPATH
+osl_pkt_frmnative(osl_t *osh, void *pkt)
+{
+#ifndef WL_UMK
+ struct sk_buff *nskb;
+ unsigned long flags;
+#endif
+
+ if (osh->pub.pkttag)
+ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ);
+
+#ifndef WL_UMK
+
+ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) {
+ spin_lock_irqsave(&osh->pktalloc_lock, flags);
+ osh->pub.pktalloced++;
+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags);
+ }
+#endif
+ return (void *)pkt;
+}
+
void * BCMFASTPATH
osl_pktget(osl_t *osh, uint len)
{
struct sk_buff *skb;
+ unsigned long flags;
#ifdef CTFPOOL
+
skb = osl_pktfastget(osh, len);
if ((skb != NULL) || ((skb = osl_alloc_skb(len)) != NULL)) {
-#else
+#else
if ((skb = osl_alloc_skb(len))) {
-#endif
+#endif
skb_put(skb, len);
skb->priority = 0;
+
+ spin_lock_irqsave(&osh->pktalloc_lock, flags);
osh->pub.pktalloced++;
+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags);
}
return ((void*) skb);
@@ -478,20 +548,9 @@ static inline void
osl_pktfastfree(osl_t *osh, struct sk_buff *skb)
{
ctfpool_t *ctfpool;
-
- ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb);
- ASSERT(ctfpool != NULL);
-
-
- spin_lock_bh(&ctfpool->lock);
- skb->next = (struct sk_buff *)ctfpool->head;
- ctfpool->head = (void *)skb;
-
- ctfpool->fast_frees++;
- ctfpool->curr_obj++;
-
- ASSERT(ctfpool->curr_obj <= ctfpool->max_obj);
- spin_unlock_bh(&ctfpool->lock);
+#ifdef CTFPOOL_SPINLOCK
+ unsigned long flags;
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
skb->tstamp.tv.sec = 0;
@@ -505,6 +564,20 @@ osl_pktfastfree(osl_t *osh, struct sk_buff *skb)
memset(skb->cb, 0, sizeof(skb->cb));
skb->ip_summed = 0;
skb->destructor = NULL;
+
+ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb);
+ ASSERT(ctfpool != NULL);
+
+
+ CTFPOOL_LOCK(ctfpool, flags);
+ skb->next = (struct sk_buff *)ctfpool->head;
+ ctfpool->head = (void *)skb;
+
+ ctfpool->fast_frees++;
+ ctfpool->curr_obj++;
+
+ ASSERT(ctfpool->curr_obj <= ctfpool->max_obj);
+ CTFPOOL_UNLOCK(ctfpool, flags);
}
#endif
@@ -513,20 +586,24 @@ void BCMFASTPATH
osl_pktfree(osl_t *osh, void *p, bool send)
{
struct sk_buff *skb, *nskb;
+ unsigned long flags;
skb = (struct sk_buff*) p;
if (send && osh->pub.tx_fn)
osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
+ PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE);
+
while (skb) {
nskb = skb->next;
skb->next = NULL;
+
#ifdef CTFPOOL
- if (PKTISFAST(osh, skb))
+ if ((PKTISFAST(osh, skb)) && (atomic_read(&skb->users) == 1))
osl_pktfastfree(osh, skb);
else {
#else
@@ -540,21 +617,21 @@ osl_pktfree(osl_t *osh, void *p, bool send)
dev_kfree_skb(skb);
}
-
+ spin_lock_irqsave(&osh->pktalloc_lock, flags);
osh->pub.pktalloced--;
-
+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags);
skb = nskb;
}
}
#ifdef CONFIG_DHD_USE_STATIC_BUF
-void *
+void*
osl_pktget_static(osl_t *osh, uint len)
{
- int i;
+ int i = 0;
struct sk_buff *skb;
- if (!bcm_static_skb || (len > (PAGE_SIZE * 2))) {
+ if (len > (PAGE_SIZE*2)) {
printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
return osl_pktget(osh, len);
}
@@ -569,10 +646,10 @@ osl_pktget_static(osl_t *osh, uint len)
if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i] = 1;
+ up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_4k[i];
skb->tail = skb->data + len;
skb->len = len;
- up(&bcm_static_skb->osl_pkt_sem);
return skb;
}
}
@@ -585,10 +662,10 @@ osl_pktget_static(osl_t *osh, uint len)
if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1;
+ up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_8k[i];
skb->tail = skb->data + len;
skb->len = len;
- up(&bcm_static_skb->osl_pkt_sem);
return skb;
}
@@ -602,14 +679,9 @@ osl_pktfree_static(osl_t *osh, void *p, bool send)
{
int i;
- if (!bcm_static_skb) {
- osl_pktfree(osh, p, send);
- return;
- }
-
- down(&bcm_static_skb->osl_pkt_sem);
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (p == bcm_static_skb->skb_4k[i]) {
+ down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i] = 0;
up(&bcm_static_skb->osl_pkt_sem);
return;
@@ -618,15 +690,14 @@ osl_pktfree_static(osl_t *osh, void *p, bool send)
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (p == bcm_static_skb->skb_8k[i]) {
+ down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0;
up(&bcm_static_skb->osl_pkt_sem);
return;
}
}
- up(&bcm_static_skb->osl_pkt_sem);
- osl_pktfree(osh, p, send);
- return;
+ return osl_pktfree(osh, p, send);
}
#endif
@@ -689,6 +760,15 @@ osl_pci_slot(osl_t *osh)
return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
}
+
+struct pci_dev *
+osl_pci_device(osl_t *osh)
+{
+ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
+
+ return osh->pdev;
+}
+
static void
osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
{
@@ -710,18 +790,46 @@ void *
osl_malloc(osl_t *osh, uint size)
{
void *addr;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
- gfp_t flags;
if (osh)
ASSERT(osh->magic == OS_HANDLE_MAGIC);
- flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
- if ((addr = kmalloc(size, flags)) == NULL) {
-#else
- if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
+#ifdef CONFIG_DHD_USE_STATIC_BUF
+ if (bcm_static_buf)
+ {
+ int i = 0;
+ if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE))
+ {
+ down(&bcm_static_buf->static_sem);
+
+ for (i = 0; i < STATIC_BUF_MAX_NUM; i++)
+ {
+ if (bcm_static_buf->buf_use[i] == 0)
+ break;
+ }
+
+ if (i == STATIC_BUF_MAX_NUM)
+ {
+ up(&bcm_static_buf->static_sem);
+ printk("all static buff in use!\n");
+ goto original;
+ }
+
+ bcm_static_buf->buf_use[i] = 1;
+ up(&bcm_static_buf->static_sem);
+
+ bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size);
+ if (osh)
+ atomic_add(size, &osh->malloced);
+
+ return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i));
+ }
+ }
+original:
#endif
+
+ if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
if (osh)
osh->failed++;
return (NULL);
@@ -735,6 +843,28 @@ osl_malloc(osl_t *osh, uint size)
void
osl_mfree(osl_t *osh, void *addr, uint size)
{
+#ifdef CONFIG_DHD_USE_STATIC_BUF
+ if (bcm_static_buf)
+ {
+ if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
+ <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN)))
+ {
+ int buf_idx = 0;
+
+ buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE;
+
+ down(&bcm_static_buf->static_sem);
+ bcm_static_buf->buf_use[buf_idx] = 0;
+ up(&bcm_static_buf->static_sem);
+
+ if (osh) {
+ ASSERT(osh->magic == OS_HANDLE_MAGIC);
+ atomic_sub(size, &osh->malloced);
+ }
+ return;
+ }
+ }
+#endif
if (osh) {
ASSERT(osh->magic == OS_HANDLE_MAGIC);
atomic_sub(size, &osh->malloced);
@@ -757,7 +887,6 @@ osl_malloc_failed(osl_t *osh)
}
-
uint
osl_dma_consistent_align(void)
{
@@ -807,10 +936,10 @@ osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
#if defined(BCMASSERT_LOG)
void
-osl_assert(char *exp, char *file, int line)
+osl_assert(const char *exp, const char *file, int line)
{
char tempbuf[256];
- char *basename;
+ const char *basename;
basename = strrchr(file, '/');
@@ -849,14 +978,12 @@ void *
osl_pktdup(osl_t *osh, void *skb)
{
void * p;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
- gfp_t flags;
+ unsigned long irqflags;
- flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
- if ((p = skb_clone((struct sk_buff *)skb, flags)) == NULL)
-#else
- if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL)
-#endif
+
+ PKTCTFMAP(osh, skb);
+
+ if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL)
return NULL;
#ifdef CTFPOOL
@@ -877,7 +1004,9 @@ osl_pktdup(osl_t *osh, void *skb)
bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
+ spin_lock_irqsave(&osh->pktalloc_lock, irqflags);
osh->pub.pktalloced++;
+ spin_unlock_irqrestore(&osh->pktalloc_lock, irqflags);
return (p);
}