linux/drivers/staging/csr/os.c
<<
>>
Prefs
   1/*
   2 * ---------------------------------------------------------------------------
   3 *  FILE:     os.c
   4 *
   5 *  PURPOSE:
   6 *      Routines to fulfil the OS-abstraction for the HIP lib.
   7 *      It is part of the porting exercise.
   8 *
   9 * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
  10 *
  11 * Refer to LICENSE.txt included with this source code for details on
  12 * the license terms.
  13 *
  14 * ---------------------------------------------------------------------------
  15 */
  16
  17/**
  18 * The HIP lib OS abstraction consists of the implementation
  19 * of the functions in this file. It is part of the porting exercise.
  20 */
  21
  22#include "unifi_priv.h"
  23
  24
  25/*
  26 * ---------------------------------------------------------------------------
  27 *  unifi_net_data_malloc
  28 *
  29 *      Allocate an OS specific net data buffer of "size" bytes.
  30 *      The bulk_data_slot.os_data_ptr must be initialised to point
  31 *      to the buffer allocated. The bulk_data_slot.length must be
  32 *      initialised to the requested size, zero otherwise.
  33 *      The bulk_data_slot.os_net_buf_ptr can be initialised to
  34 *      an OS specific pointer to be used in the unifi_net_data_free().
  35 *
  36 *
  37 *  Arguments:
  38 *      ospriv              Pointer to device private context struct.
  39 *      bulk_data_slot      Pointer to the bulk data structure to initialise.
  40 *      size                Size of the buffer to be allocated.
  41 *
  42 *  Returns:
  43 *      CSR_RESULT_SUCCESS on success, CSR_RESULT_FAILURE otherwise.
  44 * ---------------------------------------------------------------------------
  45 */
  46CsrResult
  47unifi_net_data_malloc(void *ospriv, bulk_data_desc_t *bulk_data_slot, unsigned int size)
  48{
  49    struct sk_buff *skb;
  50    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
  51    int rounded_length;
  52
  53    if (priv->card_info.sdio_block_size == 0) {
  54        unifi_error(priv, "unifi_net_data_malloc: Invalid SDIO block size\n");
  55        return CSR_RESULT_FAILURE;
  56    }
  57
  58    rounded_length = (size + priv->card_info.sdio_block_size - 1) & ~(priv->card_info.sdio_block_size - 1);
  59
  60    /*
  61     * (ETH_HLEN + 2) bytes tailroom for header manipulation
  62     * CSR_WIFI_ALIGN_BYTES bytes headroom for alignment manipulation
  63     */
  64    skb = dev_alloc_skb(rounded_length + 2 + ETH_HLEN + CSR_WIFI_ALIGN_BYTES);
  65    if (! skb) {
  66        unifi_error(ospriv, "alloc_skb failed.\n");
  67        bulk_data_slot->os_net_buf_ptr = NULL;
  68        bulk_data_slot->net_buf_length = 0;
  69        bulk_data_slot->os_data_ptr = NULL;
  70        bulk_data_slot->data_length = 0;
  71        return CSR_RESULT_FAILURE;
  72    }
  73
  74    bulk_data_slot->os_net_buf_ptr = (const unsigned char*)skb;
  75    bulk_data_slot->net_buf_length = rounded_length + 2 + ETH_HLEN + CSR_WIFI_ALIGN_BYTES;
  76    bulk_data_slot->os_data_ptr = (const void*)skb->data;
  77    bulk_data_slot->data_length = size;
  78
  79    return CSR_RESULT_SUCCESS;
  80} /* unifi_net_data_malloc() */
  81
  82/*
  83 * ---------------------------------------------------------------------------
  84 *  unifi_net_data_free
  85 *
  86 *      Free an OS specific net data buffer.
  87 *      The bulk_data_slot.length must be initialised to 0.
  88 *
  89 *
  90 *  Arguments:
  91 *      ospriv              Pointer to device private context struct.
  92 *      bulk_data_slot      Pointer to the bulk data structure that
  93 *                          holds the data to be freed.
  94 *
  95 *  Returns:
  96 *      None.
  97 * ---------------------------------------------------------------------------
  98 */
  99void
 100unifi_net_data_free(void *ospriv, bulk_data_desc_t *bulk_data_slot)
 101{
 102    struct sk_buff *skb;
 103    CSR_UNUSED(ospriv);
 104
 105    skb = (struct sk_buff *)bulk_data_slot->os_net_buf_ptr;
 106    dev_kfree_skb(skb);
 107
 108    bulk_data_slot->net_buf_length = 0;
 109    bulk_data_slot->data_length = 0;
 110    bulk_data_slot->os_data_ptr = bulk_data_slot->os_net_buf_ptr = NULL;
 111
 112} /* unifi_net_data_free() */
 113
 114
 115/*
 116* ---------------------------------------------------------------------------
 117*  unifi_net_dma_align
 118*
 119*      DMA align an OS specific net data buffer.
 120*      The buffer must be empty.
 121*
 122*
 123*  Arguments:
 124*      ospriv              Pointer to device private context struct.
 125*      bulk_data_slot      Pointer to the bulk data structure that
 126*                          holds the data to be aligned.
 127*
 128*  Returns:
 129*      None.
 130* ---------------------------------------------------------------------------
 131*/
 132CsrResult
 133unifi_net_dma_align(void *ospriv, bulk_data_desc_t *bulk_data_slot)
 134{
 135    struct sk_buff *skb;
 136    unsigned long buf_address;
 137    int offset;
 138    unifi_priv_t *priv = (unifi_priv_t*)ospriv;
 139
 140    if ((bulk_data_slot == NULL) || (CSR_WIFI_ALIGN_BYTES == 0)) {
 141        return CSR_RESULT_SUCCESS;
 142    }
 143
 144    if ((bulk_data_slot->os_data_ptr == NULL) || (bulk_data_slot->data_length == 0)) {
 145        return CSR_RESULT_SUCCESS;
 146    }
 147
 148    buf_address = (unsigned long)(bulk_data_slot->os_data_ptr) & (CSR_WIFI_ALIGN_BYTES - 1);
 149
 150    unifi_trace(priv, UDBG5,
 151                "unifi_net_dma_align: Allign buffer (0x%p) by %d bytes\n",
 152                bulk_data_slot->os_data_ptr, buf_address);
 153
 154    offset = CSR_WIFI_ALIGN_BYTES - buf_address;
 155    if (offset < 0) {
 156        unifi_error(priv, "unifi_net_dma_align: Failed (offset=%d)\n", offset);
 157        return CSR_RESULT_FAILURE;
 158    }
 159
 160    skb = (struct sk_buff*)(bulk_data_slot->os_net_buf_ptr);
 161    skb_reserve(skb, offset);
 162    bulk_data_slot->os_net_buf_ptr = (const unsigned char*)skb;
 163    bulk_data_slot->os_data_ptr = (const void*)(skb->data);
 164
 165    return CSR_RESULT_SUCCESS;
 166
 167} /* unifi_net_dma_align() */
 168
 169#ifdef ANDROID_TIMESTAMP
 170static volatile unsigned int printk_cpu = UINT_MAX;
 171char tbuf[30];
 172
 173char* print_time(void )
 174{
 175    unsigned long long t;
 176    unsigned long nanosec_rem;
 177
 178    t = cpu_clock(printk_cpu);
 179    nanosec_rem = do_div(t, 1000000000);
 180    sprintf(tbuf, "[%5lu.%06lu] ",
 181                    (unsigned long) t,
 182                    nanosec_rem / 1000);
 183
 184    return tbuf;
 185}
 186#endif
 187
 188
 189/* Module parameters */
 190extern int unifi_debug;
 191
 192#ifdef UNIFI_DEBUG
 193#define DEBUG_BUFFER_SIZE       120
 194
 195#define FORMAT_TRACE(_s, _len, _args, _fmt)             \
 196    do {                                                \
 197        va_start(_args, _fmt);                          \
 198        _len += vsnprintf(&(_s)[_len],                  \
 199                         (DEBUG_BUFFER_SIZE - _len),    \
 200                         _fmt, _args);                  \
 201        va_end(_args);                                  \
 202        if (_len >= DEBUG_BUFFER_SIZE) {                \
 203            (_s)[DEBUG_BUFFER_SIZE - 2] = '\n';         \
 204            (_s)[DEBUG_BUFFER_SIZE - 1] = 0;            \
 205        }                                               \
 206    } while (0)
 207
 208void
 209unifi_error(void* ospriv, const char *fmt, ...)
 210{
 211    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
 212    char s[DEBUG_BUFFER_SIZE];
 213    va_list args;
 214    unsigned int len;
 215#ifdef ANDROID_TIMESTAMP
 216    if (priv != NULL) {
 217        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi%d: ", print_time(), priv->instance);
 218    } else {
 219        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi: ", print_time());
 220    }
 221#else
 222    if (priv != NULL) {
 223        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi%d: ", priv->instance);
 224    } else {
 225        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi: ");
 226    }
 227#endif /* ANDROID_TIMESTAMP */
 228    FORMAT_TRACE(s, len, args, fmt);
 229
 230    printk("%s", s);
 231}
 232
 233void
 234unifi_warning(void* ospriv, const char *fmt, ...)
 235{
 236    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
 237    char s[DEBUG_BUFFER_SIZE];
 238    va_list args;
 239    unsigned int len;
 240
 241#ifdef ANDROID_TIMESTAMP
 242    if (priv != NULL) {
 243        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "%s unifi%d: ", print_time(), priv->instance);
 244    } else {
 245        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "%s unifi: ", print_time());
 246    }
 247#else
 248    if (priv != NULL) {
 249        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "unifi%d: ", priv->instance);
 250    } else {
 251        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_WARNING "unifi: ");
 252    }
 253#endif /* ANDROID_TIMESTAMP */
 254
 255    FORMAT_TRACE(s, len, args, fmt);
 256
 257    printk("%s", s);
 258}
 259
 260
 261void
 262unifi_notice(void* ospriv, const char *fmt, ...)
 263{
 264    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
 265    char s[DEBUG_BUFFER_SIZE];
 266    va_list args;
 267    unsigned int len;
 268
 269#ifdef ANDROID_TIMESTAMP
 270    if (priv != NULL) {
 271        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "%s unifi%d: ", print_time(), priv->instance);
 272    } else {
 273        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "%s unifi: ", print_time());
 274    }
 275#else
 276    if (priv != NULL) {
 277        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "unifi%d: ", priv->instance);
 278    } else {
 279        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_NOTICE "unifi: ");
 280    }
 281#endif /* ANDROID_TIMESTAMP */
 282
 283    FORMAT_TRACE(s, len, args, fmt);
 284
 285    printk("%s", s);
 286}
 287
 288
 289void
 290unifi_info(void* ospriv, const char *fmt, ...)
 291{
 292    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
 293    char s[DEBUG_BUFFER_SIZE];
 294    va_list args;
 295    unsigned int len;
 296
 297#ifdef ANDROID_TIMESTAMP
 298    if (priv != NULL) {
 299        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "%s unifi%d: ", print_time(), priv->instance);
 300    } else {
 301        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "%s unifi: ", print_time());
 302    }
 303#else
 304    if (priv != NULL) {
 305        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "unifi%d: ", priv->instance);
 306    } else {
 307        len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_INFO "unifi: ");
 308    }
 309#endif /* ANDROID_TIMESTAMP */
 310
 311    FORMAT_TRACE(s, len, args, fmt);
 312
 313    printk("%s", s);
 314}
 315
 316/* debugging */
 317void
 318unifi_trace(void* ospriv, int level, const char *fmt, ...)
 319{
 320    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
 321    char s[DEBUG_BUFFER_SIZE];
 322    va_list args;
 323    unsigned int len;
 324
 325    if (unifi_debug >= level) {
 326#ifdef ANDROID_TIMESTAMP
 327        if (priv != NULL) {
 328            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi%d: ", print_time(), priv->instance);
 329        } else {
 330            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "%s unifi: ", print_time());
 331        }
 332#else
 333        if (priv != NULL) {
 334            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi%d: ", priv->instance);
 335        } else {
 336            len = snprintf(s, DEBUG_BUFFER_SIZE, KERN_ERR "unifi: ");
 337        }
 338#endif /* ANDROID_TIMESTAMP */
 339
 340        FORMAT_TRACE(s, len, args, fmt);
 341
 342        printk("%s", s);
 343    }
 344}
 345
 346#else
 347
 348void
 349unifi_error_nop(void* ospriv, const char *fmt, ...)
 350{
 351}
 352
 353void
 354unifi_trace_nop(void* ospriv, int level, const char *fmt, ...)
 355{
 356}
 357
 358#endif /* UNIFI_DEBUG */
 359
 360
 361/*
 362 * ---------------------------------------------------------------------------
 363 *
 364 *      Debugging support.
 365 *
 366 * ---------------------------------------------------------------------------
 367 */
 368
 369#ifdef UNIFI_DEBUG
 370
 371/* Memory dump with level filter controlled by unifi_debug */
 372void
 373unifi_dump(void *ospriv, int level, const char *msg, void *mem, u16 len)
 374{
 375    unifi_priv_t *priv = (unifi_priv_t*) ospriv;
 376
 377    if (unifi_debug >= level) {
 378#ifdef ANDROID_TIMESTAMP
 379        if (priv != NULL) {
 380            printk(KERN_ERR "%s unifi%d: --- dump: %s ---\n", print_time(), priv->instance, msg ? msg : "");
 381        } else {
 382            printk(KERN_ERR "%s unifi: --- dump: %s ---\n", print_time(), msg ? msg : "");
 383        }
 384#else
 385        if (priv != NULL) {
 386            printk(KERN_ERR "unifi%d: --- dump: %s ---\n", priv->instance, msg ? msg : "");
 387        } else {
 388            printk(KERN_ERR "unifi: --- dump: %s ---\n", msg ? msg : "");
 389        }
 390#endif /* ANDROID_TIMESTAMP */
 391        dump(mem, len);
 392
 393        if (priv != NULL) {
 394            printk(KERN_ERR "unifi%d: --- end of dump ---\n", priv->instance);
 395        } else {
 396            printk(KERN_ERR "unifi: --- end of dump ---\n");
 397        }
 398    }
 399}
 400
 401/* Memory dump that appears all the time, use sparingly */
 402void
 403dump(void *mem, u16 len)
 404{
 405    int i, col = 0;
 406    unsigned char *pdata = (unsigned char *)mem;
 407#ifdef ANDROID_TIMESTAMP
 408    printk("timestamp %s \n", print_time());
 409#endif /* ANDROID_TIMESTAMP */
 410    if (mem == NULL) {
 411        printk("(null dump)\n");
 412        return;
 413    }
 414    for (i = 0; i < len; i++) {
 415        if (col == 0)
 416            printk("0x%02X: ", i);
 417
 418        printk(" %02X", pdata[i]);
 419
 420        if (++col == 16) {
 421            printk("\n");
 422            col = 0;
 423        }
 424    }
 425    if (col)
 426        printk("\n");
 427} /* dump() */
 428
 429
 430void
 431dump16(void *mem, u16 len)
 432{
 433    int i, col=0;
 434    unsigned short *p = (unsigned short *)mem;
 435#ifdef ANDROID_TIMESTAMP
 436    printk("timestamp %s \n", print_time());
 437#endif /* ANDROID_TIMESTAMP */
 438    for (i = 0; i < len; i+=2) {
 439        if (col == 0)
 440            printk("0x%02X: ", i);
 441
 442        printk(" %04X", *p++);
 443
 444        if (++col == 8) {
 445            printk("\n");
 446            col = 0;
 447        }
 448    }
 449    if (col)
 450        printk("\n");
 451}
 452
 453
 454#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
 455void
 456dump_str(void *mem, u16 len)
 457{
 458    int i;
 459    unsigned char *pdata = (unsigned char *)mem;
 460#ifdef ANDROID_TIMESTAMP
 461    printk("timestamp %s \n", print_time());
 462#endif /* ANDROID_TIMESTAMP */
 463    for (i = 0; i < len; i++) {
 464        printk("%c", pdata[i]);
 465    }
 466        printk("\n");
 467
 468} /* dump_str() */
 469#endif /* CSR_ONLY_NOTES */
 470
 471
 472#endif /* UNIFI_DEBUG */
 473
 474
 475/* ---------------------------------------------------------------------------
 476 *                              - End -
 477 * ------------------------------------------------------------------------- */
 478