aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/ath6kl/hif
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/ath6kl/hif')
-rw-r--r--drivers/staging/ath6kl/hif/common/hif_sdio_common.h87
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h131
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c1273
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c393
4 files changed, 1884 insertions, 0 deletions
diff --git a/drivers/staging/ath6kl/hif/common/hif_sdio_common.h b/drivers/staging/ath6kl/hif/common/hif_sdio_common.h
new file mode 100644
index 00000000000..93a2adceca3
--- /dev/null
+++ b/drivers/staging/ath6kl/hif/common/hif_sdio_common.h
@@ -0,0 +1,87 @@
1//------------------------------------------------------------------------------
2// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
3//
4//
5// Permission to use, copy, modify, and/or distribute this software for any
6// purpose with or without fee is hereby granted, provided that the above
7// copyright notice and this permission notice appear in all copies.
8//
9// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16//
17//
18//------------------------------------------------------------------------------
19//==============================================================================
20// common header file for HIF modules designed for SDIO
21//
22// Author(s): ="Atheros"
23//==============================================================================
24
25#ifndef HIF_SDIO_COMMON_H_
26#define HIF_SDIO_COMMON_H_
27
28 /* SDIO manufacturer ID and Codes */
29#define MANUFACTURER_ID_AR6002_BASE 0x200
30#define MANUFACTURER_ID_AR6003_BASE 0x300
31#define MANUFACTURER_ID_AR6K_BASE_MASK 0xFF00
32#define FUNCTION_CLASS 0x0
33#define MANUFACTURER_CODE 0x271 /* Atheros */
34
35 /* Mailbox address in SDIO address space */
36#define HIF_MBOX_BASE_ADDR 0x800
37#define HIF_MBOX_WIDTH 0x800
38#define HIF_MBOX_START_ADDR(mbox) \
39 ( HIF_MBOX_BASE_ADDR + mbox * HIF_MBOX_WIDTH)
40
41#define HIF_MBOX_END_ADDR(mbox) \
42 (HIF_MBOX_START_ADDR(mbox) + HIF_MBOX_WIDTH - 1)
43
44 /* extended MBOX address for larger MBOX writes to MBOX 0*/
45#define HIF_MBOX0_EXTENDED_BASE_ADDR 0x2800
46#define HIF_MBOX0_EXTENDED_WIDTH_AR6002 (6*1024)
47#define HIF_MBOX0_EXTENDED_WIDTH_AR6003 (18*1024)
48
49 /* version 1 of the chip has only a 12K extended mbox range */
50#define HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1 0x4000
51#define HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1 (12*1024)
52
53 /* GMBOX addresses */
54#define HIF_GMBOX_BASE_ADDR 0x7000
55#define HIF_GMBOX_WIDTH 0x4000
56
57 /* for SDIO we recommend a 128-byte block size */
58#define HIF_DEFAULT_IO_BLOCK_SIZE 128
59
60 /* set extended MBOX window information for SDIO interconnects */
61static INLINE void SetExtendedMboxWindowInfo(u16 Manfid, struct hif_device_mbox_info *pInfo)
62{
63 switch (Manfid & MANUFACTURER_ID_AR6K_BASE_MASK) {
64 case MANUFACTURER_ID_AR6002_BASE :
65 /* MBOX 0 has an extended range */
66 pInfo->MboxProp[0].ExtendedAddress = HIF_MBOX0_EXTENDED_BASE_ADDR;
67 pInfo->MboxProp[0].ExtendedSize = HIF_MBOX0_EXTENDED_WIDTH_AR6002;
68 break;
69 case MANUFACTURER_ID_AR6003_BASE :
70 /* MBOX 0 has an extended range */
71 pInfo->MboxProp[0].ExtendedAddress = HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1;
72 pInfo->MboxProp[0].ExtendedSize = HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1;
73 pInfo->GMboxAddress = HIF_GMBOX_BASE_ADDR;
74 pInfo->GMboxSize = HIF_GMBOX_WIDTH;
75 break;
76 default:
77 A_ASSERT(false);
78 break;
79 }
80}
81
82/* special CCCR (func 0) registers */
83
84#define CCCR_SDIO_IRQ_MODE_REG 0xF0 /* interrupt mode register */
85#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0) /* mode to enable special 4-bit interrupt assertion without clock*/
86
87#endif /*HIF_SDIO_COMMON_H_*/
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h b/drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h
new file mode 100644
index 00000000000..ed7ad4786f5
--- /dev/null
+++ b/drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h
@@ -0,0 +1,131 @@
1//------------------------------------------------------------------------------
2// <copyright file="hif_internal.h" company="Atheros">
3// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
4//
5//
6// Permission to use, copy, modify, and/or distribute this software for any
7// purpose with or without fee is hereby granted, provided that the above
8// copyright notice and this permission notice appear in all copies.
9//
10// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17//
18//
19//------------------------------------------------------------------------------
20//==============================================================================
21// internal header file for hif layer
22//
23// Author(s): ="Atheros"
24//==============================================================================
25#ifndef _HIF_INTERNAL_H_
26#define _HIF_INTERNAL_H_
27
28#include "a_config.h"
29#include "athdefs.h"
30#include "a_osapi.h"
31#include "hif.h"
32#include "../../../common/hif_sdio_common.h"
33#include <linux/scatterlist.h>
34#define HIF_LINUX_MMC_SCATTER_SUPPORT
35
36#define BUS_REQUEST_MAX_NUM 64
37
38#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000
39#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20
40#define FLAGS_CARD_ENAB 0x02
41#define FLAGS_CARD_IRQ_UNMSK 0x04
42
43#define HIF_MBOX_BLOCK_SIZE HIF_DEFAULT_IO_BLOCK_SIZE
44#define HIF_MBOX0_BLOCK_SIZE 1
45#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
46#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
47#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
48
49typedef struct bus_request {
50 struct bus_request *next; /* link list of available requests */
51 struct bus_request *inusenext; /* link list of in use requests */
52 struct semaphore sem_req;
53 u32 address; /* request data */
54 u8 *buffer;
55 u32 length;
56 u32 request;
57 void *context;
58 int status;
59 struct hif_scatter_req_priv *pScatterReq; /* this request is a scatter request */
60} BUS_REQUEST;
61
62struct hif_device {
63 struct sdio_func *func;
64 spinlock_t asynclock;
65 struct task_struct* async_task; /* task to handle async commands */
66 struct semaphore sem_async; /* wake up for async task */
67 int async_shutdown; /* stop the async task */
68 struct completion async_completion; /* thread completion */
69 BUS_REQUEST *asyncreq; /* request for async tasklet */
70 BUS_REQUEST *taskreq; /* async tasklet data */
71 spinlock_t lock;
72 BUS_REQUEST *s_busRequestFreeQueue; /* free list */
73 BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM]; /* available bus requests */
74 void *claimedContext;
75 HTC_CALLBACKS htcCallbacks;
76 u8 *dma_buffer;
77 struct dl_list ScatterReqHead; /* scatter request list head */
78 bool scatter_enabled; /* scatter enabled flag */
79 bool is_suspend;
80 bool is_disabled;
81 atomic_t irqHandling;
82 HIF_DEVICE_POWER_CHANGE_TYPE powerConfig;
83 const struct sdio_device_id *id;
84};
85
86#define HIF_DMA_BUFFER_SIZE (32 * 1024)
87#define CMD53_FIXED_ADDRESS 1
88#define CMD53_INCR_ADDRESS 2
89
90BUS_REQUEST *hifAllocateBusRequest(struct hif_device *device);
91void hifFreeBusRequest(struct hif_device *device, BUS_REQUEST *busrequest);
92void AddToAsyncList(struct hif_device *device, BUS_REQUEST *busrequest);
93
94#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT
95
96#define MAX_SCATTER_REQUESTS 4
97#define MAX_SCATTER_ENTRIES_PER_REQ 16
98#define MAX_SCATTER_REQ_TRANSFER_SIZE 32*1024
99
100struct hif_scatter_req_priv {
101 struct hif_scatter_req *pHifScatterReq; /* HIF scatter request with allocated entries */
102 struct hif_device *device; /* this device */
103 BUS_REQUEST *busrequest; /* request associated with request */
104 /* scatter list for linux */
105 struct scatterlist sgentries[MAX_SCATTER_ENTRIES_PER_REQ];
106};
107
108#define ATH_DEBUG_SCATTER ATH_DEBUG_MAKE_MODULE_MASK(0)
109
110int SetupHIFScatterSupport(struct hif_device *device, struct hif_device_scatter_support_info *pInfo);
111void CleanupHIFScatterResources(struct hif_device *device);
112int DoHifReadWriteScatter(struct hif_device *device, BUS_REQUEST *busrequest);
113
114#else // HIF_LINUX_MMC_SCATTER_SUPPORT
115
116static inline int SetupHIFScatterSupport(struct hif_device *device, struct hif_device_scatter_support_info *pInfo)
117{
118 return A_ENOTSUP;
119}
120
121static inline int DoHifReadWriteScatter(struct hif_device *device, BUS_REQUEST *busrequest)
122{
123 return A_ENOTSUP;
124}
125
126#define CleanupHIFScatterResources(d) { }
127
128#endif // HIF_LINUX_MMC_SCATTER_SUPPORT
129
130#endif // _HIF_INTERNAL_H_
131
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c
new file mode 100644
index 00000000000..5f5d67720fa
--- /dev/null
+++ b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c
@@ -0,0 +1,1273 @@
1//------------------------------------------------------------------------------
2// <copyright file="hif.c" company="Atheros">
3// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
4//
5//
6// Permission to use, copy, modify, and/or distribute this software for any
7// purpose with or without fee is hereby granted, provided that the above
8// copyright notice and this permission notice appear in all copies.
9//
10// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17//
18//
19//------------------------------------------------------------------------------
20//==============================================================================
21// HIF layer reference implementation for Linux Native MMC stack
22//
23// Author(s): ="Atheros"
24//==============================================================================
25#include <linux/mmc/card.h>
26#include <linux/mmc/mmc.h>
27#include <linux/mmc/host.h>
28#include <linux/mmc/sdio_func.h>
29#include <linux/mmc/sdio_ids.h>
30#include <linux/mmc/sdio.h>
31#include <linux/mmc/sd.h>
32#include <linux/kthread.h>
33
34/* by default setup a bounce buffer for the data packets, if the underlying host controller driver
35 does not use DMA you may be able to skip this step and save the memory allocation and transfer time */
36#define HIF_USE_DMA_BOUNCE_BUFFER 1
37#include "hif_internal.h"
38#define ATH_MODULE_NAME hif
39#include "a_debug.h"
40#include "hw/mbox_host_reg.h"
41
42#if HIF_USE_DMA_BOUNCE_BUFFER
43/* macro to check if DMA buffer is WORD-aligned and DMA-able. Most host controllers assume the
44 * buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
45 * virt_addr_valid check fails on stack memory.
46 */
47#define BUFFER_NEEDS_BOUNCE(buffer) (((unsigned long)(buffer) & 0x3) || !virt_addr_valid((buffer)))
48#else
49#define BUFFER_NEEDS_BOUNCE(buffer) (false)
50#endif
51
52/* ATHENV */
53#if defined(CONFIG_PM)
54#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
55#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
56#endif /* CONFIG_PM */
57static void delHifDevice(struct hif_device * device);
58static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, unsigned char byte);
59static int Func0_CMD52ReadByte(struct mmc_card *card, unsigned int address, unsigned char *byte);
60
61static int hifEnableFunc(struct hif_device *device, struct sdio_func *func);
62static int hifDisableFunc(struct hif_device *device, struct sdio_func *func);
63OSDRV_CALLBACKS osdrvCallbacks;
64
65int reset_sdio_on_unload = 0;
66module_param(reset_sdio_on_unload, int, 0644);
67
68extern u32 nohifscattersupport;
69
70static struct hif_device *ath6kl_alloc_hifdev(struct sdio_func *func)
71{
72 struct hif_device *hifdevice;
73
74 hifdevice = kzalloc(sizeof(struct hif_device), GFP_KERNEL);
75
76#if HIF_USE_DMA_BOUNCE_BUFFER
77 hifdevice->dma_buffer = kmalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL);
78#endif
79 hifdevice->func = func;
80 hifdevice->powerConfig = HIF_DEVICE_POWER_UP;
81 sdio_set_drvdata(func, hifdevice);
82
83 return hifdevice;
84}
85
86static struct hif_device *ath6kl_get_hifdev(struct sdio_func *func)
87{
88 return (struct hif_device *) sdio_get_drvdata(func);
89}
90
91static const struct sdio_device_id ath6kl_hifdev_ids[] = {
92 { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x0)) },
93 { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x1)) },
94 { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0)) },
95 { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1)) },
96 { /* null */ },
97};
98
99MODULE_DEVICE_TABLE(sdio, ath6kl_hifdev_ids);
100
101static int ath6kl_hifdev_probe(struct sdio_func *func,
102 const struct sdio_device_id *id)
103{
104 int ret;
105 struct hif_device *device;
106 int count;
107
108 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
109 ("ath6kl: Function: 0x%X, Vendor ID: 0x%X, "
110 "Device ID: 0x%X, block size: 0x%X/0x%X\n",
111 func->num, func->vendor, func->device,
112 func->max_blksize, func->cur_blksize));
113
114 ath6kl_alloc_hifdev(func);
115 device = ath6kl_get_hifdev(func);
116
117 device->id = id;
118 device->is_disabled = true;
119
120 spin_lock_init(&device->lock);
121 spin_lock_init(&device->asynclock);
122
123 DL_LIST_INIT(&device->ScatterReqHead);
124
125 /* Try to allow scatter unless globally overridden */
126 if (!nohifscattersupport)
127 device->scatter_enabled = true;
128
129 A_MEMZERO(device->busRequest, sizeof(device->busRequest));
130
131 for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) {
132 sema_init(&device->busRequest[count].sem_req, 0);
133 hifFreeBusRequest(device, &device->busRequest[count]);
134 }
135
136 sema_init(&device->sem_async, 0);
137
138 ret = hifEnableFunc(device, func);
139
140 return ret;
141}
142
143static void ath6kl_hifdev_remove(struct sdio_func *func)
144{
145 int status = 0;
146 struct hif_device *device;
147
148 device = ath6kl_get_hifdev(func);
149 if (device->claimedContext != NULL)
150 status = osdrvCallbacks.
151 deviceRemovedHandler(device->claimedContext, device);
152
153 if (device->is_disabled)
154 device->is_disabled = false;
155 else
156 status = hifDisableFunc(device, func);
157
158 CleanupHIFScatterResources(device);
159
160 delHifDevice(device);
161}
162
163#if defined(CONFIG_PM)
164static int ath6kl_hifdev_suspend(struct device *dev)
165{
166 struct sdio_func *func = dev_to_sdio_func(dev);
167 int status = 0;
168 struct hif_device *device;
169
170 device = ath6kl_get_hifdev(func);
171
172 if (device && device->claimedContext &&
173 osdrvCallbacks.deviceSuspendHandler) {
174 /* set true first for PowerStateChangeNotify(..) */
175 device->is_suspend = true;
176 status = osdrvCallbacks.
177 deviceSuspendHandler(device->claimedContext);
178 if (status)
179 device->is_suspend = false;
180 }
181
182 CleanupHIFScatterResources(device);
183
184 switch (status) {
185 case 0:
186 return 0;
187 case A_EBUSY:
188 /* Hack for kernel in order to support deep sleep and wow */
189 return -EBUSY;
190 default:
191 return -1;
192 }
193}
194
195static int ath6kl_hifdev_resume(struct device *dev)
196{
197 struct sdio_func *func = dev_to_sdio_func(dev);
198 int status = 0;
199 struct hif_device *device;
200
201 device = ath6kl_get_hifdev(func);
202 if (device && device->claimedContext &&
203 osdrvCallbacks.deviceSuspendHandler) {
204 status = osdrvCallbacks.
205 deviceResumeHandler(device->claimedContext);
206 if (status == 0)
207 device->is_suspend = false;
208 }
209
210 return status;
211}
212
213static const struct dev_pm_ops ath6kl_hifdev_pmops = {
214 .suspend = ath6kl_hifdev_suspend,
215 .resume = ath6kl_hifdev_resume,
216};
217#endif /* CONFIG_PM */
218
219static struct sdio_driver ath6kl_hifdev_driver = {
220 .name = "ath6kl_hifdev",
221 .id_table = ath6kl_hifdev_ids,
222 .probe = ath6kl_hifdev_probe,
223 .remove = ath6kl_hifdev_remove,
224#if defined(CONFIG_PM)
225 .drv = {
226 .pm = &ath6kl_hifdev_pmops,
227 },
228#endif
229};
230
231/* make sure we only unregister when registered. */
232static int registered = 0;
233
234extern u32 onebitmode;
235extern u32 busspeedlow;
236extern u32 debughif;
237
238static void ResetAllCards(void);
239
240#ifdef DEBUG
241
242ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif,
243 "hif",
244 "(Linux MMC) Host Interconnect Framework",
245 ATH_DEBUG_MASK_DEFAULTS,
246 0,
247 NULL);
248
249#endif
250
251
252/* ------ Functions ------ */
253int HIFInit(OSDRV_CALLBACKS *callbacks)
254{
255 int r;
256 AR_DEBUG_ASSERT(callbacks != NULL);
257
258 A_REGISTER_MODULE_DEBUG_INFO(hif);
259
260 /* store the callback handlers */
261 osdrvCallbacks = *callbacks;
262
263 /* Register with bus driver core */
264 registered = 1;
265
266 r = sdio_register_driver(&ath6kl_hifdev_driver);
267 if (r < 0)
268 return r;
269
270 return 0;
271}
272
273static int
274__HIFReadWrite(struct hif_device *device,
275 u32 address,
276 u8 *buffer,
277 u32 length,
278 u32 request,
279 void *context)
280{
281 u8 opcode;
282 int status = 0;
283 int ret;
284 u8 *tbuffer;
285 bool bounced = false;
286
287 AR_DEBUG_ASSERT(device != NULL);
288 AR_DEBUG_ASSERT(device->func != NULL);
289
290 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: 0x%p, buffer:0x%p (addr:0x%X)\n",
291 device, buffer, address));
292
293 do {
294 if (request & HIF_EXTENDED_IO) {
295 //AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Command type: CMD53\n"));
296 } else {
297 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
298 ("AR6000: Invalid command type: 0x%08x\n", request));
299 status = A_EINVAL;
300 break;
301 }
302
303 if (request & HIF_BLOCK_BASIS) {
304 /* round to whole block length size */
305 length = (length / HIF_MBOX_BLOCK_SIZE) * HIF_MBOX_BLOCK_SIZE;
306 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
307 ("AR6000: Block mode (BlockLen: %d)\n",
308 length));
309 } else if (request & HIF_BYTE_BASIS) {
310 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
311 ("AR6000: Byte mode (BlockLen: %d)\n",
312 length));
313 } else {
314 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
315 ("AR6000: Invalid data mode: 0x%08x\n", request));
316 status = A_EINVAL;
317 break;
318 }
319
320#if 0
321 /* useful for checking register accesses */
322 if (length & 0x3) {
323 A_PRINTF(KERN_ALERT"AR6000: HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n",
324 request & HIF_WRITE ? "write":"read", address, length);
325 }
326#endif
327
328 if (request & HIF_WRITE) {
329 if ((address >= HIF_MBOX_START_ADDR(0)) &&
330 (address <= HIF_MBOX_END_ADDR(3)))
331 {
332
333 AR_DEBUG_ASSERT(length <= HIF_MBOX_WIDTH);
334
335 /*
336 * Mailbox write. Adjust the address so that the last byte
337 * falls on the EOM address.
338 */
339 address += (HIF_MBOX_WIDTH - length);
340 }
341 }
342
343 if (request & HIF_FIXED_ADDRESS) {
344 opcode = CMD53_FIXED_ADDRESS;
345 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Fixed 0x%X\n", address));
346 } else if (request & HIF_INCREMENTAL_ADDRESS) {
347 opcode = CMD53_INCR_ADDRESS;
348 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Incremental 0x%X\n", address));
349 } else {
350 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
351 ("AR6000: Invalid address mode: 0x%08x\n", request));
352 status = A_EINVAL;
353 break;
354 }
355
356 if (request & HIF_WRITE) {
357#if HIF_USE_DMA_BOUNCE_BUFFER
358 if (BUFFER_NEEDS_BOUNCE(buffer)) {
359 AR_DEBUG_ASSERT(device->dma_buffer != NULL);
360 tbuffer = device->dma_buffer;
361 /* copy the write data to the dma buffer */
362 AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
363 memcpy(tbuffer, buffer, length);
364 bounced = true;
365 } else {
366 tbuffer = buffer;
367 }
368#else
369 tbuffer = buffer;
370#endif
371 if (opcode == CMD53_FIXED_ADDRESS) {
372 ret = sdio_writesb(device->func, address, tbuffer, length);
373 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writesb ret=%d address: 0x%X, len: %d, 0x%X\n",
374 ret, address, length, *(int *)tbuffer));
375 } else {
376 ret = sdio_memcpy_toio(device->func, address, tbuffer, length);
377 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writeio ret=%d address: 0x%X, len: %d, 0x%X\n",
378 ret, address, length, *(int *)tbuffer));
379 }
380 } else if (request & HIF_READ) {
381#if HIF_USE_DMA_BOUNCE_BUFFER
382 if (BUFFER_NEEDS_BOUNCE(buffer)) {
383 AR_DEBUG_ASSERT(device->dma_buffer != NULL);
384 AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
385 tbuffer = device->dma_buffer;
386 bounced = true;
387 } else {
388 tbuffer = buffer;
389 }
390#else
391 tbuffer = buffer;
392#endif
393 if (opcode == CMD53_FIXED_ADDRESS) {
394 ret = sdio_readsb(device->func, tbuffer, address, length);
395 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readsb ret=%d address: 0x%X, len: %d, 0x%X\n",
396 ret, address, length, *(int *)tbuffer));
397 } else {
398 ret = sdio_memcpy_fromio(device->func, tbuffer, address, length);
399 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readio ret=%d address: 0x%X, len: %d, 0x%X\n",
400 ret, address, length, *(int *)tbuffer));
401 }
402#if HIF_USE_DMA_BOUNCE_BUFFER
403 if (bounced) {
404 /* copy the read data from the dma buffer */
405 memcpy(buffer, tbuffer, length);
406 }
407#endif
408 } else {
409 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
410 ("AR6000: Invalid direction: 0x%08x\n", request));
411 status = A_EINVAL;
412 break;
413 }
414
415 if (ret) {
416 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
417 ("AR6000: SDIO bus operation failed! MMC stack returned : %d \n", ret));
418 status = A_ERROR;
419 }
420 } while (false);
421
422 return status;
423}
424
425void AddToAsyncList(struct hif_device *device, BUS_REQUEST *busrequest)
426{
427 unsigned long flags;
428 BUS_REQUEST *async;
429 BUS_REQUEST *active;
430
431 spin_lock_irqsave(&device->asynclock, flags);
432 active = device->asyncreq;
433 if (active == NULL) {
434 device->asyncreq = busrequest;
435 device->asyncreq->inusenext = NULL;
436 } else {
437 for (async = device->asyncreq;
438 async != NULL;
439 async = async->inusenext) {
440 active = async;
441 }
442 active->inusenext = busrequest;
443 busrequest->inusenext = NULL;
444 }
445 spin_unlock_irqrestore(&device->asynclock, flags);
446}
447
448
449/* queue a read/write request */
450int
451HIFReadWrite(struct hif_device *device,
452 u32 address,
453 u8 *buffer,
454 u32 length,
455 u32 request,
456 void *context)
457{
458 int status = 0;
459 BUS_REQUEST *busrequest;
460
461
462 AR_DEBUG_ASSERT(device != NULL);
463 AR_DEBUG_ASSERT(device->func != NULL);
464
465 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: %p addr:0x%X\n", device,address));
466
467 do {
468 if ((request & HIF_ASYNCHRONOUS) || (request & HIF_SYNCHRONOUS)){
469 /* serialize all requests through the async thread */
470 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Execution mode: %s\n",
471 (request & HIF_ASYNCHRONOUS)?"Async":"Synch"));
472 busrequest = hifAllocateBusRequest(device);
473 if (busrequest == NULL) {
474 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
475 ("AR6000: no async bus requests available (%s, addr:0x%X, len:%d) \n",
476 request & HIF_READ ? "READ":"WRITE", address, length));
477 return A_ERROR;
478 }
479 busrequest->address = address;
480 busrequest->buffer = buffer;
481 busrequest->length = length;
482 busrequest->request = request;
483 busrequest->context = context;
484
485 AddToAsyncList(device, busrequest);
486
487 if (request & HIF_SYNCHRONOUS) {
488 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued sync req: 0x%lX\n", (unsigned long)busrequest));
489
490 /* wait for completion */
491 up(&device->sem_async);
492 if (down_interruptible(&busrequest->sem_req) != 0) {
493 /* interrupted, exit */
494 return A_ERROR;
495 } else {
496 int status = busrequest->status;
497 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: sync return freeing 0x%lX: 0x%X\n",
498 (unsigned long)busrequest, busrequest->status));
499 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: freeing req: 0x%X\n", (unsigned int)request));
500 hifFreeBusRequest(device, busrequest);
501 return status;
502 }
503 } else {
504 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued async req: 0x%lX\n", (unsigned long)busrequest));
505 up(&device->sem_async);
506 return A_PENDING;
507 }
508 } else {
509 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
510 ("AR6000: Invalid execution mode: 0x%08x\n", (unsigned int)request));
511 status = A_EINVAL;
512 break;
513 }
514 } while(0);
515
516 return status;
517}
518/* thread to serialize all requests, both sync and async */
519static int async_task(void *param)
520 {
521 struct hif_device *device;
522 BUS_REQUEST *request;
523 int status;
524 unsigned long flags;
525
526 device = (struct hif_device *)param;
527 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task\n"));
528 set_current_state(TASK_INTERRUPTIBLE);
529 while(!device->async_shutdown) {
530 /* wait for work */
531 if (down_interruptible(&device->sem_async) != 0) {
532 /* interrupted, exit */
533 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task interrupted\n"));
534 break;
535 }
536 if (device->async_shutdown) {
537 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task stopping\n"));
538 break;
539 }
540 /* we want to hold the host over multiple cmds if possible, but holding the host blocks card interrupts */
541 sdio_claim_host(device->func);
542 spin_lock_irqsave(&device->asynclock, flags);
543 /* pull the request to work on */
544 while (device->asyncreq != NULL) {
545 request = device->asyncreq;
546 if (request->inusenext != NULL) {
547 device->asyncreq = request->inusenext;
548 } else {
549 device->asyncreq = NULL;
550 }
551 spin_unlock_irqrestore(&device->asynclock, flags);
552 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task processing req: 0x%lX\n", (unsigned long)request));
553
554 if (request->pScatterReq != NULL) {
555 A_ASSERT(device->scatter_enabled);
556 /* this is a queued scatter request, pass the request to scatter routine which
557 * executes it synchronously, note, no need to free the request since scatter requests
558 * are maintained on a separate list */
559 status = DoHifReadWriteScatter(device,request);
560 } else {
561 /* call HIFReadWrite in sync mode to do the work */
562 status = __HIFReadWrite(device, request->address, request->buffer,
563 request->length, request->request & ~HIF_SYNCHRONOUS, NULL);
564 if (request->request & HIF_ASYNCHRONOUS) {
565 void *context = request->context;
566 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task freeing req: 0x%lX\n", (unsigned long)request));
567 hifFreeBusRequest(device, request);
568 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task completion routine req: 0x%lX\n", (unsigned long)request));
569 device->htcCallbacks.rwCompletionHandler(context, status);
570 } else {
571 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task upping req: 0x%lX\n", (unsigned long)request));
572 request->status = status;
573 up(&request->sem_req);
574 }
575 }
576 spin_lock_irqsave(&device->asynclock, flags);
577 }
578 spin_unlock_irqrestore(&device->asynclock, flags);
579 sdio_release_host(device->func);
580 }
581
582 complete_and_exit(&device->async_completion, 0);
583 return 0;
584}
585
586static s32 IssueSDCommand(struct hif_device *device, u32 opcode, u32 arg, u32 flags, u32 *resp)
587{
588 struct mmc_command cmd;
589 s32 err;
590 struct mmc_host *host;
591 struct sdio_func *func;
592
593 func = device->func;
594 host = func->card->host;
595
596 memset(&cmd, 0, sizeof(struct mmc_command));
597 cmd.opcode = opcode;
598 cmd.arg = arg;
599 cmd.flags = flags;
600 err = mmc_wait_for_cmd(host, &cmd, 3);
601
602 if ((!err) && (resp)) {
603 *resp = cmd.resp[0];
604 }
605
606 return err;
607}
608
609int ReinitSDIO(struct hif_device *device)
610{
611 s32 err;
612 struct mmc_host *host;
613 struct mmc_card *card;
614 struct sdio_func *func;
615 u8 cmd52_resp;
616 u32 clock;
617
618 func = device->func;
619 card = func->card;
620 host = card->host;
621
622 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +ReinitSDIO \n"));
623 sdio_claim_host(func);
624
625 do {
626 if (!device->is_suspend) {
627 u32 resp;
628 u16 rca;
629 u32 i;
630 int bit = fls(host->ocr_avail) - 1;
631 /* emulate the mmc_power_up(...) */
632 host->ios.vdd = bit;
633 host->ios.chip_select = MMC_CS_DONTCARE;
634 host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
635 host->ios.power_mode = MMC_POWER_UP;
636 host->ios.bus_width = MMC_BUS_WIDTH_1;
637 host->ios.timing = MMC_TIMING_LEGACY;
638 host->ops->set_ios(host, &host->ios);
639 /*
640 * This delay should be sufficient to allow the power supply
641 * to reach the minimum voltage.
642 */
643 msleep(2);
644
645 host->ios.clock = host->f_min;
646 host->ios.power_mode = MMC_POWER_ON;
647 host->ops->set_ios(host, &host->ios);
648
649 /*
650 * This delay must be at least 74 clock sizes, or 1 ms, or the
651 * time required to reach a stable voltage.
652 */
653 msleep(2);
654
655 /* Issue CMD0. Goto idle state */
656 host->ios.chip_select = MMC_CS_HIGH;
657 host->ops->set_ios(host, &host->ios);
658 msleep(1);
659 err = IssueSDCommand(device, MMC_GO_IDLE_STATE, 0, (MMC_RSP_NONE | MMC_CMD_BC), NULL);
660 host->ios.chip_select = MMC_CS_DONTCARE;
661 host->ops->set_ios(host, &host->ios);
662 msleep(1);
663 host->use_spi_crc = 0;
664
665 if (err) {
666 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD0 failed : %d \n",err));
667 break;
668 }
669
670 if (!host->ocr) {
671 /* Issue CMD5, arg = 0 */
672 err = IssueSDCommand(device, SD_IO_SEND_OP_COND, 0, (MMC_RSP_R4 | MMC_CMD_BCR), &resp);
673 if (err) {
674 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err));
675 break;
676 }
677 host->ocr = resp;
678 }
679
680 /* Issue CMD5, arg = ocr. Wait till card is ready */
681 for (i=0;i<100;i++) {
682 err = IssueSDCommand(device, SD_IO_SEND_OP_COND, host->ocr, (MMC_RSP_R4 | MMC_CMD_BCR), &resp);
683 if (err) {
684 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err));
685 break;
686 }
687 if (resp & MMC_CARD_BUSY) {
688 break;
689 }
690 msleep(10);
691 }
692
693 if ((i == 100) || (err)) {
694 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: card in not ready : %d %d \n",i,err));
695 break;
696 }
697
698 /* Issue CMD3, get RCA */
699 err = IssueSDCommand(device, SD_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6 | MMC_CMD_BCR, &resp);
700 if (err) {
701 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD3 failed : %d \n",err));
702 break;
703 }
704 rca = resp >> 16;
705 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
706 host->ops->set_ios(host, &host->ios);
707
708 /* Issue CMD7, select card */
709 err = IssueSDCommand(device, MMC_SELECT_CARD, (rca << 16), MMC_RSP_R1 | MMC_CMD_AC, NULL);
710 if (err) {
711 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD7 failed : %d \n",err));
712 break;
713 }
714 }
715
716 /* Enable high speed */
717 if (card->host->caps & MMC_CAP_SD_HIGHSPEED) {
718 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("ReinitSDIO: Set high speed mode\n"));
719 err = Func0_CMD52ReadByte(card, SDIO_CCCR_SPEED, &cmd52_resp);
720 if (err) {
721 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 read to CCCR speed register failed : %d \n",err));
722 card->state &= ~MMC_STATE_HIGHSPEED;
723 /* no need to break */
724 } else {
725 err = Func0_CMD52WriteByte(card, SDIO_CCCR_SPEED, (cmd52_resp | SDIO_SPEED_EHS));
726 if (err) {
727 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 write to CCCR speed register failed : %d \n",err));
728 break;
729 }
730 mmc_card_set_highspeed(card);
731 host->ios.timing = MMC_TIMING_SD_HS;
732 host->ops->set_ios(host, &host->ios);
733 }
734 }
735
736 /* Set clock */
737 if (mmc_card_highspeed(card)) {
738 clock = 50000000;
739 } else {
740 clock = card->cis.max_dtr;
741 }
742
743 if (clock > host->f_max) {
744 clock = host->f_max;
745 }
746 host->ios.clock = clock;
747 host->ops->set_ios(host, &host->ios);
748
749
750 if (card->host->caps & MMC_CAP_4_BIT_DATA) {
751 /* CMD52: Set bus width & disable card detect resistor */
752 err = Func0_CMD52WriteByte(card, SDIO_CCCR_IF, SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_4BIT);
753 if (err) {
754 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 to set bus mode failed : %d \n",err));
755 break;
756 }
757 host->ios.bus_width = MMC_BUS_WIDTH_4;
758 host->ops->set_ios(host, &host->ios);
759 }
760 } while (0);
761
762 sdio_release_host(func);
763 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -ReinitSDIO \n"));
764
765 return (err) ? A_ERROR : 0;
766}
767
768int
769PowerStateChangeNotify(struct hif_device *device, HIF_DEVICE_POWER_CHANGE_TYPE config)
770{
771 int status = 0;
772#if defined(CONFIG_PM)
773 struct sdio_func *func = device->func;
774 int old_reset_val;
775 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +PowerStateChangeNotify %d\n", config));
776 switch (config) {
777 case HIF_DEVICE_POWER_DOWN:
778 case HIF_DEVICE_POWER_CUT:
779 old_reset_val = reset_sdio_on_unload;
780 reset_sdio_on_unload = 1;
781 status = hifDisableFunc(device, func);
782 reset_sdio_on_unload = old_reset_val;
783 if (!device->is_suspend) {
784 struct mmc_host *host = func->card->host;
785 host->ios.clock = 0;
786 host->ios.vdd = 0;
787 host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
788 host->ios.chip_select = MMC_CS_DONTCARE;
789 host->ios.power_mode = MMC_POWER_OFF;
790 host->ios.bus_width = MMC_BUS_WIDTH_1;
791 host->ios.timing = MMC_TIMING_LEGACY;
792 host->ops->set_ios(host, &host->ios);
793 }
794 break;
795 case HIF_DEVICE_POWER_UP:
796 if (device->powerConfig == HIF_DEVICE_POWER_CUT) {
797 status = ReinitSDIO(device);
798 }
799 if (status == 0) {
800 status = hifEnableFunc(device, func);
801 }
802 break;
803 }
804 device->powerConfig = config;
805
806 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -PowerStateChangeNotify\n"));
807#endif
808 return status;
809}
810
811int
812HIFConfigureDevice(struct hif_device *device, HIF_DEVICE_CONFIG_OPCODE opcode,
813 void *config, u32 configLen)
814{
815 u32 count;
816 int status = 0;
817
818 switch(opcode) {
819 case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
820 ((u32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE;
821 ((u32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE;
822 ((u32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE;
823 ((u32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE;
824 break;
825
826 case HIF_DEVICE_GET_MBOX_ADDR:
827 for (count = 0; count < 4; count ++) {
828 ((u32 *)config)[count] = HIF_MBOX_START_ADDR(count);
829 }
830
831 if (configLen >= sizeof(struct hif_device_mbox_info)) {
832 SetExtendedMboxWindowInfo((u16)device->func->device,
833 (struct hif_device_mbox_info *)config);
834 }
835
836 break;
837 case HIF_DEVICE_GET_IRQ_PROC_MODE:
838 *((HIF_DEVICE_IRQ_PROCESSING_MODE *)config) = HIF_DEVICE_IRQ_SYNC_ONLY;
839 break;
840 case HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT:
841 if (!device->scatter_enabled) {
842 return A_ENOTSUP;
843 }
844 status = SetupHIFScatterSupport(device, (struct hif_device_scatter_support_info *)config);
845 if (status) {
846 device->scatter_enabled = false;
847 }
848 break;
849 case HIF_DEVICE_GET_OS_DEVICE:
850 /* pass back a pointer to the SDIO function's "dev" struct */
851 ((struct hif_device_os_device_info *)config)->pOSDevice = &device->func->dev;
852 break;
853 case HIF_DEVICE_POWER_STATE_CHANGE:
854 status = PowerStateChangeNotify(device, *(HIF_DEVICE_POWER_CHANGE_TYPE *)config);
855 break;
856 default:
857 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
858 ("AR6000: Unsupported configuration opcode: %d\n", opcode));
859 status = A_ERROR;
860 }
861
862 return status;
863}
864
865void
866HIFShutDownDevice(struct hif_device *device)
867{
868 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +HIFShutDownDevice\n"));
869 if (device != NULL) {
870 AR_DEBUG_ASSERT(device->func != NULL);
871 } else {
872 /* since we are unloading the driver anyways, reset all cards in case the SDIO card
873 * is externally powered and we are unloading the SDIO stack. This avoids the problem when
874 * the SDIO stack is reloaded and attempts are made to re-enumerate a card that is already
875 * enumerated */
876 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFShutDownDevice, resetting\n"));
877 ResetAllCards();
878
879 /* Unregister with bus driver core */
880 if (registered) {
881 registered = 0;
882 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
883 ("AR6000: Unregistering with the bus driver\n"));
884 sdio_unregister_driver(&ath6kl_hifdev_driver);
885 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
886 ("AR6000: Unregistered\n"));
887 }
888 }
889 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -HIFShutDownDevice\n"));
890}
891
892static void
893hifIRQHandler(struct sdio_func *func)
894{
895 int status;
896 struct hif_device *device;
897 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifIRQHandler\n"));
898
899 device = ath6kl_get_hifdev(func);
900 atomic_set(&device->irqHandling, 1);
901 /* release the host during ints so we can pick it back up when we process cmds */
902 sdio_release_host(device->func);
903 status = device->htcCallbacks.dsrHandler(device->htcCallbacks.context);
904 sdio_claim_host(device->func);
905 atomic_set(&device->irqHandling, 0);
906 AR_DEBUG_ASSERT(status == 0 || status == A_ECANCELED);
907 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifIRQHandler\n"));
908}
909
910/* handle HTC startup via thread*/
911static int startup_task(void *param)
912{
913 struct hif_device *device;
914
915 device = (struct hif_device *)param;
916 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: call HTC from startup_task\n"));
917 /* start up inform DRV layer */
918 if ((osdrvCallbacks.deviceInsertedHandler(osdrvCallbacks.context,device)) != 0) {
919 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device rejected\n"));
920 }
921 return 0;
922}
923
924#if defined(CONFIG_PM)
925static int enable_task(void *param)
926{
927 struct hif_device *device;
928 device = (struct hif_device *)param;
929 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: call from resume_task\n"));
930
931 /* start up inform DRV layer */
932 if (device &&
933 device->claimedContext &&
934 osdrvCallbacks.devicePowerChangeHandler &&
935 osdrvCallbacks.devicePowerChangeHandler(device->claimedContext, HIF_DEVICE_POWER_UP) != 0)
936 {
937 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device rejected\n"));
938 }
939
940 return 0;
941}
942#endif
943
944void
945HIFAckInterrupt(struct hif_device *device)
946{
947 AR_DEBUG_ASSERT(device != NULL);
948
949 /* Acknowledge our function IRQ */
950}
951
952void
953HIFUnMaskInterrupt(struct hif_device *device)
954{
955 int ret;
956
957 AR_DEBUG_ASSERT(device != NULL);
958 AR_DEBUG_ASSERT(device->func != NULL);
959
960 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFUnMaskInterrupt\n"));
961
962 /* Register the IRQ Handler */
963 sdio_claim_host(device->func);
964 ret = sdio_claim_irq(device->func, hifIRQHandler);
965 sdio_release_host(device->func);
966 AR_DEBUG_ASSERT(ret == 0);
967}
968
969void HIFMaskInterrupt(struct hif_device *device)
970{
971 int ret;
972 AR_DEBUG_ASSERT(device != NULL);
973 AR_DEBUG_ASSERT(device->func != NULL);
974
975 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFMaskInterrupt\n"));
976
977 /* Mask our function IRQ */
978 sdio_claim_host(device->func);
979 while (atomic_read(&device->irqHandling)) {
980 sdio_release_host(device->func);
981 schedule_timeout(HZ/10);
982 sdio_claim_host(device->func);
983 }
984 ret = sdio_release_irq(device->func);
985 sdio_release_host(device->func);
986 AR_DEBUG_ASSERT(ret == 0);
987}
988
989BUS_REQUEST *hifAllocateBusRequest(struct hif_device *device)
990{
991 BUS_REQUEST *busrequest;
992 unsigned long flag;
993
994 /* Acquire lock */
995 spin_lock_irqsave(&device->lock, flag);
996
997 /* Remove first in list */
998 if((busrequest = device->s_busRequestFreeQueue) != NULL)
999 {
1000 device->s_busRequestFreeQueue = busrequest->next;
1001 }
1002 /* Release lock */
1003 spin_unlock_irqrestore(&device->lock, flag);
1004 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifAllocateBusRequest: 0x%p\n", busrequest));
1005 return busrequest;
1006}
1007
1008void
1009hifFreeBusRequest(struct hif_device *device, BUS_REQUEST *busrequest)
1010{
1011 unsigned long flag;
1012
1013 AR_DEBUG_ASSERT(busrequest != NULL);
1014 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifFreeBusRequest: 0x%p\n", busrequest));
1015 /* Acquire lock */
1016 spin_lock_irqsave(&device->lock, flag);
1017
1018
1019 /* Insert first in list */
1020 busrequest->next = device->s_busRequestFreeQueue;
1021 busrequest->inusenext = NULL;
1022 device->s_busRequestFreeQueue = busrequest;
1023
1024 /* Release lock */
1025 spin_unlock_irqrestore(&device->lock, flag);
1026}
1027
1028static int hifDisableFunc(struct hif_device *device, struct sdio_func *func)
1029{
1030 int ret;
1031 int status = 0;
1032
1033 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDisableFunc\n"));
1034 device = ath6kl_get_hifdev(func);
1035 if (!IS_ERR(device->async_task)) {
1036 init_completion(&device->async_completion);
1037 device->async_shutdown = 1;
1038 up(&device->sem_async);
1039 wait_for_completion(&device->async_completion);
1040 device->async_task = NULL;
1041 }
1042 /* Disable the card */
1043 sdio_claim_host(device->func);
1044 ret = sdio_disable_func(device->func);
1045 if (ret) {
1046 status = A_ERROR;
1047 }
1048
1049 if (reset_sdio_on_unload) {
1050 /* reset the SDIO interface. This is useful in automated testing where the card
1051 * does not need to be removed at the end of the test. It is expected that the user will
1052 * also unload/reload the host controller driver to force the bus driver to re-enumerate the slot */
1053 AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("AR6000: reseting SDIO card back to uninitialized state \n"));
1054
1055 /* NOTE : sdio_f0_writeb() cannot be used here, that API only allows access
1056 * to undefined registers in the range of: 0xF0-0xFF */
1057
1058 ret = Func0_CMD52WriteByte(device->func->card, SDIO_CCCR_ABORT, (1 << 3));
1059 if (ret) {
1060 status = A_ERROR;
1061 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: reset failed : %d \n",ret));
1062 }
1063 }
1064
1065 sdio_release_host(device->func);
1066
1067 if (status == 0) {
1068 device->is_disabled = true;
1069 }
1070 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDisableFunc\n"));
1071
1072 return status;
1073}
1074
1075static int hifEnableFunc(struct hif_device *device, struct sdio_func *func)
1076{
1077 struct task_struct* pTask;
1078 const char *taskName = NULL;
1079 int (*taskFunc)(void *) = NULL;
1080 int ret = 0;
1081
1082 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifEnableFunc\n"));
1083 device = ath6kl_get_hifdev(func);
1084
1085 if (device->is_disabled) {
1086 /* enable the SDIO function */
1087 sdio_claim_host(func);
1088
1089 if ((device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK) >= MANUFACTURER_ID_AR6003_BASE) {
1090 /* enable 4-bit ASYNC interrupt on AR6003 or later devices */
1091 ret = Func0_CMD52WriteByte(func->card, CCCR_SDIO_IRQ_MODE_REG, SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
1092 if (ret) {
1093 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: failed to enable 4-bit ASYNC IRQ mode %d \n",ret));
1094 sdio_release_host(func);
1095 return ret;
1096 }
1097 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: 4-bit ASYNC IRQ mode enabled\n"));
1098 }
1099 /* give us some time to enable, in ms */
1100 func->enable_timeout = 100;
1101 ret = sdio_enable_func(func);
1102 if (ret) {
1103 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to enable AR6K: 0x%X\n",
1104 __FUNCTION__, ret));
1105 sdio_release_host(func);
1106 return ret;
1107 }
1108 ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
1109 sdio_release_host(func);
1110 if (ret) {
1111 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to set block size 0x%x AR6K: 0x%X\n",
1112 __FUNCTION__, HIF_MBOX_BLOCK_SIZE, ret));
1113 return ret;
1114 }
1115 device->is_disabled = false;
1116 /* create async I/O thread */
1117 if (!device->async_task) {
1118 device->async_shutdown = 0;
1119 device->async_task = kthread_create(async_task,
1120 (void *)device,
1121 "AR6K Async");
1122 if (IS_ERR(device->async_task)) {
1123 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create async task\n", __FUNCTION__));
1124 return -ENOMEM;
1125 }
1126 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start async task\n"));
1127 wake_up_process(device->async_task );
1128 }
1129 }
1130
1131 if (!device->claimedContext) {
1132 taskFunc = startup_task;
1133 taskName = "AR6K startup";
1134 ret = 0;
1135#if defined(CONFIG_PM)
1136 } else {
1137 taskFunc = enable_task;
1138 taskName = "AR6K enable";
1139 ret = -ENOMEM;
1140#endif /* CONFIG_PM */
1141 }
1142 /* create resume thread */
1143 pTask = kthread_create(taskFunc, (void *)device, taskName);
1144 if (IS_ERR(pTask)) {
1145 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create enabel task\n", __FUNCTION__));
1146 return -ENOMEM;
1147 }
1148 wake_up_process(pTask);
1149 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifEnableFunc\n"));
1150
1151 /* task will call the enable func, indicate pending */
1152 return ret;
1153}
1154
1155/*
1156 * This should be moved to AR6K HTC layer.
1157 */
1158int hifWaitForPendingRecv(struct hif_device *device)
1159{
1160 s32 cnt = 10;
1161 u8 host_int_status;
1162 int status = 0;
1163
1164 do {
1165 while (atomic_read(&device->irqHandling)) {
1166 /* wait until irq handler finished all the jobs */
1167 schedule_timeout(HZ/10);
1168 }
1169 /* check if there is any pending irq due to force done */
1170 host_int_status = 0;
1171 status = HIFReadWrite(device, HOST_INT_STATUS_ADDRESS,
1172 (u8 *)&host_int_status, sizeof(host_int_status),
1173 HIF_RD_SYNC_BYTE_INC, NULL);
1174 host_int_status = !status ? (host_int_status & (1 << 0)) : 0;
1175 if (host_int_status) {
1176 schedule(); /* schedule for next dsrHandler */
1177 }
1178 } while (host_int_status && --cnt > 0);
1179
1180 if (host_int_status && cnt == 0) {
1181 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
1182 ("AR6000: %s(), Unable clear up pending IRQ before the system suspended\n", __FUNCTION__));
1183 }
1184
1185 return 0;
1186}
1187
1188static void
1189delHifDevice(struct hif_device * device)
1190{
1191 AR_DEBUG_ASSERT(device!= NULL);
1192 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: delHifDevice; 0x%p\n", device));
1193 kfree(device->dma_buffer);
1194 kfree(device);
1195}
1196
1197static void ResetAllCards(void)
1198{
1199}
1200
1201void HIFClaimDevice(struct hif_device *device, void *context)
1202{
1203 device->claimedContext = context;
1204}
1205
1206void HIFReleaseDevice(struct hif_device *device)
1207{
1208 device->claimedContext = NULL;
1209}
1210
1211int HIFAttachHTC(struct hif_device *device, HTC_CALLBACKS *callbacks)
1212{
1213 if (device->htcCallbacks.context != NULL) {
1214 /* already in use! */
1215 return A_ERROR;
1216 }
1217 device->htcCallbacks = *callbacks;
1218 return 0;
1219}
1220
1221void HIFDetachHTC(struct hif_device *device)
1222{
1223 A_MEMZERO(&device->htcCallbacks,sizeof(device->htcCallbacks));
1224}
1225
1226#define SDIO_SET_CMD52_ARG(arg,rw,func,raw,address,writedata) \
1227 (arg) = (((rw) & 1) << 31) | \
1228 (((func) & 0x7) << 28) | \
1229 (((raw) & 1) << 27) | \
1230 (1 << 26) | \
1231 (((address) & 0x1FFFF) << 9) | \
1232 (1 << 8) | \
1233 ((writedata) & 0xFF)
1234
1235#define SDIO_SET_CMD52_READ_ARG(arg,func,address) \
1236 SDIO_SET_CMD52_ARG(arg,0,(func),0,address,0x00)
1237#define SDIO_SET_CMD52_WRITE_ARG(arg,func,address,value) \
1238 SDIO_SET_CMD52_ARG(arg,1,(func),0,address,value)
1239
1240static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, unsigned char byte)
1241{
1242 struct mmc_command ioCmd;
1243 unsigned long arg;
1244
1245 memset(&ioCmd,0,sizeof(ioCmd));
1246 SDIO_SET_CMD52_WRITE_ARG(arg,0,address,byte);
1247 ioCmd.opcode = SD_IO_RW_DIRECT;
1248 ioCmd.arg = arg;
1249 ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
1250
1251 return mmc_wait_for_cmd(card->host, &ioCmd, 0);
1252}
1253
1254static int Func0_CMD52ReadByte(struct mmc_card *card, unsigned int address, unsigned char *byte)
1255{
1256 struct mmc_command ioCmd;
1257 unsigned long arg;
1258 s32 err;
1259
1260 memset(&ioCmd,0,sizeof(ioCmd));
1261 SDIO_SET_CMD52_READ_ARG(arg,0,address);
1262 ioCmd.opcode = SD_IO_RW_DIRECT;
1263 ioCmd.arg = arg;
1264 ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
1265
1266 err = mmc_wait_for_cmd(card->host, &ioCmd, 0);
1267
1268 if ((!err) && (byte)) {
1269 *byte = ioCmd.resp[0] & 0xFF;
1270 }
1271
1272 return err;
1273}
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
new file mode 100644
index 00000000000..7516d913dab
--- /dev/null
+++ b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
@@ -0,0 +1,393 @@
1//------------------------------------------------------------------------------
2// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
3//
4//
5// Permission to use, copy, modify, and/or distribute this software for any
6// purpose with or without fee is hereby granted, provided that the above
7// copyright notice and this permission notice appear in all copies.
8//
9// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16//
17//
18//------------------------------------------------------------------------------
19//==============================================================================
20// HIF scatter implementation
21//
22// Author(s): ="Atheros"
23//==============================================================================
24
25#include <linux/mmc/card.h>
26#include <linux/mmc/host.h>
27#include <linux/mmc/sdio_func.h>
28#include <linux/mmc/sdio_ids.h>
29#include <linux/mmc/sdio.h>
30#include <linux/kthread.h>
31#include "hif_internal.h"
32#define ATH_MODULE_NAME hif
33#include "a_debug.h"
34
35#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT
36
37#define _CMD53_ARG_READ 0
38#define _CMD53_ARG_WRITE 1
39#define _CMD53_ARG_BLOCK_BASIS 1
40#define _CMD53_ARG_FIXED_ADDRESS 0
41#define _CMD53_ARG_INCR_ADDRESS 1
42
43#define SDIO_SET_CMD53_ARG(arg,rw,func,mode,opcode,address,bytes_blocks) \
44 (arg) = (((rw) & 1) << 31) | \
45 (((func) & 0x7) << 28) | \
46 (((mode) & 1) << 27) | \
47 (((opcode) & 1) << 26) | \
48 (((address) & 0x1FFFF) << 9) | \
49 ((bytes_blocks) & 0x1FF)
50
51static void FreeScatterReq(struct hif_device *device, struct hif_scatter_req *pReq)
52{
53 unsigned long flag;
54
55 spin_lock_irqsave(&device->lock, flag);
56
57 DL_ListInsertTail(&device->ScatterReqHead, &pReq->ListLink);
58
59 spin_unlock_irqrestore(&device->lock, flag);
60
61}
62
63static struct hif_scatter_req *AllocScatterReq(struct hif_device *device)
64{
65 struct dl_list *pItem;
66 unsigned long flag;
67
68 spin_lock_irqsave(&device->lock, flag);
69
70 pItem = DL_ListRemoveItemFromHead(&device->ScatterReqHead);
71
72 spin_unlock_irqrestore(&device->lock, flag);
73
74 if (pItem != NULL) {
75 return A_CONTAINING_STRUCT(pItem, struct hif_scatter_req, ListLink);
76 }
77
78 return NULL;
79}
80
81 /* called by async task to perform the operation synchronously using direct MMC APIs */
82int DoHifReadWriteScatter(struct hif_device *device, BUS_REQUEST *busrequest)
83{
84 int i;
85 u8 rw;
86 u8 opcode;
87 struct mmc_request mmcreq;
88 struct mmc_command cmd;
89 struct mmc_data data;
90 struct hif_scatter_req_priv *pReqPriv;
91 struct hif_scatter_req *pReq;
92 int status = 0;
93 struct scatterlist *pSg;
94
95 pReqPriv = busrequest->pScatterReq;
96
97 A_ASSERT(pReqPriv != NULL);
98
99 pReq = pReqPriv->pHifScatterReq;
100
101 memset(&mmcreq, 0, sizeof(struct mmc_request));
102 memset(&cmd, 0, sizeof(struct mmc_command));
103 memset(&data, 0, sizeof(struct mmc_data));
104
105 data.blksz = HIF_MBOX_BLOCK_SIZE;
106 data.blocks = pReq->TotalLength / HIF_MBOX_BLOCK_SIZE;
107
108 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: (%s) Address: 0x%X, (BlockLen: %d, BlockCount: %d) , (tot:%d,sg:%d)\n",
109 (pReq->Request & HIF_WRITE) ? "WRITE":"READ", pReq->Address, data.blksz, data.blocks,
110 pReq->TotalLength,pReq->ValidScatterEntries));
111
112 if (pReq->Request & HIF_WRITE) {
113 rw = _CMD53_ARG_WRITE;
114 data.flags = MMC_DATA_WRITE;
115 } else {
116 rw = _CMD53_ARG_READ;
117 data.flags = MMC_DATA_READ;
118 }
119
120 if (pReq->Request & HIF_FIXED_ADDRESS) {
121 opcode = _CMD53_ARG_FIXED_ADDRESS;
122 } else {
123 opcode = _CMD53_ARG_INCR_ADDRESS;
124 }
125
126 /* fill SG entries */
127 pSg = pReqPriv->sgentries;
128 sg_init_table(pSg, pReq->ValidScatterEntries);
129
130 /* assemble SG list */
131 for (i = 0 ; i < pReq->ValidScatterEntries ; i++, pSg++) {
132 /* setup each sg entry */
133 if ((unsigned long)pReq->ScatterList[i].pBuffer & 0x3) {
134 /* note some scatter engines can handle unaligned buffers, print this
135 * as informational only */
136 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
137 ("HIF: (%s) Scatter Buffer is unaligned 0x%lx\n",
138 pReq->Request & HIF_WRITE ? "WRITE":"READ",
139 (unsigned long)pReq->ScatterList[i].pBuffer));
140 }
141
142 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, (" %d: Addr:0x%lX, Len:%d \n",
143 i,(unsigned long)pReq->ScatterList[i].pBuffer,pReq->ScatterList[i].Length));
144
145 sg_set_buf(pSg, pReq->ScatterList[i].pBuffer, pReq->ScatterList[i].Length);
146 }
147 /* set scatter-gather table for request */
148 data.sg = pReqPriv->sgentries;
149 data.sg_len = pReq->ValidScatterEntries;
150 /* set command argument */
151 SDIO_SET_CMD53_ARG(cmd.arg,
152 rw,
153 device->func->num,
154 _CMD53_ARG_BLOCK_BASIS,
155 opcode,
156 pReq->Address,
157 data.blocks);
158
159 cmd.opcode = SD_IO_RW_EXTENDED;
160 cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
161
162 mmcreq.cmd = &cmd;
163 mmcreq.data = &data;
164
165 mmc_set_data_timeout(&data, device->func->card);
166 /* synchronous call to process request */
167 mmc_wait_for_req(device->func->card->host, &mmcreq);
168
169 if (cmd.error) {
170 status = A_ERROR;
171 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: cmd error: %d \n",cmd.error));
172 }
173
174 if (data.error) {
175 status = A_ERROR;
176 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: data error: %d \n",data.error));
177 }
178
179 if (status) {
180 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: FAILED!!! (%s) Address: 0x%X, Block mode (BlockLen: %d, BlockCount: %d)\n",
181 (pReq->Request & HIF_WRITE) ? "WRITE":"READ",pReq->Address, data.blksz, data.blocks));
182 }
183
184 /* set completion status, fail or success */
185 pReq->CompletionStatus = status;
186
187 if (pReq->Request & HIF_ASYNCHRONOUS) {
188 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: async_task completion routine req: 0x%lX (%d)\n",(unsigned long)busrequest, status));
189 /* complete the request */
190 A_ASSERT(pReq->CompletionRoutine != NULL);
191 pReq->CompletionRoutine(pReq);
192 } else {
193 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER async_task upping busrequest : 0x%lX (%d)\n", (unsigned long)busrequest,status));
194 /* signal wait */
195 up(&busrequest->sem_req);
196 }
197
198 return status;
199}
200
201 /* callback to issue a read-write scatter request */
202static int HifReadWriteScatter(struct hif_device *device, struct hif_scatter_req *pReq)
203{
204 int status = A_EINVAL;
205 u32 request = pReq->Request;
206 struct hif_scatter_req_priv *pReqPriv = (struct hif_scatter_req_priv *)pReq->HIFPrivate[0];
207
208 do {
209
210 A_ASSERT(pReqPriv != NULL);
211
212 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: total len: %d Scatter Entries: %d\n",
213 pReq->TotalLength, pReq->ValidScatterEntries));
214
215 if (!(request & HIF_EXTENDED_IO)) {
216 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
217 ("HIF-SCATTER: Invalid command type: 0x%08x\n", request));
218 break;
219 }
220
221 if (!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS))) {
222 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
223 ("HIF-SCATTER: Invalid execution mode: 0x%08x\n", request));
224 break;
225 }
226
227 if (!(request & HIF_BLOCK_BASIS)) {
228 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
229 ("HIF-SCATTER: Invalid data mode: 0x%08x\n", request));
230 break;
231 }
232
233 if (pReq->TotalLength > MAX_SCATTER_REQ_TRANSFER_SIZE) {
234 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
235 ("HIF-SCATTER: Invalid length: %d \n", pReq->TotalLength));
236 break;
237 }
238
239 if (pReq->TotalLength == 0) {
240 A_ASSERT(false);
241 break;
242 }
243
244 /* add bus request to the async list for the async I/O thread to process */
245 AddToAsyncList(device, pReqPriv->busrequest);
246
247 if (request & HIF_SYNCHRONOUS) {
248 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued sync req: 0x%lX\n", (unsigned long)pReqPriv->busrequest));
249 /* signal thread and wait */
250 up(&device->sem_async);
251 if (down_interruptible(&pReqPriv->busrequest->sem_req) != 0) {
252 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,("HIF-SCATTER: interrupted! \n"));
253 /* interrupted, exit */
254 status = A_ERROR;
255 break;
256 } else {
257 status = pReq->CompletionStatus;
258 }
259 } else {
260 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued async req: 0x%lX\n", (unsigned long)pReqPriv->busrequest));
261 /* wake thread, it will process and then take care of the async callback */
262 up(&device->sem_async);
263 status = 0;
264 }
265
266 } while (false);
267
268 if (status && (request & HIF_ASYNCHRONOUS)) {
269 pReq->CompletionStatus = status;
270 pReq->CompletionRoutine(pReq);
271 status = 0;
272 }
273
274 return status;
275}
276
277 /* setup of HIF scatter resources */
278int SetupHIFScatterSupport(struct hif_device *device, struct hif_device_scatter_support_info *pInfo)
279{
280 int status = A_ERROR;
281 int i;
282 struct hif_scatter_req_priv *pReqPriv;
283 BUS_REQUEST *busrequest;
284
285 do {
286
287 /* check if host supports scatter requests and it meets our requirements */
288 if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
289 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
290 device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
291 status = A_ENOTSUP;
292 break;
293 }
294
295 AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HIF-SCATTER Enabled: max scatter req : %d entries: %d \n",
296 MAX_SCATTER_REQUESTS, MAX_SCATTER_ENTRIES_PER_REQ));
297
298 for (i = 0; i < MAX_SCATTER_REQUESTS; i++) {
299 /* allocate the private request blob */
300 pReqPriv = (struct hif_scatter_req_priv *)A_MALLOC(sizeof(struct hif_scatter_req_priv));
301 if (NULL == pReqPriv) {
302 break;
303 }
304 A_MEMZERO(pReqPriv, sizeof(struct hif_scatter_req_priv));
305 /* save the device instance*/
306 pReqPriv->device = device;
307 /* allocate the scatter request */
308 pReqPriv->pHifScatterReq = (struct hif_scatter_req *)A_MALLOC(sizeof(struct hif_scatter_req) +
309 (MAX_SCATTER_ENTRIES_PER_REQ - 1) * (sizeof(struct hif_scatter_item)));
310
311 if (NULL == pReqPriv->pHifScatterReq) {
312 kfree(pReqPriv);
313 break;
314 }
315 /* just zero the main part of the scatter request */
316 A_MEMZERO(pReqPriv->pHifScatterReq, sizeof(struct hif_scatter_req));
317 /* back pointer to the private struct */
318 pReqPriv->pHifScatterReq->HIFPrivate[0] = pReqPriv;
319 /* allocate a bus request for this scatter request */
320 busrequest = hifAllocateBusRequest(device);
321 if (NULL == busrequest) {
322 kfree(pReqPriv->pHifScatterReq);
323 kfree(pReqPriv);
324 break;
325 }
326 /* assign the scatter request to this bus request */
327 busrequest->pScatterReq = pReqPriv;
328 /* point back to the request */
329 pReqPriv->busrequest = busrequest;
330 /* add it to the scatter pool */
331 FreeScatterReq(device,pReqPriv->pHifScatterReq);
332 }
333
334 if (i != MAX_SCATTER_REQUESTS) {
335 status = A_NO_MEMORY;
336 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : failed to alloc scatter resources !\n"));
337 break;
338 }
339
340 /* set scatter function pointers */
341 pInfo->pAllocateReqFunc = AllocScatterReq;
342 pInfo->pFreeReqFunc = FreeScatterReq;
343 pInfo->pReadWriteScatterFunc = HifReadWriteScatter;
344 pInfo->MaxScatterEntries = MAX_SCATTER_ENTRIES_PER_REQ;
345 pInfo->MaxTransferSizePerScatterReq = MAX_SCATTER_REQ_TRANSFER_SIZE;
346
347 status = 0;
348
349 } while (false);
350
351 if (status) {
352 CleanupHIFScatterResources(device);
353 }
354
355 return status;
356}
357
358 /* clean up scatter support */
359void CleanupHIFScatterResources(struct hif_device *device)
360{
361 struct hif_scatter_req_priv *pReqPriv;
362 struct hif_scatter_req *pReq;
363
364 /* empty the free list */
365
366 while (1) {
367
368 pReq = AllocScatterReq(device);
369
370 if (NULL == pReq) {
371 break;
372 }
373
374 pReqPriv = (struct hif_scatter_req_priv *)pReq->HIFPrivate[0];
375 A_ASSERT(pReqPriv != NULL);
376
377 if (pReqPriv->busrequest != NULL) {
378 pReqPriv->busrequest->pScatterReq = NULL;
379 /* free bus request */
380 hifFreeBusRequest(device, pReqPriv->busrequest);
381 pReqPriv->busrequest = NULL;
382 }
383
384 if (pReqPriv->pHifScatterReq != NULL) {
385 kfree(pReqPriv->pHifScatterReq);
386 pReqPriv->pHifScatterReq = NULL;
387 }
388
389 kfree(pReqPriv);
390 }
391}
392
393#endif // HIF_LINUX_MMC_SCATTER_SUPPORT