~fcwu-tw/+junk/oem-wireless-bluetooth-dw1550-dkms

« back to all changes in this revision

Viewing changes to oem-wireless-bluetooth-intel-7260/drivers/net/wireless/iwlwifi/trans_slave/idi_al_emulation/iwl-em-sfdb.c

  • Committer: Doro Wu
  • Date: 2013-08-14 01:41:53 UTC
  • Revision ID: doro.wu@canonical.com-20130814014153-5v7ergizf2ilf7ly
[Doro Wu]
* Merge bcmwl 6.30.223.30+bdcom-0ubuntu1

[Jesse Sung]
* Add patchram support and IDs for broadcom devices (LP: #1180300)
* cherry picked d9c78e9738ccd0017b10b8f44462aafb61904a4a from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 *
3
 
 * Copyright(c) 2005 - 2013 Intel Corporation.
4
 
 * All rights reserved.
5
 
 *
6
 
 * LICENSE PLACE HOLDER
7
 
 *
8
 
 *****************************************************************************/
9
 
 
10
 
#include <linux/kthread.h>
11
 
 
12
 
#include "iwl-fh.h"
13
 
#include "iwl-io.h"
14
 
#include "iwl-prph.h"
15
 
#include "iwl-csr.h"
16
 
#include "iwl-em-sfdb.h"
17
 
#include "trans_slave/idi_al.h"
18
 
#include "iwl-emulation.h"
19
 
#include "iwl-target-access.h"
20
 
 
21
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
22
 
#include <linux/interrupt.h>
23
 
#include "trans_slave/idi_UT/iwl-idi-ut.h"
24
 
#endif
25
 
/*
26
 
 * IWL SFDB Emulation Logger
27
 
 */
28
 
#define SFDB_LOG_PREFIX "[SFDB]"
29
 
 
30
 
#ifdef __IWL_SFDB_LOG_ENABLED__
31
 
#define SFDB_TRACE_ENTER \
32
 
        IWL_EM_TRACE_ENTER(__SFDB_LOG_LEVEL_TRACE__, SFDB_LOG_PREFIX)
33
 
#define SFDB_TRACE_EXIT \
34
 
        IWL_EM_TRACE_EXIT(__SFDB_LOG_LEVEL_TRACE__, SFDB_LOG_PREFIX)
35
 
#define SFDB_TRACE_EXIT_RET_STR(_ret) \
36
 
        IWL_EM_LOG(__SFDB_LOG_LEVEL_TRACE__, SFDB_LOG_PREFIX, "<<< "_ret)
37
 
#define SFDB_TRACE_EXIT_RET(_ret) \
38
 
        IWL_EM_TRACE_EXIT_RET(__SFDB_LOG_LEVEL_TRACE__, SFDB_LOG_PREFIX,\
39
 
                              _ret)
40
 
#define IWL_SFDB_LOG(fmt, args ...) \
41
 
        IWL_EM_LOG(__SFDB_LOG_LEVEL_DEBUG__, SFDB_LOG_PREFIX, fmt, ## args)
42
 
#define IWL_SFDB_LOG_HEX_DUMP(msg, p, len) \
43
 
        IWL_EM_LOG_HEX_DUMP(msg, p, len)
44
 
#else
45
 
 
46
 
#define SFDB_TRACE_ENTER
47
 
#define SFDB_TRACE_EXIT
48
 
#define SFDB_TRACE_EXIT_RET_STR(_ret)
49
 
#define SFDB_TRACE_EXIT_RET(_ret)
50
 
#define IWL_SFDB_LOG(fmt, args ...)
51
 
#define IWL_SFDB_LOG_HEX_DUMP(msg, p, len)
52
 
 
53
 
#endif
54
 
/* Always print error messages */
55
 
#define IWL_SFDB_LOG_ERR(fmt, args ...) \
56
 
        IWL_EM_LOG_ERR(fmt, ## args)
57
 
 
58
 
/* Pointer manipulation defines */
59
 
#define SFDB_SCD_PTR_MASK       (SFDB_SCD_QUEUE_SIZE - 1)
60
 
#define SFDB_QUEUE_PTR_MASK     (SFDB_TFD_NUM_ENTRIES - 1)
61
 
#define SFDB_SCD_PTR(_p)        ((_p) & SFDB_SCD_PTR_MASK)
62
 
#define SFDB_QUEUE_PTR(_p)      ((_p) & SFDB_QUEUE_PTR_MASK)
63
 
#define SFDB_INC_PTR(_p)        ((_p) = ((_p)+1) & SFDB_SCD_PTR_MASK)
64
 
#define SFDB_GET_QUEUE(_qid)    (&iwl_sfdb_em->tfd_queues[_qid])
65
 
 
66
 
/* This is the order of TFD size, size = 64 ==> order = 6 */
67
 
#define HIT_DATA_TFD_SIZE_ORDER (6)
68
 
 
69
 
/* dma_addr_t of allocated BC table, externed to replace AL define */
70
 
u32 IWL_SFDB_BC_ADDRESS;
71
 
 
72
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
73
 
static void iwl_sfdb_em_dispatch_reclaim_emu(unsigned long data);
74
 
#endif
75
 
 
76
 
/* Like struct iwl_dma_ptr, which is currently PCIe-specific. */
77
 
struct iwl_em_dma_ptr {
78
 
        void *addr;
79
 
        dma_addr_t dma;
80
 
        size_t size;
81
 
};
82
 
 
83
 
/**
84
 
 * Holds one TFD queue for the emulation.
85
 
 *
86
 
 * The PCIe TFD queue itself is dynamically allocated, and its virtual and dma
87
 
 * address is saved in 'tfds'. The queue is used by the PCIe FH.
88
 
 * The indices array is used to tell which PCIe TFD entry (in the tfds queue)
89
 
 * is a decompression of which tfd index as represented by the AL FW and mapped
90
 
 * to the SRAM.
91
 
 * Meaning that when we attach TFD x from the pool (of IDI TFDs),
92
 
 * we both decompress it to pcie_tfds.addr[write_ptr], and write 'x'
93
 
 * in lut_table[write_ptr],
94
 
 * so later we would be able to free/clean both its representations.
95
 
 **/
96
 
struct iwl_tfd_em_queue {
97
 
        int write_ptr;
98
 
        int read_ptr;
99
 
 
100
 
        bool need_update;
101
 
        bool is_aggregated;
102
 
 
103
 
        struct iwl_em_dma_ptr pci_tfds;
104
 
        u8 lut_table[SFDB_TFD_NUM_ENTRIES];
105
 
};
106
 
 
107
 
/**
108
 
  * Represents a byte count table per one queue.
109
 
  * For each entry in the queue holds a 2-byte count.
110
 
  * This is multiplied by 2 in order to
111
 
  * provide duplication of each entry as needed by the scheduler.
112
 
  */
113
 
struct iwl_sfdb_em_bc_tbl {
114
 
        __le16 sfdb_queue_bc_table[SFDB_TFD_NUM_ENTRIES * 2];
115
 
} __packed;
116
 
 
117
 
/**
118
 
  * Holds the whole TFD queues (SFDB) emulation context.
119
 
  * kw -- keep warm buffer (not present in IDI, so here we manage it)
120
 
  * tfd_queues -- array of TFD queue contexts
121
 
  * trans -- pointer to transport layer, to interact with the driver
122
 
  **/
123
 
struct iwl_sfdb_t {
124
 
        /* Connection to PCI transport */
125
 
        struct iwl_trans *trans;
126
 
 
127
 
        /* Internal KW and BC buffers */
128
 
        struct iwl_em_dma_ptr kw_buffer;
129
 
        struct iwl_em_dma_ptr bc_tables;
130
 
 
131
 
        /* TFDQs */
132
 
        struct iwl_tfd_em_queue tfd_queues[SFDB_NUM_QUEUES];
133
 
 
134
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
135
 
        /* Gate on the queue id given to the reclaim flow */
136
 
        spinlock_t gate;
137
 
 
138
 
        /* Runs the reclaim flow emulation - needs to be in tasklet context
139
 
         * to emulate RX packet*/
140
 
        struct tasklet_struct reclaim_flow;
141
 
#endif
142
 
};
143
 
 
144
 
/* Global SFDB struct */
145
 
static struct iwl_sfdb_t iwl_sfdb_em_global;
146
 
static struct iwl_sfdb_t *iwl_sfdb_em = &iwl_sfdb_em_global;
147
 
 
148
 
/**
149
 
 * Represents IDI form of transmission buffers
150
 
 *
151
 
 * @tb _addr - The index of the TB in the SRAM TB Pool.
152
 
 * @t_len - The length of the tb.
153
 
 */
154
 
struct iwl_sfdb_idi_tb {
155
 
        u8      tb_addr;
156
 
        __le16  tb_len;
157
 
} __packed;
158
 
 
159
 
/**
160
 
 * Represents IDI form of transmission frame descriptor (TFD)
161
 
 */
162
 
struct iwl_sfdb_idi_tfd {
163
 
        u8                      reserved[3];
164
 
        u8                      numTbs;
165
 
        struct iwl_sfdb_idi_tb  tbs[SFDB_NUM_OF_TBS];
166
 
} __packed;
167
 
 
168
 
/*
169
 
 ************ Utils functions *************
170
 
 */
171
 
 
172
 
/**
173
 
 * Allocates a DMAable address and fills it to the emulation dma pointer struct.
174
 
 * The dma memory is zeroed.
175
 
 *
176
 
 * Returns 0 on success, negative value describing the error otherwise.
177
 
 */
178
 
static inline int iwl_sfdb_em_alloc_dma_ptr(struct iwl_em_dma_ptr *ptr,
179
 
                                            size_t size)
180
 
{
181
 
        SFDB_TRACE_ENTER;
182
 
 
183
 
        if (WARN_ON(ptr->addr))
184
 
                return -EINVAL;
185
 
 
186
 
        /* Alloc dmaable pointer */
187
 
        ptr->addr = dma_alloc_coherent(iwl_sfdb_em->trans->dev,
188
 
                                       size,
189
 
                                       &ptr->dma, GFP_KERNEL);
190
 
        if (!ptr->addr)
191
 
                return -ENOMEM;
192
 
        ptr->size = size;
193
 
 
194
 
        /* Zero allocated memory */
195
 
        memset(ptr->addr, 0, size);
196
 
 
197
 
        IWL_SFDB_LOG("Allocated DMA pointer: virt %p phys %lx size %zu\n",
198
 
                     ptr->addr, (unsigned long)ptr->dma, ptr->size);
199
 
        SFDB_TRACE_ENTER;
200
 
        return 0;
201
 
}
202
 
 
203
 
/**
204
 
 * Frees a DMAable memory location with the emulation dma pointer struct.
205
 
 * The struct is zeroed before return.
206
 
 */
207
 
static inline void iwl_sfdb_em_free_dma_ptr(struct iwl_em_dma_ptr *ptr)
208
 
{
209
 
        SFDB_TRACE_ENTER;
210
 
 
211
 
        if (!ptr->addr)
212
 
                return;
213
 
 
214
 
        IWL_SFDB_LOG("Freeing DMA pointer: virt %p phys %lx size %zu\n",
215
 
                     ptr->addr, (unsigned long)ptr->dma, ptr->size);
216
 
        dma_free_coherent(iwl_sfdb_em->trans->dev,
217
 
                          ptr->size,
218
 
                          ptr->addr,
219
 
                          ptr->dma);
220
 
        memset(ptr, 0, sizeof(*ptr));
221
 
 
222
 
        SFDB_TRACE_EXIT;
223
 
}
224
 
 
225
 
/**
226
 
 * Gets a pointer to a TFD in the IDI form which is located in the AL SRAM.
227
 
 */
228
 
static inline struct iwl_sfdb_idi_tfd *iwl_sfdb_em_get_idi_tfd(u8 tfd_index)
229
 
{
230
 
        return ((struct iwl_sfdb_idi_tfd *)((u8 *)AL_SRAM_VIRTUAL_ADDRESS
231
 
                                        + IDI_AL_SFDB_TFD_POOL_OFFSET))
232
 
                + tfd_index;
233
 
}
234
 
 
235
 
/**
236
 
 * Gets a pointer to a TB in the IDI form which is located in the AL SRAM.
237
 
 */
238
 
static void *iwl_sfdb_em_get_idi_tb(u8 tb_index)
239
 
{
240
 
        SFDB_TRACE_ENTER;
241
 
 
242
 
        return ((u8 *)AL_SRAM_VIRTUAL_ADDRESS + IDI_AL_SFDB_PAYLOAD_MEM_OFFSET)
243
 
                 + (tb_index * SFDB_TB_SIZE);
244
 
 
245
 
        SFDB_TRACE_EXIT;
246
 
}
247
 
 
248
 
/**
249
 
 * Converts a TB in the IDI form to the PCIe TB form.
250
 
 *
251
 
 * Each IDI TB is composed of one-byte index to the TB pool, and 1 byte length.
252
 
 * The PCIe TB is made of 36 bit of address, and 12 bits of length.
253
 
 *
254
 
 * Copyies the idi_tb to the pci_tb.
255
 
 */
256
 
static inline void iwl_sfdb_em_convert_tb(struct iwl_sfdb_idi_tb *idi_tb,
257
 
                                          struct iwl_tfd_tb *pcie_tb,
258
 
                                          int tb_index)
259
 
{
260
 
        /* Buffer is the virtual address of the idi tb
261
 
            phys_addr is the phisical address of the idi tb */
262
 
        void *virt_addr = iwl_sfdb_em_get_idi_tb(idi_tb->tb_addr);
263
 
        u16 hi_n_len = (le16_to_cpu(idi_tb->tb_len) << 4);
264
 
        dma_addr_t phys_addr;
265
 
        SFDB_TRACE_ENTER;
266
 
 
267
 
        /* Calc IDI TB phisical address */
268
 
        phys_addr = (dma_addr_t)((u8 *)AL_SRAM_ADDRESS +
269
 
                        ((u8 *)virt_addr - (u8 *)AL_SRAM_VIRTUAL_ADDRESS));
270
 
        IWL_SFDB_LOG("IDI TB: Convertin TB - index=%d, addres=%lx, len=%u",
271
 
                     idi_tb->tb_addr, (unsigned long)phys_addr,
272
 
                     idi_tb->tb_len);
273
 
 
274
 
        put_unaligned_le32(phys_addr, &pcie_tb->lo);
275
 
        if (sizeof(dma_addr_t) > sizeof(u32))
276
 
                hi_n_len |= (((phys_addr >> 16) >> 16) & 0xF);
277
 
        pcie_tb->hi_n_len = cpu_to_le16(hi_n_len);
278
 
 
279
 
        SFDB_TRACE_EXIT;
280
 
}
281
 
 
282
 
/*
283
 
 ************ API functions ***************
284
 
 */
285
 
 
286
 
/**
287
 
 * Initializes the SFDB module in the emulation.
288
 
 *
289
 
 *@trans - transport to the pci.
290
 
 *
291
 
 * Returns 0 on success, negative value describing the error otherwise.
292
 
 */
293
 
int iwl_sfdb_em_init(struct iwl_trans *trans)
294
 
{
295
 
        int ret;
296
 
        SFDB_TRACE_ENTER;
297
 
 
298
 
        /* Zero structs */
299
 
        memset(iwl_sfdb_em, 0, sizeof(struct iwl_sfdb_t));
300
 
 
301
 
        /* Store trans */
302
 
        iwl_sfdb_em->trans = trans;
303
 
 
304
 
        /* Initialize keep warm buffers */
305
 
        IWL_SFDB_LOG("Initializing keep-warm buffer");
306
 
        ret = iwl_sfdb_em_alloc_dma_ptr(&iwl_sfdb_em->kw_buffer, IWL_KW_SIZE);
307
 
        if (ret) {
308
 
                IWL_SFDB_LOG_ERR("Keep Warm allocation failed (%d)", ret);
309
 
                goto out;
310
 
        }
311
 
 
312
 
        /* Initialize Byte Count tables*/
313
 
        IWL_SFDB_LOG("Initializing BC tables");
314
 
        ret = iwl_sfdb_em_alloc_dma_ptr(&iwl_sfdb_em->bc_tables,
315
 
                SFDB_NUM_QUEUES * sizeof(struct iwl_sfdb_em_bc_tbl));
316
 
        if (ret) {
317
 
                IWL_SFDB_LOG_ERR("BC tables allocation failed (%d)", ret);
318
 
                goto free_kw;
319
 
        }
320
 
        IWL_SFDB_BC_ADDRESS = (u32)&iwl_sfdb_em->bc_tables.dma;
321
 
 
322
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
323
 
        /* Init reclaim flow tasklet */
324
 
        tasklet_init(&(iwl_sfdb_em->reclaim_flow),
325
 
                     iwl_sfdb_em_dispatch_reclaim_emu, 0);
326
 
        spin_lock_init(&iwl_sfdb_em->gate);
327
 
#endif
328
 
 
329
 
        IWL_SFDB_LOG("SFDB Initialized");
330
 
        goto out;
331
 
 
332
 
free_kw:
333
 
        iwl_sfdb_em_free_dma_ptr(&iwl_sfdb_em->kw_buffer);
334
 
out:
335
 
        SFDB_TRACE_EXIT;
336
 
        return ret;
337
 
}
338
 
 
339
 
/*
340
 
 * start  the SFDB.
341
 
 * The start should be called only after sfdb init or after stop flow.
342
 
 *
343
 
 * Returns 0 on success, negative value describing the error otherwise.
344
 
 */
345
 
int iwl_sfdb_em_start(void)
346
 
{
347
 
        /* Write KW address to NIC */
348
 
        iwl_idi_tg_write32(iwl_sfdb_em->trans,
349
 
                           FH_KW_MEM_ADDR_REG,
350
 
                           iwl_sfdb_em->kw_buffer.dma >> 4);
351
 
 
352
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
353
 
        /* Re Init reclaim flow tasklet */
354
 
        tasklet_init(&(iwl_sfdb_em->reclaim_flow),
355
 
                     iwl_sfdb_em_dispatch_reclaim_emu, 0);
356
 
#endif
357
 
        return 0;
358
 
}
359
 
 
360
 
/*
361
 
 * Reset the queue data struct to default values.
362
 
 *
363
 
 * @queue_id - The queue id to reset in the sfdb.
364
 
 */
365
 
static void iwl_sfdb_em_reset_queue(u8 queue_id)
366
 
{
367
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
368
 
        SFDB_TRACE_ENTER;
369
 
 
370
 
        /* Q flags */
371
 
        q->is_aggregated = false;
372
 
        q->need_update = true;
373
 
 
374
 
        /* Read/Write pointer */
375
 
        q->read_ptr = 0;
376
 
        q->write_ptr = 0;
377
 
 
378
 
        /* Set all TB indexes to invalid */
379
 
        memset(q->lut_table, SFDB_INVALID_ENTRY, SFDB_TFD_NUM_ENTRIES);
380
 
 
381
 
        SFDB_TRACE_EXIT;
382
 
}
383
 
 
384
 
/*
385
 
 * Stops the SFDB.
386
 
 * Does not free the data structures just zeroes them.
387
 
 *
388
 
 * NOTE: The LMAC should be stopped before this call to prevent
389
 
 * a race condition of LMAC pulling data from zeroed ring.
390
 
 *
391
 
 * Returns 0 on success, negative value describing the error otherwise.
392
 
 */
393
 
int iwl_sfdb_em_stop(void)
394
 
{
395
 
        int i;
396
 
        SFDB_TRACE_ENTER;
397
 
 
398
 
        /* Clear the BC tables */
399
 
        memset(iwl_sfdb_em->bc_tables.addr,
400
 
               0,
401
 
               SFDB_NUM_QUEUES * sizeof(struct iwl_sfdb_em_bc_tbl));
402
 
 
403
 
        /* Clear the Queues */
404
 
        for (i = 0; i < SFDB_NUM_QUEUES; i++)
405
 
                iwl_sfdb_em_reset_queue(i);
406
 
 
407
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
408
 
        tasklet_kill(&iwl_sfdb_em->reclaim_flow);
409
 
#endif
410
 
 
411
 
        SFDB_TRACE_EXIT;
412
 
        return 0;
413
 
}
414
 
 
415
 
/**
416
 
 * Frees the sfdb emulation struct.
417
 
 *
418
 
 * The al emulation stopping should be called before trying to stop the SFDB.
419
 
 */
420
 
void iwl_sfdb_em_free(void)
421
 
{
422
 
        int i;
423
 
        struct iwl_tfd_em_queue *q;
424
 
        SFDB_TRACE_ENTER;
425
 
 
426
 
        /* Free internal structures */
427
 
        iwl_sfdb_em_free_dma_ptr(&iwl_sfdb_em->bc_tables);
428
 
        iwl_sfdb_em_free_dma_ptr(&iwl_sfdb_em->kw_buffer);
429
 
 
430
 
        /* Free Queues */
431
 
        for (i = 0; i < SFDB_NUM_QUEUES; i++) {
432
 
                IWL_SFDB_LOG("SFDB: Freeing Queue %d", i);
433
 
                q = SFDB_GET_QUEUE(i);
434
 
                iwl_sfdb_em_free_dma_ptr(&q->pci_tfds);
435
 
        }
436
 
 
437
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
438
 
        /*Stop reclaim flow interrupts */
439
 
        tasklet_kill(&iwl_sfdb_em->reclaim_flow);
440
 
#endif
441
 
 
442
 
        IWL_SFDB_LOG("SFDB Freed");
443
 
        SFDB_TRACE_EXIT;
444
 
}
445
 
 
446
 
/**
447
 
 * This function initializes a TFD queue and configures FH with the base
448
 
 * address of this queue.
449
 
 * Allocates a DMA memory for the PCIe TFD queue.
450
 
 *
451
 
 * @param queue_id - the number of queue.
452
 
 */
453
 
void iwl_sfdb_em_init_queue(u8 queue_id)
454
 
{
455
 
        int ret;
456
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
457
 
        SFDB_TRACE_ENTER;
458
 
 
459
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
460
 
 
461
 
        /* Allocate pci TFDs*/
462
 
        IWL_SFDB_LOG("Initializing queue %d - %s Allocated",
463
 
                     queue_id,
464
 
                     (!q->pci_tfds.addr) ? "Not" : "Already");
465
 
 
466
 
        /* If this pointer has been allocated before, just zero the memory.
467
 
         * This pointer is zeroed on sfdb init -  so if it's not zero it means
468
 
         * that the memory was already allocated */
469
 
        if (!q->pci_tfds.addr) {
470
 
                ret = iwl_sfdb_em_alloc_dma_ptr(&q->pci_tfds,
471
 
                        sizeof(struct iwl_tfd) * SFDB_TFD_NUM_ENTRIES);
472
 
                if (ret) {
473
 
                        IWL_SFDB_LOG_ERR("Failed to allocate DMA memory (%d)",
474
 
                                         ret);
475
 
                        WARN_ON(true);
476
 
                }
477
 
        } else {
478
 
                memset(q->pci_tfds.addr, 0,
479
 
                       sizeof(struct iwl_tfd) * SFDB_TFD_NUM_ENTRIES);
480
 
        }
481
 
 
482
 
        /* Reset the queue */
483
 
        iwl_sfdb_em_reset_queue(queue_id);
484
 
 
485
 
        /*Configure FH with the TFD ring address of the Q */
486
 
        iwl_sfdb_em_config_hw(queue_id);
487
 
        SFDB_TRACE_EXIT;
488
 
}
489
 
 
490
 
/**
491
 
 * Writes the given value to the queues tfd entry in the Byte Count table.
492
 
 *
493
 
 * @ param queue_id - The queue id to update the byte count value.
494
 
 * @ param tfd_entry - The tfd entry in the queue to which we update the bc.
495
 
 * @ param value - The value to write to BC_TABLE[queue_id][tfd_entry]
496
 
 */
497
 
void iwl_sfdb_em_write_bc(u8 queue_id, u8 tfd_entry, __le16 value)
498
 
{
499
 
        struct iwl_sfdb_em_bc_tbl *tbl =
500
 
                (struct iwl_sfdb_em_bc_tbl *)iwl_sfdb_em->bc_tables.addr +
501
 
                queue_id;
502
 
 
503
 
        SFDB_TRACE_ENTER;
504
 
        IWL_SFDB_LOG("Writing BC to queue %d, tfd %d , BC value %d",
505
 
                     queue_id, tfd_entry, value);
506
 
 
507
 
        tbl->sfdb_queue_bc_table[SFDB_QUEUE_PTR(tfd_entry)] = value;
508
 
        tbl->sfdb_queue_bc_table[SFDB_TFD_NUM_ENTRIES +
509
 
                         SFDB_QUEUE_PTR(tfd_entry)] = value;
510
 
        SFDB_TRACE_EXIT;
511
 
}
512
 
 
513
 
/**
514
 
 * Writes the given value to the LUT table in the tfd entry.
515
 
 *
516
 
 * @ param queue_id - The queue id to update the LUT value.
517
 
 * @ param tfd_entry - The tfd entry in the queue to which we update the LUT.
518
 
 * @ param value - The value to write to LUT_TABLE[queue_id][tfd_entry]
519
 
 */
520
 
void iwl_sfdb_em_write_lut_value(u8 queue_id, u8 tfd_entry, u16 value)
521
 
{
522
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
523
 
 
524
 
        SFDB_TRACE_ENTER;
525
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
526
 
 
527
 
        IWL_SFDB_LOG("Writing LUT value to queue %d, tfd %d , LUT value %d",
528
 
                     queue_id, tfd_entry, value);
529
 
 
530
 
        q->lut_table[tfd_entry] = value;
531
 
 
532
 
        SFDB_TRACE_EXIT;
533
 
}
534
 
 
535
 
/**
536
 
 * Frees all TFDs in the queue up to (but not including) given tfd_entry.
537
 
 * Note that tfd_entry is a pointer to the queue (like the read pointer),
538
 
 * not an index in the TFD pool.
539
 
 *
540
 
 * @param queue_id - The number of queue.
541
 
 * @param tfd_index - The index of the TFD in the TFD pool
542
 
 */
543
 
void iwl_sfdb_em_release_tfds(u8 queue_id, u8 tfd_entry)
544
 
{
545
 
        u8 read;
546
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
547
 
 
548
 
        SFDB_TRACE_ENTER;
549
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
550
 
 
551
 
        read = SFDB_QUEUE_PTR(q->read_ptr);
552
 
        IWL_SFDB_LOG(
553
 
                "Releasing TFDs: queue %d, from slot %d (read pointer) until %d (inclusive)\n",
554
 
                queue_id, read, tfd_entry);
555
 
 
556
 
        /* This increment will make the release until the
557
 
        original tfd_entry inclusive. */
558
 
        tfd_entry = SFDB_QUEUE_PTR(tfd_entry + 1);
559
 
 
560
 
        while (read != tfd_entry) {
561
 
                iwl_sfdb_em_deattach_tfd(queue_id, read);
562
 
                SFDB_INC_PTR(q->read_ptr);
563
 
                read = SFDB_QUEUE_PTR(q->read_ptr);
564
 
        }
565
 
 
566
 
        SFDB_TRACE_EXIT;
567
 
}
568
 
 
569
 
/**
570
 
 * Sets the next free entry in the lut of the queue
571
 
 * to point to IDI TFD index from the pool.
572
 
 *
573
 
 * @param queue_id - The number of queue.
574
 
 * @param tfd_index - The index of the TFD in the TFD pool
575
 
 *
576
 
 * @return void
577
 
 */
578
 
void iwl_sfdb_em_attach_tfd(u8 queue_id, u8 tfd_index)
579
 
{
580
 
        int i;
581
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
582
 
        u32 write_ptr = SFDB_QUEUE_PTR(q->write_ptr);
583
 
        struct iwl_tfd *pcie_tfd =
584
 
                                (struct iwl_tfd *)q->pci_tfds.addr + write_ptr;
585
 
        struct iwl_sfdb_idi_tfd *idi_tfd =
586
 
                (struct iwl_sfdb_idi_tfd *)iwl_sfdb_em_get_idi_tfd(tfd_index);
587
 
 
588
 
        SFDB_TRACE_ENTER;
589
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
590
 
 
591
 
        IWL_SFDB_LOG("Attaching TFD %u to queue %u in slot %u",
592
 
                     tfd_index, queue_id, write_ptr);
593
 
        memset(pcie_tfd, 0, sizeof(struct iwl_tfd));
594
 
 
595
 
        for (i = 0; i < idi_tfd->numTbs; ++i) {
596
 
                iwl_sfdb_em_convert_tb(&idi_tfd->tbs[i], &pcie_tfd->tbs[i], i);
597
 
                pcie_tfd->num_tbs++;
598
 
        }
599
 
 
600
 
        SFDB_TRACE_EXIT;
601
 
}
602
 
 
603
 
/**
604
 
 * This function deattach TFD from the queue.
605
 
 * Because we use a PCIe queue, there is no "de-attaching" as removing the
606
 
 * TFD, but only invalidating the relevant index in tfd_indices (telling that no
607
 
 * TFD in the pool now referenced to that slot in the queue).
608
 
 *
609
 
 * @param U08 : queue_id  -- the number of queue
610
 
 * @param U08 : tfdEntry -- the entry in the TFD queue
611
 
 */
612
 
void iwl_sfdb_em_deattach_tfd(u8 queue_id, u8 tfd_entry)
613
 
{
614
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
615
 
        SFDB_TRACE_ENTER;
616
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
617
 
 
618
 
        IWL_SFDB_LOG("Deattaching TFD %u from queue %u",
619
 
                     tfd_entry, queue_id);
620
 
        q->lut_table[tfd_entry] = SFDB_INVALID_ENTRY;
621
 
 
622
 
        /* Invalidating BC */
623
 
        iwl_sfdb_em_write_bc(queue_id, tfd_entry, cpu_to_le16(1));
624
 
 
625
 
        SFDB_TRACE_EXIT;
626
 
}
627
 
 
628
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
629
 
 
630
 
/**
631
 
 * Get device command from the latest packet in the given queue id.
632
 
 */
633
 
static struct iwl_device_cmd *iwl_sfdb_em_get_current_cmd(u8 queue_id)
634
 
{
635
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
636
 
        u32 write_ptr = SFDB_QUEUE_PTR(q->write_ptr);
637
 
        struct iwl_sfdb_idi_tfd *idi_tfd;
638
 
        u8 tfd_index;
639
 
        void *virt_addr;
640
 
 
641
 
        SFDB_TRACE_ENTER;
642
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
643
 
 
644
 
 
645
 
        tfd_index = q->lut_table[write_ptr];
646
 
        idi_tfd = (struct iwl_sfdb_idi_tfd *)iwl_sfdb_em_get_idi_tfd(tfd_index);
647
 
        virt_addr = (void *)iwl_sfdb_em_get_idi_tb(idi_tfd->tbs[0].tb_addr);
648
 
        return (struct iwl_device_cmd *)virt_addr;
649
 
}
650
 
 
651
 
/**
652
 
 * Calls the IDI reclaim flow.
653
 
 * Tasklet context.
654
 
 */
655
 
static void iwl_sfdb_em_dispatch_reclaim_emu(unsigned long data)
656
 
{
657
 
        struct iwl_rx_cmd_buffer *rxcb = (struct iwl_rx_cmd_buffer *)data;
658
 
 
659
 
        /* Call the mock reclaim flow in tasklet context */
660
 
        iwl_idi_tx_handle_dispatch_emu(iwl_sfdb_em->trans, rxcb);
661
 
 
662
 
        /* Free variables */
663
 
        kfree(rxcb);
664
 
}
665
 
 
666
 
/**
667
 
 * Reclaim flow emulation for the integration.
668
 
 */
669
 
static void iwl_sfdb_em_test_reclaim(u8 queue_id)
670
 
{
671
 
        struct iwl_rx_cmd_buffer *rxcb;
672
 
        struct iwl_rx_packet *pkt;
673
 
        struct iwl_device_cmd *dev_cmd;
674
 
        struct iwl_idi_trans_rx *trans_rx =
675
 
                        IWL_TRANS_GET_IDI_TRANS_RX(iwl_sfdb_em->trans);
676
 
        struct iwl_trans_slv *trans_slv =
677
 
                        IWL_TRANS_GET_SLV_TRANS(iwl_sfdb_em->trans);
678
 
 
679
 
        /* Alloc RX command buffer */
680
 
        rxcb = kzalloc(sizeof(struct iwl_rx_cmd_buffer), GFP_KERNEL);
681
 
        if (!rxcb) {
682
 
                IWL_SFDB_LOG_ERR("Can't allocate rxcb");
683
 
                return;
684
 
        }
685
 
 
686
 
        /* Alloc and zero page for command buffer */
687
 
        rxcb->_page = alloc_pages((GFP_KERNEL | __GFP_COMP | __GFP_ZERO),
688
 
                                  trans_slv->rx_page_order);
689
 
        if (!rxcb->_page) {
690
 
                IWL_SFDB_LOG_ERR("Can't allocate rxcb->page");
691
 
                kfree(rxcb);
692
 
                return;
693
 
        }
694
 
 
695
 
        /* extract last device cmd from TB */
696
 
        dev_cmd = iwl_sfdb_em_get_current_cmd(queue_id);
697
 
 
698
 
        /* Update packet in local rxcb */
699
 
        pkt = rxb_addr(rxcb);
700
 
        pkt->hdr.cmd = dev_cmd->hdr.cmd;
701
 
        pkt->hdr.sequence = dev_cmd->hdr.sequence;
702
 
 
703
 
        /* Call mock reclaim flow in tasklet context*/
704
 
        spin_lock(&iwl_sfdb_em->gate);
705
 
        tasklet_unlock_wait(&iwl_sfdb_em->reclaim_flow);
706
 
        iwl_sfdb_em->reclaim_flow.data = (unsigned long)rxcb;
707
 
        tasklet_schedule(&iwl_sfdb_em->reclaim_flow);
708
 
        spin_unlock(&iwl_sfdb_em->gate);
709
 
}
710
 
#endif /* CPTCFG_IWLWIFI_TRANS_UT */
711
 
 
712
 
/**
713
 
 * Increments the write pointer and updates the SCD register.
714
 
 *
715
 
 * @param queue_id - The number of queue.
716
 
 */
717
 
void iwl_sfdb_em_inc_write_ptr(u8 queue_id)
718
 
{
719
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
720
 
 
721
 
        SFDB_TRACE_ENTER;
722
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
723
 
 
724
 
        IWL_SFDB_LOG("Incrementing WRITE pointer on queue %d, Old %d",
725
 
                     queue_id,
726
 
                     iwl_sfdb_em_get_write_ptr(queue_id));
727
 
 
728
 
#ifdef CPTCFG_IWLWIFI_TRANS_UT
729
 
        iwl_sfdb_em_test_reclaim(queue_id);
730
 
        SFDB_INC_PTR(q->write_ptr);
731
 
#else
732
 
        SFDB_INC_PTR(q->write_ptr);
733
 
        iwl_sfdb_em_hw_set_write_ptr(queue_id, SFDB_SCD_PTR(q->write_ptr));
734
 
#endif
735
 
        SFDB_TRACE_EXIT;
736
 
}
737
 
 
738
 
/**
739
 
 * Gets the write pointer of the given queue.
740
 
 *
741
 
 * @param queue_id - The number of queue.
742
 
 *
743
 
 * Returns the write pointer of the queue.
744
 
 */
745
 
u32  iwl_sfdb_em_get_write_ptr(u8 queue_id)
746
 
{
747
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
748
 
        SFDB_TRACE_ENTER;
749
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
750
 
 
751
 
        SFDB_TRACE_EXIT;
752
 
        return SFDB_SCD_PTR(q->write_ptr);
753
 
}
754
 
 
755
 
/**
756
 
 * Update Write pointer of Scheduler for queue_id
757
 
 *
758
 
 * @param queue_id - The number of queue
759
 
 * @param index - The index to set the write pointer
760
 
 */
761
 
void iwl_sfdb_em_hw_set_write_ptr(u8 queue_id, u32 index)
762
 
{
763
 
        /* TODO: does the same assumptions of PCI hold here?
764
 
          PCI code assumes that after setting CSR_GP_CNTRL this function will
765
 
          be called again, and this time it will update the write pointer */
766
 
 
767
 
        SFDB_TRACE_ENTER;
768
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
769
 
 
770
 
        iwl_write32(iwl_sfdb_em->trans, HBUS_TARG_WRPTR,
771
 
                    (u32)index | ((u32)queue_id << 8));
772
 
        IWL_SFDB_LOG("HW write pointer set to %d on Queue %d, requested %d",
773
 
                     iwl_sfdb_em_get_write_ptr(queue_id),
774
 
                     queue_id,
775
 
                     index);
776
 
 
777
 
        SFDB_TRACE_EXIT;
778
 
}
779
 
 
780
 
/**
781
 
 * Returns the read pointer of the queue
782
 
 *
783
 
 * @param queue_id - the number of queue.
784
 
 *
785
 
 * Returns the read pointer of the given queue.
786
 
 */
787
 
u8 iwl_sfdb_em_get_read_ptr(u8 queue_id)
788
 
{
789
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
790
 
        SFDB_TRACE_ENTER;
791
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
792
 
 
793
 
        SFDB_TRACE_EXIT;
794
 
        return SFDB_SCD_PTR(q->read_ptr);
795
 
}
796
 
 
797
 
/**
798
 
 * Update read pointer of Scheduler for queue_id
799
 
 *
800
 
 * @param queue_id - The number of queue
801
 
 * @param index - The index to set the read pointer
802
 
 */
803
 
void iwl_sfdb_em_hw_set_read_ptr(u8 queue_id, u8 index)
804
 
{
805
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
806
 
        SFDB_TRACE_ENTER;
807
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
808
 
 
809
 
        IWL_SFDB_LOG("Setting READ pointer on Q %d to %d", queue_id, index);
810
 
        q->read_ptr = index;
811
 
        iwl_write_prph(iwl_sfdb_em->trans,
812
 
                       SCD_QUEUE_RDPTR(queue_id),
813
 
                       q->read_ptr);
814
 
        SFDB_TRACE_EXIT;
815
 
}
816
 
 
817
 
/**
818
 
 * This function updates the byte count table for this queue and index
819
 
 *
820
 
 * @param queue_id - the number of queue
821
 
 * @param byte_cnt - the number of bytes for this frame
822
 
 *
823
 
 * @return void
824
 
 */
825
 
void iwl_sfdb_em_update_byte_count(u8 queue_id, __le16 byte_cnt)
826
 
{
827
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
828
 
        SFDB_TRACE_ENTER;
829
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
830
 
 
831
 
        iwl_sfdb_em_write_bc(queue_id, SFDB_QUEUE_PTR(q->write_ptr), byte_cnt);
832
 
        SFDB_TRACE_EXIT;
833
 
}
834
 
 
835
 
/**
836
 
 * Configures the LMAC (FH/SCD) for using this queue
837
 
 *
838
 
 * @param queue_id - The number of queue
839
 
 */
840
 
void iwl_sfdb_em_config_hw(u8 queue_id)
841
 
{
842
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
843
 
        SFDB_TRACE_ENTER;
844
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
845
 
 
846
 
        IWL_SFDB_LOG("Configure HW to use queue %d", queue_id);
847
 
        iwl_write_direct32(iwl_sfdb_em->trans,
848
 
                           FH_MEM_CBBC_QUEUE(queue_id),
849
 
                           q->pci_tfds.dma >> 8);
850
 
 
851
 
        SFDB_TRACE_EXIT;
852
 
}
853
 
 
854
 
/**
855
 
 * This function sets the context data for the queue
856
 
 *
857
 
 * @queue_id - the number of queue
858
 
 *
859
 
 * @return void
860
 
 */
861
 
void iwl_sfdb_em_set_ctx_data(u8 queue_id, u32 scd_base_addr)
862
 
{
863
 
        iwl_trans_write_mem32(iwl_sfdb_em->trans, scd_base_addr +
864
 
                        SCD_CONTEXT_QUEUE_OFFSET(queue_id), 0);
865
 
        iwl_trans_write_mem32(iwl_sfdb_em->trans, scd_base_addr +
866
 
                        SCD_CONTEXT_QUEUE_OFFSET(queue_id) +
867
 
                        sizeof(u32),
868
 
                        ((64 <<
869
 
                        SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
870
 
                        SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
871
 
                        ((64 <<
872
 
                        SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
873
 
                        SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
874
 
}
875
 
 
876
 
/**
877
 
 * This function sets the status of this queue (to SCD status register)
878
 
 *
879
 
 * @queueId - the number of queue
880
 
 * @isActive - is the queue active
881
 
 * @isPan - is the queue for PAN
882
 
 * @txFifo - the Q->Fifo mapping
883
 
 *
884
 
 * @return void
885
 
 */
886
 
void iwl_sfdb_em_set_status(u8 queue_id, u32 is_active,
887
 
                            u32 is_pan, u32 tx_fifo)
888
 
{
889
 
        iwl_write_prph(iwl_sfdb_em->trans, SCD_QUEUE_STATUS_BITS(queue_id),
890
 
                       (is_active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
891
 
                       (tx_fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
892
 
                       (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
893
 
                       (is_pan << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN) |
894
 
                       SCD_QUEUE_STTS_REG_MSK);
895
 
}
896
 
 
897
 
/**
898
 
 * This function returns the status of this queue (from SCD status register)
899
 
 *
900
 
 * @queueId- The number of queue.
901
 
 */
902
 
u32 iwl_sfdb_em_get_status(u8 queue_id)
903
 
{
904
 
        return iwl_idi_tg_read32(iwl_sfdb_em->trans,
905
 
                                 SCD_QUEUE_STATUS_BITS(queue_id));
906
 
}
907
 
 
908
 
/**
909
 
 * Returns if the queue is aggregated.
910
 
 *
911
 
 * @param queue_id - The number of queue
912
 
 *
913
 
 * Returns TRUE if the queue is active, FALSE otherwise.
914
 
 */
915
 
bool iwl_sfdb_em_queue_is_aggregated(u8 queue_id)
916
 
{
917
 
        struct iwl_tfd_em_queue *q = SFDB_GET_QUEUE(queue_id);
918
 
        BUG_ON(queue_id >= SFDB_NUM_QUEUES);
919
 
        return q->is_aggregated;
920
 
}