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; }
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; }
static void sqn_tx_timeout(struct net_device *dev) { /* struct sqn_private *priv = netdev_priv(dev); */ sqn_pr_enter(); sqn_pr_err("TX watch dog timeout\n"); sqn_pr_leave(); }
struct sqn_private *sqn_add_card(void *card, struct device *realdev) { struct sqn_private *priv = 0; u8 dummy_wimax_mac_addr[ETH_ALEN] = { 0x00, 0x16, 0x08, 0x00, 0x06, 0x53 }; /* Allocate an Ethernet device and register it */ struct net_device *dev = alloc_netdev(sizeof(struct sqn_private), "wimax%d", ether_setup); sqn_pr_enter(); if (!dev) { sqn_pr_err("init wimaxX device failed\n"); goto done; } priv = netdev_priv(dev); memset(priv, 0, sizeof(struct sqn_private)); /* * Use dummy WiMAX mac address for development version (boot from * flash) of WiMAX SDIO cards. Production cards use mac address from * firmware which is loaded by driver. Random ethernet address can't be * used if IPv4 convergence layer is enabled on WiMAX base station. */ memcpy(priv->mac_addr, dummy_wimax_mac_addr, ETH_ALEN); spin_lock_init(&priv->drv_lock); /* Fill the private stucture */ priv->dev = dev; priv->card = card; /* Setup the OS Interface to our functions */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) dev->open = sqn_dev_open; dev->stop = sqn_dev_stop; dev->hard_start_xmit = sqn_hard_start_xmit; dev->tx_timeout = sqn_tx_timeout; dev->get_stats = sqn_get_stats; #else dev->netdev_ops = &sqn_netdev_ops; #endif /* TODO: Make multicast possible */ dev->flags &= ~IFF_MULTICAST; //wimax interface mtu must be 1400 (in spec) dev->mtu = 1400; SET_NETDEV_DEV(dev, realdev); done: sqn_pr_leave(); return priv; }
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_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; }
static int write_data(struct sdio_func *func, u32 addr, void *data , u32 size, u32 access_size) { int rv = 0, retry = 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 *buf = 0; size_t buf_size = 0; u32 written_size = 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"); written_size = 0; buf_size = sqn_alloc_big_buffer(&buf, size, GFP_KERNEL | GFP_DMA); if (!buf) { sqn_pr_err("failed to allocate buffer of %u bytes\n", size); goto out; } do { memcpy(buf, data + written_size, buf_size); rv = sdio_writesb(func, SQN_SDIO_ADA_RDWR, buf, buf_size); if (rv) { sqn_pr_dbg("can't write to SQN_SDIO_ADA_RDWR register\n"); goto out; } written_size += buf_size; if (written_size + buf_size > size) buf_size = size - written_size; } while (written_size < size); kfree(buf); /* * 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; }
void sqn_dfs_init(void) { struct dentry *debug_dir = 0; char *debug_dir_name = "dbg"; struct dentry *config_dir = 0; char *config_dir_name= "cfg"; struct dentry *module_dir = 0; char *module_dir_name= "modules"; struct dentry *feature_dir = 0; char *feature_dir_name= "features"; struct dentry *perf_rx_file = 0; char *perf_rx_file_name = "raw_speed_rx"; char *fetch_rx_file_name = "fetch_rx_packets"; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) sqn_dfs_init_struct(); sqn_dfs_rootdir = debugfs_create_dir(SQN_MODULE_NAME, NULL); if (!sqn_dfs_rootdir) { sqn_pr_err("Can't create debugfs entry '%s'\n", SQN_MODULE_NAME); goto out; } debug_dir = debugfs_create_dir(debug_dir_name, sqn_dfs_rootdir); if (!debug_dir) { sqn_pr_err("Can't create debugfs entry '%s'\n", debug_dir_name); goto out; } config_dir = debugfs_create_dir(config_dir_name, sqn_dfs_rootdir); if (!config_dir) { sqn_pr_err("Can't create debugfs entry '%s'\n", config_dir_name); goto out; } module_dir = debugfs_create_dir(module_dir_name, debug_dir); if (!module_dir) { sqn_pr_err("Can't create debugfs entry '%s'\n", module_dir_name); goto out; } feature_dir = debugfs_create_dir(feature_dir_name, debug_dir); if (!feature_dir) { sqn_pr_err("Can't create debugfs entry '%s'\n", feature_dir_name); goto out; } #define sqn_dfs_add_u8(parent, name, value) \ ({ \ struct dentry *p = (parent); \ const char *n = (name); \ u8 *v = (value); \ struct dentry *d = 0; \ d = debugfs_create_u8(n, 0600, p, v); \ if (!d) { \ sqn_pr_err("Can't create debugfs entry '%s'\n" \ , name); \ goto out; \ } \ }) sqn_dfs_add_u8(module_dir, "all", &sqn_dfs.mf.all); sqn_dfs_add_u8(module_dir, "thp", __sqn_thp_per_file_dbg_addr()); sqn_dfs_add_u8(module_dir, "main", __sqn_main_per_file_dbg_addr()); sqn_dfs_add_u8(module_dir, "fw", __sqn_fw_per_file_dbg_addr()); sqn_dfs_add_u8(module_dir, "pm", __sqn_pm_per_file_dbg_addr()); sqn_dfs_add_u8(module_dir, "sdio", __sqn_sdio_per_file_dbg_addr()); sqn_dfs_add_u8(feature_dir, "all", &sqn_dfs.ff.all); sqn_dfs_add_u8(feature_dir, "dump_all_pkts", &sqn_dfs.ff.dump_all_pkts); sqn_dfs_add_u8(feature_dir, "dump_tx_pkt", &sqn_dfs.ff.dump_tx_pkt); sqn_dfs_add_u8(feature_dir, "dump_rx_pkt", &sqn_dfs.ff.dump_rx_pkt); sqn_dfs_add_u8(feature_dir, "dump_lsp_pkt", &sqn_dfs.ff.dump_lsp_pkt); sqn_dfs_add_u8(feature_dir, "dump_thp_pkt", &sqn_dfs.ff.dump_thp_pkt); sqn_dfs_add_u8(feature_dir, "verbose_thp_hdr", &sqn_dfs.ff.verbose_thp_hdr); sqn_dfs_add_u8(feature_dir, "verbose_lsp", &sqn_dfs.ff.verbose_lsp); sqn_dfs_add_u8(feature_dir, "wake_lock", &sqn_dfs.ff.wake_lock); sqn_dfs_add_u8(feature_dir, "trace_funcs", &sqn_dfs.ff.trace_funcs); { struct dentry *dentry; dentry = debugfs_create_file(perf_rx_file_name, S_IRUGO, sqn_dfs_rootdir, 0, &sqn_perf_rx_fops); if (!dentry) sqn_pr_err("failed to create the debugfs %s file\n", perf_rx_file_name); dentry = debugfs_create_file(fetch_rx_file_name, S_IRUGO, sqn_dfs_rootdir, 0, &sqn_fetch_rx_fops); if (!dentry) sqn_pr_err("failed to create the debugfs %s file\n", fetch_rx_file_name); } #undef sqn_dfs_add_u8 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ out: sqn_pr_leave(); return; }