if_ath_sdio.c 11.2 KB
Newer Older
1
/*
Akash Patel's avatar
Akash Patel committed
2
 * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
3
 *
Akash Patel's avatar
Akash Patel committed
4
 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5
 *
Akash Patel's avatar
Akash Patel committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 *
 * 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.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 */

#ifndef EXPORT_SYMTAB
#define EXPORT_SYMTAB
#endif

#include <osdep.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/if_arp.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sd.h>
#include "bmi_msg.h" /* TARGET_TYPE_ */
#include "if_ath_sdio.h"
45
#include "vos_api.h"
fktsai's avatar
fktsai committed
46
#include "regtable.h"
47
48
49
50
51
52

#ifndef REMOVE_PKT_LOG
#include "ol_txrx_types.h"
#include "pktlog_ac_api.h"
#include "pktlog_ac.h"
#endif
53
#include "epping_main.h"
54
55
56
57
58
59
60

#ifndef ATH_BUS_PM
#ifdef CONFIG_PM
#define ATH_BUS_PM
#endif /* CONFIG_PM */
#endif /* ATH_BUS_PM */

61
62
63
64
#ifndef REMOVE_PKT_LOG
struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs = NULL;
#endif

65
66
67
68
typedef void * hif_handle_t;
typedef void * hif_softc_t;

extern int hdd_wlan_startup(struct device *dev, void *hif_sc);
69
extern void __hdd_wlan_exit(void);
70
71
72
73
74
75
76
77
78
79

struct ath_hif_sdio_softc *sc = NULL;

static A_STATUS
ath_hif_sdio_probe(void *context, void *hif_handle)
{
    int ret = 0;
    struct ol_softc *ol_sc;
    HIF_DEVICE_OS_DEVICE_INFO os_dev_info;
    struct sdio_func *func = NULL;
80
    const struct sdio_device_id *id;
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    u_int32_t target_type;
    ENTER();

    sc = (struct ath_hif_sdio_softc *) A_MALLOC(sizeof(*sc));
    if (!sc) {
        ret = -ENOMEM;
        goto err_alloc;
    }
    A_MEMZERO(sc,sizeof(*sc));


    sc->hif_handle = hif_handle;
    HIFConfigureDevice(hif_handle, HIF_DEVICE_GET_OS_DEVICE, &os_dev_info, sizeof(os_dev_info));

    sc->aps_osdev.device = os_dev_info.pOSDevice;
    sc->aps_osdev.bc.bc_bustype = HAL_BUS_TYPE_SDIO;
    spin_lock_init(&sc->target_lock);

    {
        /*
         * Attach Target register table.  This is needed early on --
         * even before BMI -- since PCI and HIF initialization (and BMI init)
         * directly access Target registers (e.g. CE registers).
         *
         * TBDXXX: targetdef should not be global -- should be stored
         * in per-device struct so that we can support multiple
         * different Target types with a single Host driver.
         * The whole notion of an "hif type" -- (not as in the hif
         * module, but generic "Host Interface Type") is bizarre.
         * At first, one one expect it to be things like SDIO, USB, PCI.
         * But instead, it's an actual platform type. Inexplicably, the
         * values used for HIF platform types are *different* from the
         * values used for Target Types.
         */

#if defined(CONFIG_AR9888_SUPPORT)
        hif_register_tbl_attach(HIF_TYPE_AR9888);
        target_register_tbl_attach(TARGET_TYPE_AR9888);
        target_type = TARGET_TYPE_AR9888;
#elif defined(CONFIG_AR6320_SUPPORT)
121
        id = ((HIF_DEVICE*)hif_handle)->id;
122
        if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == MANUFACTURER_ID_QCA9377_BASE) {
123
124
            hif_register_tbl_attach(HIF_TYPE_AR6320V2);
            target_register_tbl_attach(TARGET_TYPE_AR6320V2);
125
126
127
128
129
130
131
132
133
134
135
        } else if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == MANUFACTURER_ID_AR6320_BASE) {
            int ar6kid = id->device & MANUFACTURER_ID_AR6K_REV_MASK;
            if (ar6kid >= 1) {
                /* v2 or higher silicon */
                hif_register_tbl_attach(HIF_TYPE_AR6320V2);
                target_register_tbl_attach(TARGET_TYPE_AR6320V2);
            } else {
                /* legacy v1 silicon */
                hif_register_tbl_attach(HIF_TYPE_AR6320);
                target_register_tbl_attach(TARGET_TYPE_AR6320);
            }
136
        }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
        target_type = TARGET_TYPE_AR6320;

