コード例 #1
0
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;
}
コード例 #2
0
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;
}
コード例 #3
0
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();
}
コード例 #4
0
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;
}
コード例 #5
0
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;
}
コード例 #6
0
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;
}
コード例 #7
0
ファイル: sdio-fw.c プロジェクト: 12rafael/jellytimekernel
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;
}
コード例 #8
0
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;
}