static void *sqn_dfs_perf_rx_seq_next(struct seq_file *seq, void *v, loff_t *pos) { u32 *idx = 0; sqn_pr_enter(); ++(*pos); if (SEQ_START_TOKEN == v) { idx = kmalloc(sizeof(u32), GFP_KERNEL); if (!idx) { sqn_pr_dbg("failed to alloc seq_file iterator\n"); goto out; } } else { idx = v; } *idx = *pos - 1; sqn_pr_dbg("idx %u, pos %llu\n", *idx, *pos); if (*idx >= SQN_DFS_PERF_STAT_SIZE) { /* indicate end of sequence */ sqn_pr_dbg("end of sequence, idx %u\n", *idx); idx = 0; } out: sqn_pr_leave(); return idx; }
static void *sqn_dfs_perf_rx_seq_start(struct seq_file *seq, loff_t *pos) { u32 *idx = 0; sqn_pr_enter(); if (0 == *pos) { sqn_pr_dbg("zero pos\n"); idx = SEQ_START_TOKEN; goto out; } else if (SQN_DFS_PERF_STAT_SIZE <= *pos) { /* indicate beyond end of file position */ sqn_pr_dbg("beyond end of file position %llu\n", *pos); idx = 0; goto out; } idx = kmalloc(sizeof(u32), GFP_KERNEL); if (!idx) { sqn_pr_dbg("failed to alloc seq_file iterator\n"); goto out; } *idx = *pos; sqn_pr_dbg("start pos %u\n", *idx); out: sqn_pr_leave(); return idx; }
static int sqn_handle_mac_addr_tag(struct sdio_func *func, u8 *data, u32 length) { int rv = 0; struct sqn_private *priv = ((struct sqn_sdio_card *)sdio_get_drvdata(func))->priv; sqn_pr_enter(); /* * This tag could contain one or two mac addresses in string * form, delimited by some symbol (space or something else). * Each mac address written as a string has constant length. * Thus we can determine the number of mac addresses by the * length of the tag: * * mac addr length in string form: XX:XX:XX:XX:XX:XX = 17 bytes * tag length: 17 bytes [ + 1 byte + 17 bytes ] */ #define MAC_ADDR_STRING_LEN 17 /* * If we have only one mac addr we should increment it by one * and use it. * If we have two mac addresses we should use a second one. */ if (MAC_ADDR_STRING_LEN <= length && length < 2 * MAC_ADDR_STRING_LEN + 1) { sqn_pr_dbg("single mac address\n"); /* we have only one mac addr */ get_mac_addr_from_str(data, length, priv->mac_addr); ++(priv->mac_addr[ETH_ALEN - 1]); } else if (2 * MAC_ADDR_STRING_LEN + 1 == length) { /* we have two macs */ sqn_pr_dbg("two mac addresses, using second\n"); get_mac_addr_from_str(data + MAC_ADDR_STRING_LEN + 1 , length - (MAC_ADDR_STRING_LEN + 1), priv->mac_addr); } else { /* incorrect data length */ sqn_pr_err("can't get mac address from bootloader" " - incorrect mac address length\n"); rv = -1; goto out; } sqn_pr_info("setting MAC address from bootloader: " "%02x:%02x:%02x:%02x:%02x:%02x\n", priv->mac_addr[0] , priv->mac_addr[1], priv->mac_addr[2], priv->mac_addr[3] , priv->mac_addr[4], priv->mac_addr[5]); out: sqn_pr_leave(); return rv; }
/** sqn_load_firmware - loads firmware to card * @func: SDIO function, used to transfer data via SDIO interface, * also used to obtain pointer to device structure. * * But now the only work it does - is loading of bootstrapper to card, * because firmware is supposed to be loaded by a userspace program. */ int sqn_load_firmware(struct sdio_func *func) { int rv = 0; const struct firmware *fw = 0; //Create a local firmware_name with path to replace original global firmware_name -- Tony Wu. const char *firmware_name = "../../../data/wimax/Boot.bin"; struct sqn_sdio_card *sqn_card = sdio_get_drvdata(func); sqn_pr_enter(); sqn_pr_info("trying to find bootloader image: \"%s\"\n", firmware_name); if ((rv = request_firmware(&fw, firmware_name, &func->dev))) goto out; if (SQN_1130 == sqn_card->version) { sdio_claim_host(func); /* properly setup registers for firmware loading */ sqn_pr_dbg("setting up SQN_H_SDRAM_NO_EMR register\n"); sdio_writeb(func, 0, SQN_H_SDRAM_NO_EMR, &rv); if (rv) { sdio_release_host(func); goto out; } sqn_pr_dbg("setting up SQN_H_SDRAMCTL_RSTN register\n"); sdio_writeb(func, 1, SQN_H_SDRAMCTL_RSTN, &rv); sdio_release_host(func); if (rv) goto out; } sqn_pr_info("loading bootloader to the card...\n"); if ((rv = sqn_load_bootstrapper(func, (u8*) fw->data, fw->size))) goto out; /* boot the card */ sqn_pr_info("bootting the card...\n"); sdio_claim_host(func); // by daniel sdio_writeb(func, 1, SQN_H_CRSTN, &rv); sdio_release_host(func); // by daniel if (rv) goto out; sqn_pr_info(" done\n"); out: // To avoid kzalloc leakage in /drivers/base/firmware_class.c if (fw) { release_firmware(fw); fw = NULL; } sqn_pr_leave(); return rv; }
static int sqn_handle_memcpy_tag(struct sdio_func *func , struct sqn_tag_memcpy * mcpy_tag) { int rv = 0; sqn_pr_enter(); /* * Convert values accordingly to platform "endianes" * (big or little endian) because bootstrapper file * data is big endian */ mcpy_tag->address = be32_to_cpu(mcpy_tag->address); mcpy_tag->access_size = be32_to_cpu(mcpy_tag->access_size); mcpy_tag->data_size = be32_to_cpu(mcpy_tag->data_size); /* sqn_pr_dbg("----------------------------------------\n"); */ sqn_pr_dbg("address: 0x%02X access_size: %u data_size: %u\n" , mcpy_tag->address, mcpy_tag->access_size , mcpy_tag->data_size); /* sqn_pr_dbg_dump("|", mcpy_tag->data, mcpy_tag->data_size); */ rv = write_data(func, mcpy_tag->address, mcpy_tag->data , mcpy_tag->data_size, mcpy_tag->access_size); sqn_pr_leave(); return rv; }
static int get_mac_addr_from_str(u8 *data, u32 length, u8 *result) { int rv = 0; int i = 0; sqn_pr_enter(); if (0 == length) { rv = -1; goto out; } /* * Check if we have delimiters on appropriate places: * * X X : X X : X X : X X : X X : X X * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */ if ( !( ( ':' == data[2] || '-' == data[2]) && ( ':' == data[5] || '-' == data[5]) && ( ':' == data[8] || '-' == data[8]) && ( ':' == data[11] || '-' == data[11]) && ( ':' == data[14] || '-' == data[14]) )) { sqn_pr_err("can't get mac address from firmware" " - incorrect mac address\n"); rv = -1; goto out; } i = 0; while (i < length) { int high = 0; int low = 0; if ((high = char_to_int(data[i])) >= 0 && (low = char_to_int(data[i + 1])) >= 0) { result[i/3] = low; result[i/3] |= high << 4; } else { sqn_pr_err("can't get mac address from firmware" " - incorrect mac address\n"); rv = -1; goto out; } i += 3; } out: if (length > 0) { data[length - 1] = 0; sqn_pr_dbg("mac addr string: %s\n", data); } sqn_pr_leave(); return rv; }
int thp_handler(struct sk_buff *skb, struct net_device *pDev, struct packet_type *pPt) #endif { struct sk_buff *skb_thp = 0; struct ethhdr *eth = 0; sqn_pr_enter(); /* We need only ETH_P_802_2 protocol packets with THP mac address */ eth = skb2ethhdr(skb); if(ntohs(skb->protocol) != ETH_P_802_2 || !is_thp_packet(eth->h_dest)) { //for DDTM, drop all NOT THP packets if(drop_packet) { sqn_pr_dbg("HTC CODE: drop packet for DDTM\n"); skb->pkt_type = PACKET_OTHERHOST; } goto not_thp_out; } skb_thp = skb_clone(skb, GFP_ATOMIC); /* Bugz 22554: strip CRC at the end of packet */ skb_trim(skb_thp, skb_thp->len - 4); #if THP_TRACE sqn_pr_info("%s: RX packet, len = %d\n", __func__, skb_thp->len); #endif sqn_pr_dbg("RX THP packet, length %d\n", skb_thp->len); skb_queue_tail(&to_sqntool_queue, skb_thp); if(skb_queue_len(&to_sqntool_queue) == 256){ skb_thp = skb_dequeue(&to_sqntool_queue); kfree_skb(skb_thp); } wake_up_interruptible(&to_sqntool_wait); //Wake up wait queue thp_out: dev_kfree_skb_any(skb); sqn_pr_leave(); return NET_RX_DROP; not_thp_out: dev_kfree_skb_any(skb); sqn_pr_leave(); return NET_RX_SUCCESS; }
static int is_good_ahb_address(u32 address, enum sqn_card_version card_version) { u32 sdram_base = 0; u32 sdram_end = 0; u32 sdram_ctl_base = 0; u32 sdram_ctl_end = 0; int status = 0; sqn_pr_enter(); if (address % 4) return 0; if (SQN_1130 == card_version) { sqn_pr_dbg("using 1130 AHB address boundaries\n"); sdram_base = SQN_1130_SDRAM_BASE; sdram_end = SQN_1130_SDRAM_END; sdram_ctl_base = SQN_1130_SDRAMCTL_BASE; sdram_ctl_end = SQN_1130_SDRAMCTL_END; } else if (SQN_1210 == card_version) { sqn_pr_dbg("using 1210 AHB address boundaries\n"); sdram_base = SQN_1210_SDRAM_BASE; sdram_end = SQN_1210_SDRAM_END; sdram_ctl_base = SQN_1210_SDRAMCTL_BASE; sdram_ctl_end = SQN_1210_SDRAMCTL_END; } else { sqn_pr_warn("Can't check AHB address because of unknown" " card version\n"); status = 0; goto out; } status = ((sdram_base <= address && address < sdram_end) || (sdram_ctl_base <= address && address < sdram_ctl_end)); out: sqn_pr_leave(); return status; }
void signal_card_sleep_completion(struct sqn_private *priv) { struct sqn_sdio_card *card = priv->card; unsigned long irq_flags = 0; sqn_pr_enter(); spin_lock_irqsave(&priv->drv_lock, irq_flags); card->is_card_sleeps = 0; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); wake_up_interruptible(&g_card_sleep_waitq); sqn_pr_dbg("card sleep completion is signaled\n"); sqn_pr_leave(); }
static int sqn_handle_memset_tag(struct sdio_func *func , struct sqn_tag_memset * mset_tag) { int rv = 0; u8 *buf = 0; const u32 buf_size = 1024; u32 left_bytes = 0; sqn_pr_enter(); /* * Convert values accordingly to platform "endianes" * (big or little endian) because bootstrapper file * data is big endian */ mset_tag->address = be32_to_cpu(mset_tag->address); mset_tag->access_size = be32_to_cpu(mset_tag->access_size); mset_tag->size = be32_to_cpu(mset_tag->size); /* sqn_pr_dbg("----------------------------------------\n"); */ sqn_pr_dbg("address: 0x%02X access_size: %u size: %u pattern 0x%02X\n" , mset_tag->address, mset_tag->access_size , mset_tag->size, mset_tag->pattern); buf = kmalloc(buf_size, GFP_KERNEL); if (0 == buf) return -ENOMEM; memset(buf, mset_tag->pattern, buf_size); left_bytes = mset_tag->size; while (left_bytes) { u32 bytes_to_write = min(buf_size, left_bytes); rv = write_data(func, mset_tag->address, buf, bytes_to_write, mset_tag->access_size); if (rv) goto out; left_bytes -= bytes_to_write; } out: kfree(buf); sqn_pr_leave(); return rv; }
int sqn_start_tx_thread(struct sqn_private *priv) { int rv = 0; sqn_pr_enter(); priv->tx_thread = kthread_run(sqn_tx_thread, priv->dev, "sqn_tx"); if (IS_ERR(priv->tx_thread)) { sqn_pr_dbg("error creating TX thread.\n"); rv = 1; goto out; } sqn_pr_leave(); out: return rv; }
int sqn_start_card(struct sqn_private *priv) { struct net_device *dev = priv->dev; sqn_pr_enter(); if (register_netdev(dev)) { sqn_pr_err("cannot register ethX device\n"); return -1; } sqn_pr_dbg("starting TX thread...\n"); /* TODO: move waitq initializatio to add_card() */ init_waitqueue_head(&priv->tx_waitq); init_waitqueue_head(&priv->rx_waitq); if (sqn_start_tx_thread(priv)) goto err_init_adapter; sqn_pr_info("%s: Sequans WiMAX adapter\n", dev->name); #if IGNORE_CARRIER_STATE netif_carrier_on(priv->dev); #else /* In release version this should be uncommented */ /* netif_carrier_off(priv->dev); */ #endif done: sqn_pr_leave(); return 0; err_init_adapter: /* TODO: Free allocated resources */ sqn_pr_err("error while init adapter\n"); free_netdev(dev); priv = NULL; goto done; }
int sqn_handle_lsp_packet(struct sqn_private *priv , struct sk_buff *skb) { struct sqn_sdio_card *card = priv->card; unsigned long irq_flags = 0; struct sqn_lsp_packet *lsp_response = (struct sqn_lsp_packet*) ((u8*)skb->data + sizeof(struct sqn_eth_header)); sqn_pr_enter(); if (!sqn_is_rx_lsp_packet(skb)) { sqn_pr_dbg("not LSP packet\n"); sqn_pr_leave(); return 0; } sqn_pr_dbg("LSP packet\n"); switch (ntohl(lsp_response->lsp_header.id)) { case THSP_GET_MEDIA_CONNECTION_STATE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_GET_MEDIA_CONNECTION_STATE state=%xh\n" , ntohl(lsp_response->lsp_header.u.media_con_state)); } sqn_pr_warn("THSP_GET_MEDIA_CONNECTION_STATE not implemented\n"); break; case THSP_MEDIA_CONNECTION_STATE_CHANGE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_MEDIA_CONNECTION_STATE_CHANGE state=%xh\n" , ntohl(lsp_response->lsp_header.u.media_con_state)); } if (THSP_MEDIA_CONNECTION_ATTACHED == ntohl(lsp_response->lsp_header.u.media_con_state)) { #if IGNORE_CARRIER_STATE /* netif_carrier_on(priv->dev); */ sqn_pr_info("WiMAX carrier PRESENT [ignored]\n"); #else netif_carrier_on(priv->dev); sqn_pr_info("WiMAX carrier PRESENT\n"); #endif } else { #if IGNORE_CARRIER_STATE /* netif_carrier_off(priv->dev); */ sqn_pr_info("WiMAX carrier LOST [ignored]\n"); #else netif_carrier_off(priv->dev); sqn_pr_info("WiMAX carrier LOST\n"); #endif } break; case THSP_SET_HOST_POWER_MODE_ACK: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_SET_HOST_POWER_MODE_ACK tid=0x%x\n" , ntohl(lsp_response->lsp_header.u.host_power.tid)); } free_last_request(); spin_lock_irqsave(&priv->drv_lock, irq_flags); card->is_card_sleeps = 1; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); signal_pm_request_completion(priv); break; case THSP_SET_FW_POWER_MODE_ACK: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_SET_FW_POWER_MODE_ACK tid=0x%x\n" , ntohl(lsp_response->lsp_header.u.fw_power.tid)); } sqn_pr_info("THSP_SET_FW_POWER_MODE_ACK not implemented\n"); break; case THSP_SQN_STATE_CHANGE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_SQN_STATE_CHANGE tid=0x%x, state=%xh\n" , ntohl(lsp_response->lsp_header.u.fw_state.tid) , ntohl(lsp_response->lsp_header.u.fw_state.state)); } handle_sqn_state_change_msg(priv, lsp_response); break; case THSP_THP_AVAILABLE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_THP_AVAILABLE tid=0x%x, reply=%xh\n" , ntohl(lsp_response->lsp_header.u.thp_avl.tid) , ntohl(lsp_response->lsp_header.u.thp_avl.reply)); } handle_thp_avl_msg(priv, lsp_response); break; default: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: UNKNOWN=0x%x\n" , ntohl(lsp_response->lsp_header.id)); } } dev_kfree_skb_any(skb); sqn_pr_leave(); return 1; }
/** sqn_load_bootstrapper - reads a binary boostrapper file, analize it * and loads data to the card. * * Bootstrapper is consists of Tag, Length, Value (TLV) sections. * Each section starts with 4 bytes tag. Then goes length of data (4 bytes) * and then the data itself. * * All fields of bootstrapper file is in BIG ENDIAN format. */ static int sqn_load_bootstrapper(struct sdio_func *func, u8 *data, int size) { struct sqn_tlv *tlv = (struct sqn_tlv*) data; int rv = 0; sqn_pr_enter(); while (size > 0) { /* * Convert values accordingly to platform "endianes" * (big or little endian) because bootstrapper file * data is big endian */ tlv->tag = be32_to_cpu(tlv->tag); tlv->length = be32_to_cpu(tlv->length); switch (tlv->tag) { case SWM_INFO_TAG_SQN_ROOT: case SWM_INFO_TAG_SQN_BOOTROM_GROUP: case SWM_INFO_TAG_SQN_ID_GROUP: /* * This tag is a "container" tag - it's value field * contains other tags */ /* sqn_pr_dbg("========================================\n"); */ sqn_pr_dbg("tag: CONTAINER %x length: %u\n", tlv->tag , tlv->length); /* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */ /* * If this is a buggy tag, adjust length to * the rest of data */ if (0 == tlv->length) tlv->length = size - sizeof(*tlv); rv = sqn_load_bootstrapper(func, (u8*) tlv->value , tlv->length); if (rv) goto out; break; case SWM_INFO_TAG_SQN_MEMCPY: /* sqn_pr_dbg("========================================\n"); */ sqn_pr_dbg("tag: SWM_INFO_TAG_SQN_MEMCPY length: %u\n" , tlv->length); /* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */ rv = sqn_handle_memcpy_tag(func , (struct sqn_tag_memcpy*) tlv->value); if (rv) goto out; break; case SWM_INFO_TAG_SQN_MEMSET: /* sqn_pr_dbg("========================================\n"); */ sqn_pr_dbg("tag: SWM_INFO_TAG_SQN_MEMSET length: %u\n" , tlv->length); /* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */ rv = sqn_handle_memset_tag(func , (struct sqn_tag_memset*) tlv->value); if (rv) goto out; break; case SWM_INFO_TAG_SQN_MAC_ADDRESS: /* sqn_pr_dbg("========================================\n"); */ sqn_pr_dbg("tag: SWM_INFO_TAG_SQN_MAC_ADDRESS length: %u\n" , tlv->length); /* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */ rv = sqn_handle_mac_addr_tag(func, tlv->value , tlv->length); if (rv) goto out; break; default: /* skip all other tags */ /* sqn_pr_dbg("========================================\n"); */ sqn_pr_dbg("tag: UNKNOWN %x length: %u\n" , tlv->tag, tlv->length); /* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */ break; } /* increment tlv to point it to the beginning of the next * sqn_tlv struct and decrement size accordingly */ size = (int)(size - (sizeof(*tlv) + tlv->length)); tlv = (struct sqn_tlv*) ((u8*)tlv + sizeof(*tlv) + tlv->length); } if (0 != size) { /* something wrong with parsing of tlv values */ rv = -1; goto out; } out: sqn_pr_leave(); return rv; }
static int sqn_tx_thread(void *data) { struct net_device *dev = (struct net_device *) data; struct sqn_private *priv = netdev_priv(dev); int rv = 0; unsigned long irq_flags = 0; sqn_pr_enter(); /* * Set PF_NOFREEZE to prevent kernel to freeze this thread * when going to suspend. We will manually stop it from * driver's suspend handler. */ current->flags |= PF_NOFREEZE; for (;;) { spin_lock_irqsave(&priv->drv_lock, irq_flags); if (!(priv->is_tx_queue_empty(priv)) || priv->removed) spin_unlock_irqrestore(&priv->drv_lock, irq_flags); else { int rv = 0; sqn_pr_dbg("wait for skb\n"); spin_unlock_irqrestore(&priv->drv_lock, irq_flags); rv = wait_event_interruptible(priv->tx_waitq , !(priv->is_tx_queue_empty(priv)) || kthread_should_stop() || priv->removed); /* * If we've been interrupted by a signal, then we * should stop a thread */ if (0 != rv) { sqn_pr_dbg("got a signal from kernel %d\n", rv); break; } } sqn_pr_dbg("got skb to send, wake up\n"); if (kthread_should_stop()) { sqn_pr_dbg("break from main thread\n"); break; } spin_lock_irqsave(&priv->drv_lock, irq_flags); if (priv->removed) { sqn_pr_dbg("adapter removed; wait to die...\n"); spin_unlock_irqrestore(&priv->drv_lock, irq_flags); mdelay(1); continue; } spin_unlock_irqrestore(&priv->drv_lock, irq_flags); rv= priv->hw_host_to_card(priv); if (rv) sqn_pr_dbg("failed to send PDU: %d\n", rv); } sqn_pr_leave(); return 0; }
static int write_data(struct sdio_func *func, u32 addr, void *data , u32 size, u32 access_size) { int rv = 0; struct sqn_sdio_card *sqn_card = sdio_get_drvdata(func); sqn_pr_enter(); sdio_claim_host(func); if (is_good_ahb_address(addr, sqn_card->version) && 0 == (size % 4) && 4 == access_size) { /* write data using AHB */ u8 *data_cp = 0; #ifdef DEBUG u8 *read_data = 0; #endif sqn_pr_dbg("write data using AHB\n"); sdio_writel(func, addr, SQN_SDIO_ADA_ADDR, &rv); if (rv) { sqn_pr_dbg("can't set SQN_SDIO_ADA_ADDR register\n"); goto out; } sqn_pr_dbg("after SQN_SDIO_ADA_ADDR\n"); data_cp = kmalloc(size, GFP_KERNEL | GFP_DMA); memcpy(data_cp, data, size); rv = sdio_writesb(func, SQN_SDIO_ADA_RDWR, data_cp, size); if (rv) { sqn_pr_dbg("can't write to SQN_SDIO_ADA_RDWR register\n"); goto out; } kfree(data_cp); /* * Workaround when sdio_writesb doesn't work because DMA * alignment */ /* int i = 0; for (; i < size/4; ++i) { sdio_writel(func, *((u32*)data + i), SQN_SDIO_ADA_RDWR, &rv); if (rv) { sqn_pr_dbg("can't write to SQN_SDIO_ADA_RDWR register\n"); goto out; } } */ sqn_pr_dbg("after SQN_SDIO_ADA_RDWR\n"); /* ******** only for debugging ******** */ /* validate written data */ /* #ifdef DEBUG */ #if 0 sqn_pr_dbg("reading data using AHB\n"); sdio_writel(func, addr, SQN_SDIO_ADA_ADDR, &rv); if (rv) { sqn_pr_dbg("can't set SQN_SDIO_ADA_ADDR register\n"); goto out; } sqn_pr_dbg("after SQN_SDIO_ADA_ADDR\n"); read_data = kmalloc(size, GFP_KERNEL); rv = sdio_readsb(func, read_data, SQN_SDIO_ADA_RDWR, size); if (rv) { sqn_pr_dbg("can't read from SQN_SDIO_ADA_RDWR register\n"); kfree(read_data); goto out; } if (memcmp(data, read_data, size)) sqn_pr_dbg("WARNING: written data are __not__ equal\n"); else sqn_pr_dbg("OK: written data are equal\n"); kfree(read_data); #endif /* DEBUG */ /* ******** only for debugging ******** */ } else if (4 == access_size && size >= 4) { /* write data using CMD53 */ sqn_pr_dbg("write data using CMD53\n"); rv = sdio_memcpy_toio(func, addr, data , size); } else { /* write data using CMD52 */ /* not implemented yet, so we use CMD53 */ /* rv = sdio_memcpy_toio(func, addr, data , size); */ int i = 0; sqn_pr_dbg("write data using CMD52\n"); for (i = 0; i < size; ++i) { sdio_writeb(func, *((u8*)data + i), addr + i, &rv); if (rv) { sqn_pr_dbg("can't write 1 byte to %xh addr using CMD52\n" , addr + i); goto out; } } } out: sdio_release_host(func); sqn_pr_leave(); return rv; }
int sqn_wakeup_fw(struct sdio_func *func) { int rv = 0; int ver = 0; int counter = 0; int retry_cnt = 3; u32 wakeup_delay = 0; unsigned long timeout = msecs_to_jiffies(800); unsigned long irq_flags = 0; struct sqn_private *priv = ((struct sqn_sdio_card *)sdio_get_drvdata(func))->priv; struct sqn_sdio_card *card = priv->card; u8 need_to_unlock_wakelock = 0; sqn_pr_enter(); sqn_pr_info("waking up the card...\n"); if (!wake_lock_active(&card->wakelock_tx)) { if (mmc_wimax_get_sdio_wakelock_log()) { printk(KERN_INFO "[WIMAX] lock wl_tx2,"); PRINTRTC; } wake_lock(&card->wakelock_tx); need_to_unlock_wakelock = 1; } retry: if (priv->removed) goto out; sdio_claim_host(func); #define SDIO_CCCR_CCCR_SDIO_VERSION_VALUE 0x11 wakeup_delay = 2; counter = 5; do { sqn_pr_dbg("CMD52 #%d, delay %d msec\n", counter, wakeup_delay); ver = sdio_readb(func, SDIO_CCCR_CCCR_SDIO_VERSION, &rv); // To avoid FW sutck in PLLOFF, SDIO isn't able to wake up it. mdelay(wakeup_delay); --counter; } while((rv || ver != SDIO_CCCR_CCCR_SDIO_VERSION_VALUE) && counter > 0); if (rv) { sqn_pr_err("error when reading SDIO_VERSION\n"); if (mmc_wimax_get_wimax_FW_freeze_WK_TX()) { sqn_pr_info("[ste]set is_card_sleeps 0 to avoid TX polling\n"); card->is_card_sleeps = 0; } sdio_release_host(func); goto out; } else sqn_pr_dbg("SDIO_VERSION has been read successfully\n"); sqn_pr_dbg("send wake-up signal to card\n"); sdio_writeb(func, 1, SQN_SOC_SIGS_LSBS, &rv); if (rv) sqn_pr_err("error when writing to SQN_SOC_SIGS_LSBS: %d\n", rv); sdio_release_host(func); sqn_pr_info("wait for completion (timeout %d msec)...\n" , jiffies_to_msecs(timeout)); rv = wait_event_interruptible_timeout(g_card_sleep_waitq , 0 == card->is_card_sleeps || priv->removed, timeout); if (priv->removed) goto out; if (-ERESTARTSYS == rv) { sqn_pr_warn("got a signal from kernel %d\n", rv); } else if (0 == rv) { rv = -1; sqn_pr_err("can't wake up the card - timeout elapsed\n"); if (retry_cnt-- > 0 && card->is_card_sleeps) { sqn_pr_info("retry wake up\n"); goto retry; } sqn_pr_info("giving up to wake up the card\n"); spin_lock_irqsave(&priv->drv_lock, irq_flags); card->is_card_sleeps = 0; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); } else { rv = 0; sqn_pr_info("card is waked up successfully\n"); } out: if (need_to_unlock_wakelock && wake_lock_active(&card->wakelock_tx)) { if (mmc_wimax_get_sdio_wakelock_log()) { printk(KERN_INFO "[WIMAX] release wake_lock_tx in %s,", __func__); PRINTRTC; } wake_unlock(&card->wakelock_tx); /* TX */ } sqn_pr_leave(); return rv; }
int sqn_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long irq_flags = 0; struct ethhdr *eth; struct sqn_private *priv = netdev_priv(dev); #if DRIVER_DEBUG printk(KERN_WARNING "sqn_hard_start_xmit \n"); #endif sqn_pr_enter(); sqn_pr_dbg("skb->len = %d\n", skb->len); #if SKB_DEBUG sqn_pr_info("%s: got skb [0x%p] from kernel, users %d\n", __func__, skb, atomic_read(&skb->users)); #endif spin_lock_irqsave(&priv->drv_lock, irq_flags); //HTC code: for DDTM if(drop_packet){ eth = (struct ethhdr*) skb->data; if(memcmp(eth->h_dest, ss_macaddr, ETH_ALEN) != 0){ sqn_pr_dbg("HTC drop_packet enabled: not THP, drop it\n"); #if DRIVER_DEBUG printk(KERN_WARNING "sqn_hard_start_xmit: network packet\n"); #endif priv->stats.tx_dropped++; priv->stats.tx_errors++; dev_kfree_skb_any(skb); goto out; }else{ sqn_pr_dbg("HTC drop_packet enabled: THP, let it live\n"); #if DRIVER_DEBUG printk(KERN_WARNING "sqn_hard_start_xmit: thp packet\n"); #endif } } if (priv->removed) goto out; if (skb->len < 1 || (skb->len > SQN_MAX_PDU_LEN)) { sqn_pr_dbg("skb length %d not in range (1, %d)\n", skb->len, SQN_MAX_PDU_LEN); /* * We'll never manage to send this one; * drop it and return 'OK' */ priv->stats.tx_dropped++; priv->stats.tx_errors++; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); goto out; } /* netif_stop_queue(priv->dev); */ priv->add_skb_to_tx_queue(priv, skb, 1); priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; dev->trans_start = jiffies; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); wake_up_interruptible(&priv->tx_waitq); out: sqn_pr_leave(); return NETDEV_TX_OK; }