#endif
    }
    func = ((HIF_DEVICE*)hif_handle)->func;

    ol_sc = A_MALLOC(sizeof(*ol_sc));
    if (!ol_sc){
           ret = -ENOMEM;
           goto err_attach;
    }
    OS_MEMZERO(ol_sc, sizeof(*ol_sc));
    ol_sc->sc_osdev = &sc->aps_osdev;
    ol_sc->hif_sc = (void *)sc;
    sc->ol_sc = ol_sc;
    ol_sc->target_type = target_type;
    ol_sc->enableuartprint = 1;
    ol_sc->enablefwlog = 0;
    ol_sc->enablesinglebinary = FALSE;
    ol_sc->max_no_of_peers = 1;

    ol_sc->hif_hdl = hif_handle;
159

160
#if 0 /* ndef TARGET_DUMP_FOR_NON_QC_PLATFORM */
161
162
163
164
165
166
    ol_sc->ramdump_base = ioremap(RAMDUMP_ADDR, RAMDUMP_SIZE);
    ol_sc->ramdump_size = RAMDUMP_SIZE;
    if (ol_sc->ramdump_base == NULL) {
        ol_sc->ramdump_base = 0;
        ol_sc->ramdump_size = 0;
    }
167
#endif
168
169
    init_waitqueue_head(&ol_sc->sc_osdev->event_queue);

170
171
172
173
174
175
    if (athdiag_procfs_init(sc) != 0) {
        VOS_TRACE(VOS_MODULE_ID_HIF, VOS_TRACE_LEVEL_ERROR,
                "%s athdiag_procfs_init failed",__func__);
        ret =  A_ERROR;
        goto err_attach1;
    }
176
177
178
179

    ret = hdd_wlan_startup(&(func->dev), ol_sc);
    if ( ret ) {
        VOS_TRACE(VOS_MODULE_ID_HIF, VOS_TRACE_LEVEL_FATAL," hdd_wlan_startup failed");
180
        goto err_attach2;
181
182
183
184
    }else{
        VOS_TRACE(VOS_MODULE_ID_HIF, VOS_TRACE_LEVEL_INFO," hdd_wlan_startup success!");
    }

185
186
187
188
189
190
	/* epping is minimum ethernet driver and the
	 * epping fw does not support pktlog, etc.
	 * After hdd_wladriver is epping directly return. */
	if (WLAN_IS_EPPING_ENABLED(vos_get_conparam()))
		goto end;

191
192
193
194
195
196
197
198
199
200
201
#ifndef REMOVE_PKT_LOG
    if (vos_get_conparam() != VOS_FTM_MODE) {
        /*
         * pktlog initialization
         */
        ol_pl_sethandle(&ol_sc->pdev_txrx_handle->pl_dev, ol_sc);

        if (pktlogmod_init(ol_sc))
            printk(KERN_ERR "%s: pktlogmod_init failed\n", __func__);
    }
#endif
202
end:
203
    return 0;
204
205
206

err_attach2:
    athdiag_procfs_remove();
207
err_attach1:
208
    A_FREE(ol_sc);
209
err_attach:
210
211
    A_FREE(sc);
    sc = NULL;
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
err_alloc:
    return ret;
}

int
ol_ath_sdio_configure(hif_softc_t hif_sc, struct net_device *dev, hif_handle_t *hif_hdl)
{
    struct ath_hif_sdio_softc *sc = (struct ath_hif_sdio_softc *) hif_sc;
    int ret = 0;

    sc->aps_osdev.netdev = dev;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
    SET_MODULE_OWNER(dev);
#endif

    *hif_hdl = sc->hif_handle;

    return ret;
}

static A_STATUS
ath_hif_sdio_remove(void *context, void *hif_handle)
{
    ENTER();

237
238
239
240
241
242
    if (!sc) {
        VOS_TRACE(VOS_MODULE_ID_HIF, VOS_TRACE_LEVEL_ERROR,
                  "Global SDIO context is NULL");
        return A_ERROR;
    }

243
244
    athdiag_procfs_remove();

245
#ifndef TARGET_DUMP_FOR_NON_QC_PLATFORM
246
    iounmap(sc->ol_sc->ramdump_base);
247
#endif
248

249
#ifndef REMOVE_PKT_LOG
250
251
    if (vos_get_conparam() != VOS_FTM_MODE &&
		!WLAN_IS_EPPING_ENABLED(vos_get_conparam())){
252
253
254
255
256
        if (sc && sc->ol_sc)
            pktlogmod_exit(sc->ol_sc);
    }
#endif

257
258
259
    //cleaning up the upper layers
    __hdd_wlan_exit();

260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    if (sc && sc->ol_sc){
       A_FREE(sc->ol_sc);
       sc->ol_sc = NULL;
    }
    if (sc) {
        A_FREE(sc);
        sc = NULL;
    }

    EXIT();
    return 0;
}

static A_STATUS
ath_hif_sdio_suspend(void *context)
{
    printk(KERN_INFO "ol_ath_sdio_suspend TODO\n");
    return 0;
}

static A_STATUS
ath_hif_sdio_resume(void *context)
{
    printk(KERN_INFO "ol_ath_sdio_resume ODO\n");
    return 0;
}

