diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
commit | e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7 (patch) | |
tree | ea51b391f7d74ca695dcb9f5e46eb02688a92ed9 /drivers/staging/brcm80211/util/linux_osl.c | |
parent | 81280572ca6f54009edfa4deee563e8678784218 (diff) | |
parent | a4ac0d847af9dd34d5953a5e264400326144b6b2 (diff) | |
download | op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.zip op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.tar.gz |
Merge 'staging-next' to Linus's tree
This merges the staging-next tree to Linus's tree and resolves
some conflicts that were present due to changes in other trees that were
affected by files here.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/brcm80211/util/linux_osl.c')
-rw-r--r-- | drivers/staging/brcm80211/util/linux_osl.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c new file mode 100644 index 0000000..2bb5b87 --- /dev/null +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +#include <linux/delay.h> +#include <linux/fs.h> +#ifdef mips +#include <asm/paccess.h> +#endif /* mips */ +#include <bcmendian.h> +#include <linuxver.h> +#include <bcmdefs.h> +#include <osl.h> +#include <bcmutils.h> +#include <pcicfg.h> + + +#define PCI_CFG_RETRY 10 + +#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */ +#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ + +struct osl_info { + osl_pubinfo_t pub; + uint magic; + void *pdev; + uint failed; + uint bustype; +}; + +/* Global ASSERT type flag */ +u32 g_assert_type; + +#ifdef BRCM_FULLMAC +static s16 linuxbcmerrormap[] = { 0, /* 0 */ + -EINVAL, /* BCME_ERROR */ + -EINVAL, /* BCME_BADARG */ + -EINVAL, /* BCME_BADOPTION */ + -EINVAL, /* BCME_NOTUP */ + -EINVAL, /* BCME_NOTDOWN */ + -EINVAL, /* BCME_NOTAP */ + -EINVAL, /* BCME_NOTSTA */ + -EINVAL, /* BCME_BADKEYIDX */ + -EINVAL, /* BCME_RADIOOFF */ + -EINVAL, /* BCME_NOTBANDLOCKED */ + -EINVAL, /* BCME_NOCLK */ + -EINVAL, /* BCME_BADRATESET */ + -EINVAL, /* BCME_BADBAND */ + -E2BIG, /* BCME_BUFTOOSHORT */ + -E2BIG, /* BCME_BUFTOOLONG */ + -EBUSY, /* BCME_BUSY */ + -EINVAL, /* BCME_NOTASSOCIATED */ + -EINVAL, /* BCME_BADSSIDLEN */ + -EINVAL, /* BCME_OUTOFRANGECHAN */ + -EINVAL, /* BCME_BADCHAN */ + -EFAULT, /* BCME_BADADDR */ + -ENOMEM, /* BCME_NORESOURCE */ + -EOPNOTSUPP, /* BCME_UNSUPPORTED */ + -EMSGSIZE, /* BCME_BADLENGTH */ + -EINVAL, /* BCME_NOTREADY */ + -EPERM, /* BCME_NOTPERMITTED */ + -ENOMEM, /* BCME_NOMEM */ + -EINVAL, /* BCME_ASSOCIATED */ + -ERANGE, /* BCME_RANGE */ + -EINVAL, /* BCME_NOTFOUND */ + -EINVAL, /* BCME_WME_NOT_ENABLED */ + -EINVAL, /* BCME_TSPEC_NOTFOUND */ + -EINVAL, /* BCME_ACM_NOTSUPPORTED */ + -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ + -EIO, /* BCME_SDIO_ERROR */ + -ENODEV, /* BCME_DONGLE_DOWN */ + -EINVAL, /* BCME_VERSION */ + -EIO, /* BCME_TXFAIL */ + -EIO, /* BCME_RXFAIL */ + -EINVAL, /* BCME_NODEVICE */ + -EINVAL, /* BCME_NMODE_DISABLED */ + -ENODATA, /* BCME_NONRESIDENT */ + +/* When an new error code is added to bcmutils.h, add os + * spcecific error translation here as well + */ +/* check if BCME_LAST changed since the last time this function was updated */ +#if BCME_LAST != -42 +#error "You need to add a OS error translation in the linuxbcmerrormap \ + for new error code defined in bcmutils.h" +#endif +}; + +/* translate bcmerrors into linux errors */ +int osl_error(int bcmerror) +{ + if (bcmerror > 0) + bcmerror = 0; + else if (bcmerror < BCME_LAST) + bcmerror = BCME_ERROR; + + /* Array bounds covered by ASSERT in osl_attach */ + return linuxbcmerrormap[-bcmerror]; +} +#endif /* BRCM_FULLMAC */ + +osl_t *osl_attach(void *pdev, uint bustype, bool pkttag) +{ + osl_t *osh; + + osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); + ASSERT(osh); + + bzero(osh, sizeof(osl_t)); + +#ifdef BRCM_FULLMAC + /* Check that error map has the right number of entries in it */ + ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(linuxbcmerrormap) - 1)); +#endif /* BRCM_FULLMAC */ + + osh->magic = OS_HANDLE_MAGIC; + osh->failed = 0; + osh->pdev = pdev; + osh->pub.pkttag = pkttag; + osh->bustype = bustype; + + switch (bustype) { + case PCI_BUS: + case SI_BUS: + case PCMCIA_BUS: + osh->pub.mmbus = true; + break; + case JTAG_BUS: + case SDIO_BUS: + case USB_BUS: + case SPI_BUS: + case RPC_BUS: + osh->pub.mmbus = false; + break; + default: + ASSERT(false); + break; + } + +#if defined(BCMDBG) && !defined(BRCM_FULLMAC) + if (pkttag) { + struct sk_buff *skb; + ASSERT(OSL_PKTTAG_SZ <= sizeof(skb->cb)); + } +#endif + return osh; +} + +void osl_detach(osl_t *osh) +{ + if (osh == NULL) + return; + + ASSERT(osh->magic == OS_HANDLE_MAGIC); + kfree(osh); +} + +/* Return a new packet. zero out pkttag */ +void *BCMFASTPATH osl_pktget(osl_t *osh, uint len) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(len); + if (skb) { + skb_put(skb, len); + skb->priority = 0; + + osh->pub.pktalloced++; + } + + return (void *)skb; +} + +/* Free the driver packet. Free the tag if present */ +void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send) +{ + struct sk_buff *skb, *nskb; + int nest = 0; + + skb = (struct sk_buff *)p; + ASSERT(skb); + + if (send && osh->pub.tx_fn) + osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); + + /* perversion: we use skb->next to chain multi-skb packets */ + while (skb) { + nskb = skb->next; + skb->next = NULL; + + if (skb->destructor) + /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if + * destructor exists + */ + dev_kfree_skb_any(skb); + else + /* can free immediately (even in_irq()) if destructor + * does not exist + */ + dev_kfree_skb(skb); + + osh->pub.pktalloced--; + nest++; + skb = nskb; + } +} + +u32 osl_pci_read_config(osl_t *osh, uint offset, uint size) +{ + uint val = 0; + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + /* only 4byte access supported */ + ASSERT(size == 4); + + do { + pci_read_config_dword(osh->pdev, offset, &val); + if (val != 0xffffffff) + break; + } while (retry--); + +#ifdef BCMDBG + if (retry < PCI_CFG_RETRY) + printk("PCI CONFIG READ access to %d required %d retries\n", + offset, (PCI_CFG_RETRY - retry)); +#endif /* BCMDBG */ + + return val; +} + +void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) +{ + uint retry = PCI_CFG_RETRY; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + /* only 4byte access supported */ + ASSERT(size == 4); + + do { + pci_write_config_dword(osh->pdev, offset, val); + if (offset != PCI_BAR0_WIN) + break; + if (osl_pci_read_config(osh, offset, size) == val) + break; + } while (retry--); + +#if defined(BCMDBG) && !defined(BRCM_FULLMAC) + if (retry < PCI_CFG_RETRY) + printk("PCI CONFIG WRITE access to %d required %d retries\n", + offset, (PCI_CFG_RETRY - retry)); +#endif /* BCMDBG */ +} + +/* return bus # for the pci device pointed by osh->pdev */ +uint osl_pci_bus(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return ((struct pci_dev *)osh->pdev)->bus->number; +} + +/* return slot # for the pci device pointed by osh->pdev */ +uint osl_pci_slot(osl_t *osh) +{ + ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); + + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); +} + +uint osl_dma_consistent_align(void) +{ + return PAGE_SIZE; +} + +void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits, + uint *alloced, unsigned long *pap) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + if (align_bits) { + u16 align = (1 << align_bits); + if (!IS_ALIGNED(DMA_CONSISTENT_ALIGN, align)) + size += align; + *alloced = size; + } + return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap); +} + +void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + + pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa); +} + +uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction) +{ + int dir; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; + return pci_map_single(osh->pdev, va, size, dir); +} + +void BCMFASTPATH osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) +{ + int dir; + + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; + pci_unmap_single(osh->pdev, (u32) pa, size, dir); +} + +#if defined(BCMDBG_ASSERT) +void osl_assert(char *exp, char *file, int line) +{ + char tempbuf[256]; + char *basename; + + basename = strrchr(file, '/'); + /* skip the '/' */ + if (basename) + basename++; + + if (!basename) + basename = file; + +#ifdef BCMDBG_ASSERT + snprintf(tempbuf, 256, + "assertion \"%s\" failed: file \"%s\", line %d\n", exp, + basename, line); + + /* Print assert message and give it time to be written to /var/log/messages */ + if (!in_interrupt()) { + const int delay = 3; + printk(KERN_ERR "%s", tempbuf); + printk(KERN_ERR "panic in %d seconds\n", delay); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(delay * HZ); + } + + switch (g_assert_type) { + case 0: + panic(KERN_ERR "%s", tempbuf); + break; + case 1: + printk(KERN_ERR "%s", tempbuf); + BUG(); + break; + case 2: + printk(KERN_ERR "%s", tempbuf); + break; + default: + break; + } +#endif /* BCMDBG_ASSERT */ + +} +#endif /* defined(BCMDBG_ASSERT) */ + +#if defined(BCMSDIO) && !defined(BRCM_FULLMAC) +u8 osl_readb(osl_t *osh, volatile u8 *r) +{ + osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn; + void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + + return (u8) ((rreg) (ctx, (void *)r, sizeof(u8))); +} + +u16 osl_readw(osl_t *osh, volatile u16 *r) +{ + osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn; + void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + + return (u16) ((rreg) (ctx, (void *)r, sizeof(u16))); +} + +u32 osl_readl(osl_t *osh, volatile u32 *r) +{ + osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn; + void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + + return (u32) ((rreg) (ctx, (void *)r, sizeof(u32))); +} + +void osl_writeb(osl_t *osh, volatile u8 *r, u8 v) +{ + osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn; + void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + + ((wreg) (ctx, (void *)r, v, sizeof(u8))); +} + +void osl_writew(osl_t *osh, volatile u16 *r, u16 v) +{ + osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn; + void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + + ((wreg) (ctx, (void *)r, v, sizeof(u16))); +} + +void osl_writel(osl_t *osh, volatile u32 *r, u32 v) +{ + osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn; + void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + + ((wreg) (ctx, (void *)r, v, sizeof(u32))); +} +#endif /* BCMSDIO */ |