blob: 6a06d61568b9af35a8e15f1e08d149ae182c67b4 [file] [log] [blame]
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001/*
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
Greg Kroah-Hartmana1c16ed2010-10-21 11:17:44 -070017#include <linux/delay.h>
18#include <linux/fs.h>
19#ifdef mips
20#include <asm/paccess.h>
21#endif /* mips */
Henry Ptasinskia9533e72010-09-08 21:04:42 -070022#include <bcmendian.h>
Brett Rudleyc6ac24e2010-10-26 11:55:23 -070023#include <linux/module.h>
24#include <linux/pci.h>
25#include <linux/netdevice.h>
26#include <linux/sched.h>
Henry Ptasinskia9533e72010-09-08 21:04:42 -070027#include <bcmdefs.h>
28#include <osl.h>
29#include <bcmutils.h>
Henry Ptasinskia9533e72010-09-08 21:04:42 -070030#include <pcicfg.h>
31
Henry Ptasinskia9533e72010-09-08 21:04:42 -070032
Henry Ptasinskia9533e72010-09-08 21:04:42 -070033#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */
34#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
35
Henry Ptasinskia9533e72010-09-08 21:04:42 -070036/* Global ASSERT type flag */
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070037u32 g_assert_type;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070038
Brett Rudleye69284f2010-11-16 15:45:48 -080039struct osl_info *osl_attach(void *pdev, uint bustype)
Henry Ptasinskia9533e72010-09-08 21:04:42 -070040{
Brett Rudleye69284f2010-11-16 15:45:48 -080041 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070042
Brett Rudleye69284f2010-11-16 15:45:48 -080043 osh = kmalloc(sizeof(struct osl_info), GFP_ATOMIC);
Henry Ptasinskia9533e72010-09-08 21:04:42 -070044 ASSERT(osh);
45
Brett Rudley9249ede2010-11-30 20:09:49 -080046 memset(osh, 0, sizeof(struct osl_info));
Henry Ptasinskia9533e72010-09-08 21:04:42 -070047
Henry Ptasinskia9533e72010-09-08 21:04:42 -070048 osh->magic = OS_HANDLE_MAGIC;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070049 osh->pdev = pdev;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070050 osh->bustype = bustype;
51
52 switch (bustype) {
53 case PCI_BUS:
54 case SI_BUS:
nohee ko194c6072010-10-06 11:56:28 -070055 case PCMCIA_BUS:
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -070056 osh->pub.mmbus = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070057 break;
58 case JTAG_BUS:
59 case SDIO_BUS:
60 case USB_BUS:
61 case SPI_BUS:
62 case RPC_BUS:
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -070063 osh->pub.mmbus = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070064 break;
65 default:
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -070066 ASSERT(false);
Henry Ptasinskia9533e72010-09-08 21:04:42 -070067 break;
68 }
69
Henry Ptasinskia9533e72010-09-08 21:04:42 -070070 return osh;
71}
72
Brett Rudleye69284f2010-11-16 15:45:48 -080073void osl_detach(struct osl_info *osh)
Henry Ptasinskia9533e72010-09-08 21:04:42 -070074{
75 if (osh == NULL)
76 return;
77
78 ASSERT(osh->magic == OS_HANDLE_MAGIC);
79 kfree(osh);
80}
81
Brett Rudleye69284f2010-11-16 15:45:48 -080082void *BCMFASTPATH osl_pktget(struct osl_info *osh, uint len)
Henry Ptasinskia9533e72010-09-08 21:04:42 -070083{
84 struct sk_buff *skb;
85
Jason Cooperca8c1e52010-09-14 09:45:33 -040086 skb = dev_alloc_skb(len);
87 if (skb) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -070088 skb_put(skb, len);
89 skb->priority = 0;
90
91 osh->pub.pktalloced++;
92 }
93
Jason Cooper90ea2292010-09-14 09:45:32 -040094 return (void *)skb;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070095}
96
97/* Free the driver packet. Free the tag if present */
Brett Rudleye69284f2010-11-16 15:45:48 -080098void BCMFASTPATH osl_pktfree(struct osl_info *osh, void *p, bool send)
Henry Ptasinskia9533e72010-09-08 21:04:42 -070099{
100 struct sk_buff *skb, *nskb;
101 int nest = 0;
102
103 skb = (struct sk_buff *)p;
104 ASSERT(skb);
105
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700106 /* perversion: we use skb->next to chain multi-skb packets */
107 while (skb) {
108 nskb = skb->next;
109 skb->next = NULL;
110
111 if (skb->destructor)
112 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
113 * destructor exists
114 */
115 dev_kfree_skb_any(skb);
116 else
117 /* can free immediately (even in_irq()) if destructor
118 * does not exist
119 */
120 dev_kfree_skb(skb);
121
122 osh->pub.pktalloced--;
123 nest++;
124 skb = nskb;
125 }
126}
127
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700128/* return bus # for the pci device pointed by osh->pdev */
Brett Rudleye69284f2010-11-16 15:45:48 -0800129uint osl_pci_bus(struct osl_info *osh)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700130{
131 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
132
133 return ((struct pci_dev *)osh->pdev)->bus->number;
134}
135
136/* return slot # for the pci device pointed by osh->pdev */
Brett Rudleye69284f2010-11-16 15:45:48 -0800137uint osl_pci_slot(struct osl_info *osh)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700138{
139 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
140
141 return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
142}
143
Brett Rudleye69284f2010-11-16 15:45:48 -0800144void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, u16 align_bits,
Greg Kroah-Hartman3deea902010-10-05 11:15:47 -0700145 uint *alloced, unsigned long *pap)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700146{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700147 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
148
Brett Rudley40e5c962010-10-08 13:57:13 -0700149 if (align_bits) {
150 u16 align = (1 << align_bits);
Brett Rudley8fb6b182010-11-01 17:10:15 -0700151 if (!IS_ALIGNED(PAGE_SIZE, align))
Brett Rudley40e5c962010-10-08 13:57:13 -0700152 size += align;
153 *alloced = size;
154 }
Jason Cooper90ea2292010-09-14 09:45:32 -0400155 return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700156}
157
Brett Rudleye69284f2010-11-16 15:45:48 -0800158void osl_dma_free_consistent(struct osl_info *osh, void *va, uint size,
159 unsigned long pa)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700160{
161 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
162
163 pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa);
164}
165
Brett Rudleye69284f2010-11-16 15:45:48 -0800166uint BCMFASTPATH osl_dma_map(struct osl_info *osh, void *va, uint size,
167 int direction)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700168{
169 int dir;
170
171 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
172 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
Jason Cooper90ea2292010-09-14 09:45:32 -0400173 return pci_map_single(osh->pdev, va, size, dir);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700174}
175
Brett Rudleye69284f2010-11-16 15:45:48 -0800176void BCMFASTPATH osl_dma_unmap(struct osl_info *osh, uint pa, uint size,
177 int direction)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700178{
179 int dir;
180
181 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
182 dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700183 pci_unmap_single(osh->pdev, (u32) pa, size, dir);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700184}
185
186#if defined(BCMDBG_ASSERT)
187void osl_assert(char *exp, char *file, int line)
188{
189 char tempbuf[256];
190 char *basename;
191
192 basename = strrchr(file, '/');
193 /* skip the '/' */
194 if (basename)
195 basename++;
196
197 if (!basename)
198 basename = file;
199
200#ifdef BCMDBG_ASSERT
201 snprintf(tempbuf, 256,
202 "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
203 basename, line);
204
205 /* Print assert message and give it time to be written to /var/log/messages */
206 if (!in_interrupt()) {
207 const int delay = 3;
nohee ko194c6072010-10-06 11:56:28 -0700208 printk(KERN_ERR "%s", tempbuf);
209 printk(KERN_ERR "panic in %d seconds\n", delay);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700210 set_current_state(TASK_INTERRUPTIBLE);
211 schedule_timeout(delay * HZ);
212 }
213
214 switch (g_assert_type) {
215 case 0:
nohee ko194c6072010-10-06 11:56:28 -0700216 panic(KERN_ERR "%s", tempbuf);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700217 break;
218 case 1:
nohee ko194c6072010-10-06 11:56:28 -0700219 printk(KERN_ERR "%s", tempbuf);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700220 BUG();
221 break;
222 case 2:
nohee ko194c6072010-10-06 11:56:28 -0700223 printk(KERN_ERR "%s", tempbuf);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700224 break;
225 default:
226 break;
227 }
228#endif /* BCMDBG_ASSERT */
229
230}
231#endif /* defined(BCMDBG_ASSERT) */
232