static A_STATUS
ath_hif_sdio_power_change(void *context, A_UINT32 config)
{
    printk(KERN_INFO "ol_ath_sdio_power change TODO\n");
    return 0;
}

/*
 * Module glue.
 */
297
#include <linux/version.h>
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
static char *version = "HIF (Atheros/multi-bss)";
static char *dev_info = "ath_hif_sdio";

static int init_ath_hif_sdio(void)
{
    static int probed = 0;
    A_STATUS status;
    OSDRV_CALLBACKS osdrvCallbacks;
    ENTER();

    A_MEMZERO(&osdrvCallbacks,sizeof(osdrvCallbacks));
    osdrvCallbacks.deviceInsertedHandler = ath_hif_sdio_probe;
    osdrvCallbacks.deviceRemovedHandler = ath_hif_sdio_remove;
#ifdef CONFIG_PM
    osdrvCallbacks.deviceSuspendHandler = ath_hif_sdio_suspend;
    osdrvCallbacks.deviceResumeHandler = ath_hif_sdio_resume;
    osdrvCallbacks.devicePowerChangeHandler = ath_hif_sdio_power_change;
#endif

    if (probed) {
        return -ENODEV;
    }
    probed++;

    VOS_TRACE(VOS_MODULE_ID_HIF, VOS_TRACE_LEVEL_INFO,"%s %d",__func__,__LINE__);
    status = HIFInit(&osdrvCallbacks);
    if(status != A_OK){
       VOS_TRACE(VOS_MODULE_ID_HIF, VOS_TRACE_LEVEL_FATAL, "%s HIFInit failed!",__func__);
        return -ENODEV;
    }

    printk(KERN_INFO "%s: %s\n", dev_info, version);

    return 0;
}

int hif_register_driver(void)
{
   int status = 0;
   ENTER();
   status = init_ath_hif_sdio();
   EXIT("status = %d", status);
   return status;

}

void hif_unregister_driver(void)
{
   ENTER();
   HIFShutDownDevice(NULL);
   EXIT();
   return ;
}

void hif_init_adf_ctx(adf_os_device_t adf_dev, void *ol_sc)
{
   struct ol_softc *ol_sc_local = (struct ol_softc *)ol_sc;
   struct ath_hif_sdio_softc *hif_sc = ol_sc_local->hif_sc;
   ENTER();
   adf_dev->drv = &hif_sc->aps_osdev;
   adf_dev->dev = hif_sc->aps_osdev.device;
   ol_sc_local->adf_dev = adf_dev;
   EXIT();
}

363
364
365
366
367
368
void hif_deinit_adf_ctx(void *ol_sc)
{
   struct ol_softc *sc = (struct ol_softc *)ol_sc;
   sc->adf_dev = NULL;
}

369
/* Function to set the TXRX handle in the ol_sc context */
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
void hif_init_pdev_txrx_handle(void *ol_sc, void *txrx_handle)
{
   struct ol_softc *sc = (struct ol_softc *)ol_sc;
   ENTER();
   sc->pdev_txrx_handle = txrx_handle;
}

void hif_disable_isr(void *ol_sc)
{
   ENTER("- dummy function!");
}

void
HIFSetTargetSleep(HIF_DEVICE *hif_device, A_BOOL sleep_ok, A_BOOL wait_for_it)
{
   ENTER("- dummy function!");
}

void
HIFCancelDeferredTargetSleep(HIF_DEVICE *hif_device)
{
    ENTER("- dummy function!");

}

395
/* Function to reset SoC */
396
397
398
399
void hif_reset_soc(void *ol_sc)
{
    ENTER("- dummy function!");
}
400
401
402

void hif_get_hw_info(void *ol_sc, u32 *version, u32 *revision)
{
fktsai's avatar
fktsai committed
403
404
405
406
407
408
409
410
411
412
413
414
415
416
    struct ol_softc *ol_sc_local = (struct ol_softc *)ol_sc;
    A_UINT32 chip_id = 0;
    A_STATUS rv;
    rv = HIFDiagReadAccess(ol_sc_local->hif_hdl,
             (CHIP_ID_ADDRESS | RTC_SOC_BASE_ADDRESS), &chip_id);
    if (rv != A_OK) {
        pr_warn("%s[%d]: get chip id fail\n", __func__, __LINE__);
        ol_sc_local->target_revision = -1;
    } else {
        ol_sc_local->target_revision =
            CHIP_ID_REVISION_GET(chip_id);
    }
    *version = ol_sc_local->target_version;
    *revision = ol_sc_local->target_revision;
417
}
418
419
420
421
422

void hif_set_fw_info(void *ol_sc, u32 target_fw_version)
{
    ((struct ol_softc *)ol_sc)->target_fw_version = target_fw_version;
}
423
424
425
426
427
428
429
430
431
432
433

int hif_pm_runtime_get(void)
{
    return 0;
}

int hif_pm_runtime_put(void)
{
    return 0;
}