Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[pandora-kernel.git] / drivers / staging / brcm80211 / util / linux_osl.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/delay.h>
18 #include <linux/fs.h>
19 #ifdef mips
20 #include <asm/paccess.h>
21 #endif                          /* mips */
22 #include <bcmendian.h>
23 #include <linux/module.h>
24 #include <linux/pci.h>
25 #include <linux/netdevice.h>
26 #include <linux/sched.h>
27 #include <bcmdefs.h>
28 #include <osl.h>
29 #include <bcmutils.h>
30 #include <pcicfg.h>
31
32
33 #define OS_HANDLE_MAGIC         0x1234abcd      /* Magic # to recognise osh */
34 #define BCM_MEM_FILENAME_LEN    24      /* Mem. filename length */
35
36 /* Global ASSERT type flag */
37 u32 g_assert_type;
38
39 struct osl_info *osl_attach(void *pdev, uint bustype)
40 {
41         struct osl_info *osh;
42
43         osh = kmalloc(sizeof(struct osl_info), GFP_ATOMIC);
44         ASSERT(osh);
45
46         memset(osh, 0, sizeof(struct osl_info));
47
48         osh->magic = OS_HANDLE_MAGIC;
49         osh->pdev = pdev;
50         osh->bustype = bustype;
51
52         switch (bustype) {
53         case PCI_BUS:
54         case SI_BUS:
55         case PCMCIA_BUS:
56                 osh->mmbus = true;
57                 break;
58         case JTAG_BUS:
59         case SDIO_BUS:
60         case USB_BUS:
61         case SPI_BUS:
62         case RPC_BUS:
63                 osh->mmbus = false;
64                 break;
65         default:
66                 ASSERT(false);
67                 break;
68         }
69
70         return osh;
71 }
72
73 void osl_detach(struct osl_info *osh)
74 {
75         if (osh == NULL)
76                 return;
77
78         ASSERT(osh->magic == OS_HANDLE_MAGIC);
79         kfree(osh);
80 }
81
82 struct sk_buff *BCMFASTPATH pkt_buf_get_skb(struct osl_info *osh, uint len)
83 {
84         struct sk_buff *skb;
85
86         skb = dev_alloc_skb(len);
87         if (skb) {
88                 skb_put(skb, len);
89                 skb->priority = 0;
90
91                 osh->pktalloced++;
92         }
93
94         return skb;
95 }
96
97 /* Free the driver packet. Free the tag if present */
98 void BCMFASTPATH pkt_buf_free_skb(struct osl_info *osh, struct sk_buff *skb, bool send)
99 {
100         struct sk_buff *nskb;
101         int nest = 0;
102
103         ASSERT(skb);
104
105         /* perversion: we use skb->next to chain multi-skb packets */
106         while (skb) {
107                 nskb = skb->next;
108                 skb->next = NULL;
109
110                 if (skb->destructor)
111                         /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
112                          * destructor exists
113                          */
114                         dev_kfree_skb_any(skb);
115                 else
116                         /* can free immediately (even in_irq()) if destructor
117                          * does not exist
118                          */
119                         dev_kfree_skb(skb);
120
121                 osh->pktalloced--;
122                 nest++;
123                 skb = nskb;
124         }
125 }
126
127 /* return bus # for the pci device pointed by osh->pdev */
128 uint osl_pci_bus(struct osl_info *osh)
129 {
130         ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
131
132         return ((struct pci_dev *)osh->pdev)->bus->number;
133 }
134
135 /* return slot # for the pci device pointed by osh->pdev */
136 uint osl_pci_slot(struct osl_info *osh)
137 {
138         ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
139
140         return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
141 }
142
143 void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, u16 align_bits,
144                                uint *alloced, unsigned long *pap)
145 {
146         ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
147
148         if (align_bits) {
149                 u16 align = (1 << align_bits);
150                 if (!IS_ALIGNED(PAGE_SIZE, align))
151                         size += align;
152                 *alloced = size;
153         }
154         return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap);
155 }
156
157 void osl_dma_free_consistent(struct osl_info *osh, void *va, uint size,
158                              unsigned long pa)
159 {
160         ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
161
162         pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa);
163 }
164
165 uint BCMFASTPATH osl_dma_map(struct osl_info *osh, void *va, uint size,
166                              int direction)
167 {
168         int dir;
169
170         ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
171         dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
172         return pci_map_single(osh->pdev, va, size, dir);
173 }
174
175 void BCMFASTPATH osl_dma_unmap(struct osl_info *osh, uint pa, uint size,
176                                int direction)
177 {
178         int dir;
179
180         ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
181         dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
182         pci_unmap_single(osh->pdev, (u32) pa, size, dir);
183 }
184
185 #if defined(BCMDBG_ASSERT)
186 void osl_assert(char *exp, char *file, int line)
187 {
188         char tempbuf[256];
189         char *basename;
190
191         basename = strrchr(file, '/');
192         /* skip the '/' */
193         if (basename)
194                 basename++;
195
196         if (!basename)
197                 basename = file;
198
199 #ifdef BCMDBG_ASSERT
200         snprintf(tempbuf, 256,
201                  "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
202                  basename, line);
203
204         /* Print assert message and give it time to be written to /var/log/messages */
205         if (!in_interrupt()) {
206                 const int delay = 3;
207                 printk(KERN_ERR "%s", tempbuf);
208                 printk(KERN_ERR "panic in %d seconds\n", delay);
209                 set_current_state(TASK_INTERRUPTIBLE);
210                 schedule_timeout(delay * HZ);
211         }
212
213         switch (g_assert_type) {
214         case 0:
215                 panic(KERN_ERR "%s", tempbuf);
216                 break;
217         case 1:
218                 printk(KERN_ERR "%s", tempbuf);
219                 BUG();
220                 break;
221         case 2:
222                 printk(KERN_ERR "%s", tempbuf);
223                 break;
224         default:
225                 break;
226         }
227 #endif                          /* BCMDBG_ASSERT */
228
229 }
230 #endif                          /* defined(BCMDBG_ASSERT) */
231