Пример #1
0
static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
				      struct net_device *dev, u16 reason_code)
{
	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);

	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
		   reason_code);

	if (!ath6kl_cfg80211_ready(ar))
		return -EIO;

	if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
		ath6kl_err("busy, destroy in progress\n");
		return -EBUSY;
	}

	if (down_interruptible(&ar->sem)) {
		ath6kl_err("busy, couldn't get access\n");
		return -ERESTARTSYS;
	}

	ar->reconnect_flag = 0;
	ath6kl_disconnect(ar);
	memset(ar->ssid, 0, sizeof(ar->ssid));
	ar->ssid_len = 0;

	if (!test_bit(SKIP_SCAN, &ar->flag))
		memset(ar->req_bssid, 0, sizeof(ar->req_bssid));

	up(&ar->sem);

	ar->sme_state = SME_DISCONNECTED;

	return 0;
}
Пример #2
0
int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
{
	u32 cid = BMI_SET_APP_START;
	int ret;
	u32 offset;
	u16 size;

	if (ar->bmi.done_sent) {
		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
		return -EACCES;
	}

	size = sizeof(cid) + sizeof(addr);
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
	memset(ar->bmi.cmd_buf, 0, size);

	ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr);

	offset = 0;
	memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
	offset += sizeof(cid);
	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
	offset += sizeof(addr);

	ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to write to the device: %d\n", ret);
		return ret;
	}

	return 0;
}
Пример #3
0
static int ath6kl_vreg_enable(struct ath6kl_power_vreg_data *vreg)
{
	int rc = 0;

	ath6kl_dbg(ATH6KL_DBG_BOOT, "vreg_en for : %s\n", vreg->name);

	if (!vreg->is_enabled) {
		if (vreg->set_voltage_sup) {
			rc = regulator_set_voltage(vreg->reg,
						vreg->low_vol_level,
						vreg->high_vol_level);
			if (rc) {
				ath6kl_err("vreg_set_vol(%s) failed rc=%d\n",
						vreg->name, rc);
				goto out;
			}
		}

		rc = regulator_enable(vreg->reg);
		if (rc) {
			ath6kl_err("regulator_enable(%s) failed. rc=%d\n",
					vreg->name, rc);
			goto out;
		}
		vreg->is_enabled = true;
	}
out:
	return rc;
}
Пример #4
0
int rttm_init(void* ar)
{
   S_RTTM_CONTEXT *prttm=NULL;
   ath6kl_dbg(ATH6KL_DBG_RTT,"rttm init ");
   prttm=kmalloc(sizeof(S_RTTM_CONTEXT),GFP_KERNEL);
   if(NULL==prttm)
    return -ENOMEM;
   memset(prttm,0,sizeof(S_RTTM_CONTEXT));
   if(NULL==prttm->cirbuf)
   {
    ath6kl_err("RTT Init Failed to AllocMem for rttm context \n");
    return -ENOMEM;
   }
   prttm->pvreadptr = prttm->cirbuf;
   prttm->pvbufptr = prttm->cirbuf;
   prttm->ar =ar;
   DEV_SETRTT_HDL(prttm);
   //Initialize NL For RTT
   if(0!=ath_netlink_init())
   {
       ath6kl_err("RTT Init Failed to Initialize NetLink Interface \n");
       return -ENODEV;
   }
   return 0;
}
Пример #5
0
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
{
	unsigned long timeout;
	u32 rx_word = 0;
	int ret = 0;

	timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
	while (time_before(jiffies, timeout) && !rx_word) {
		ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
					  (u8 *)&rx_word, sizeof(rx_word),
					  HIF_RD_SYNC_BYTE_INC);
		if (ret) {
			ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
			return ret;
		}

		 /* all we really want is one bit */
		rx_word &= (1 << ENDPOINT1);
	}

	if (!rx_word) {
		ath6kl_err("bmi_recv_buf FIFO empty\n");
		return -EINVAL;
	}

	return ret;
}
Пример #6
0
static int ath6kl_vreg_disable(struct ath6kl_power_vreg_data *vreg)
{
	int rc = 0;

	if (!vreg)
		return rc;

	ath6kl_dbg(ATH6KL_DBG_BOOT, "vreg_disable for : %s\n", vreg->name);

	if (vreg->is_enabled) {
		rc = regulator_disable(vreg->reg);
		if (rc) {
			ath6kl_err("regulator_disable(%s) failed. rc=%d\n",
					vreg->name, rc);
			goto out;
		}
		vreg->is_enabled = false;

		if (vreg->set_voltage_sup) {
			/* Set the min voltage to 0 */
			rc = regulator_set_voltage(vreg->reg,
						0,
						vreg->high_vol_level);
			if (rc) {
				ath6kl_err("vreg_set_vol(%s) failed rc=%d\n",
						vreg->name, rc);
				goto out;

			}
		}
	}

out:
	return rc;
}
Пример #7
0
void ath_netlink_send(char *event_data, u32 event_datalen)
{
	struct sk_buff *skb = NULL;
	struct nlmsghdr *nlh;

	skb = nlmsg_new(NLMSG_SPACE(event_datalen), GFP_ATOMIC);
	if (!skb) {
		ath6kl_err("%s: No memory,\n", __func__);
		return;
	}

	nlh = nlmsg_put(skb, gpid, 0, 0 , NLMSG_SPACE(event_datalen), 0);
	if (!nlh) {
		ath6kl_err("%s: nlmsg_put() failed\n", __func__);
		return;
	}

	memcpy(NLMSG_DATA(nlh), event_data, event_datalen);

#ifdef ATH6KL_SUPPORT_NETLINK_KERNEL3_7
	NETLINK_CB(skb).portid = 0;        /* from kernel */
#else
	NETLINK_CB(skb).pid = 0;        /* from kernel */
#endif
	NETLINK_CB(skb).dst_group = 0;  /* unicast */
	netlink_unicast(ath_nl_sock, skb, gpid, MSG_DONTWAIT);
}
Пример #8
0
static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
{
	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);

	if (!ath6kl_cfg80211_ready(ar))
		return -EIO;

	if (test_bit(CONNECTED, &ar->flag)) {
		ar->tx_pwr = 0;

		if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
			ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
			return -EIO;
		}

		wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
						 5 * HZ);

		if (signal_pending(current)) {
			ath6kl_err("target did not respond\n");
			return -EINTR;
		}
	}

	*dbm = ar->tx_pwr;
	return 0;
}
void ath6kl_mangle_mac_address(struct ath6kl *ar, u8 locally_administered_bit)
{
	u8 *ptr_mac;
	int i, ret;
	u8 *macbuf;

	switch (ar->target_type) {
	case TARGET_TYPE_AR6003:
		ptr_mac = ar->fw_board + AR6003_MAC_ADDRESS_OFFSET;
		break;
	case TARGET_TYPE_AR6004:
		ptr_mac = ar->fw_board + AR6004_MAC_ADDRESS_OFFSET;
		break;
	default:
		ath6kl_err("Invalid Target Type\n");
		return;
	}

/* #if 0 mac address issue - It sometimes changed macaddress */
	ath6kl_dbg(ATH6KL_DBG_BOOT,
		   "MAC from EEPROM %02X:%02X:%02X:%02X:%02X:%02X\n",
		   ptr_mac[0], ptr_mac[1], ptr_mac[2],
		   ptr_mac[3], ptr_mac[4], ptr_mac[5]);
/* #endif */

	ret = ath6kl_fetch_nvmac_info(ar);

	if (ret) {
		ath6kl_err("MAC address nvmac file not found\n");
		return;
	}
	macbuf = kmalloc(ath6kl_softmac_len + 1, GFP_ATOMIC);
	if (macbuf) {
		unsigned int softmac[6];
		memcpy(macbuf, ath6kl_softmac, ath6kl_softmac_len);
		macbuf[ath6kl_softmac_len] = '\0';

		if (sscanf(macbuf, "%02x:%02x:%02x:%02x:%02x:%02x",
				   &softmac[0], &softmac[1], &softmac[2],
				   &softmac[3], &softmac[4], &softmac[5])
				 == 6) {

			for (i = 0; i < 6; ++i)
				ptr_mac[i] = softmac[i] & 0xff;
	}

		ath6kl_dbg(ATH6KL_DBG_BOOT,
			"MAC from SoftMAC %02X_%02X:%02X\n",
			ptr_mac[0], ptr_mac[4], ptr_mac[5]);
		}
	vfree(ath6kl_softmac);

	if (locally_administered_bit)
		ptr_mac[0] |= 0x02;

	ath6kl_calculate_crc(ar->target_type, ar->fw_board, ar->fw_board_len);
}
Пример #10
0
struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
{
	int ret = 0;
	struct wireless_dev *wdev;
	struct ath6kl *ar;

	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
	if (!wdev) {
		ath6kl_err("couldn't allocate wireless device\n");
		return NULL;
	}

	/* create a new wiphy for use with cfg80211 */
	wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
	if (!wdev->wiphy) {
		ath6kl_err("couldn't allocate wiphy device\n");
		kfree(wdev);
		return NULL;
	}

	ar = wiphy_priv(wdev->wiphy);
	ar->p2p = !!ath6kl_p2p;

	wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;

	wdev->wiphy->max_remain_on_channel_duration = 5000;

	/* set device pointer for wiphy */
	set_wiphy_dev(wdev->wiphy, dev);

	wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
		BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
	if (ar->p2p) {
		wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
			BIT(NL80211_IFTYPE_P2P_CLIENT);
	}
	/* max num of ssids that can be probed during scanning */
	wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
	wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;

	wdev->wiphy->cipher_suites = cipher_suites;
	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);

	ret = wiphy_register(wdev->wiphy);
	if (ret < 0) {
		ath6kl_err("couldn't register wiphy device\n");
		wiphy_free(wdev->wiphy);
		kfree(wdev);
		return NULL;
	}

	return wdev;
}
Пример #11
0
int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
{
	u32 cid = BMI_READ_MEMORY;
	int ret;
	u32 offset;
	u32 len_remain, rx_len;
	u16 size;

	if (ar->bmi.done_sent) {
		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
		return -EACCES;
	}

	size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len);
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
	memset(ar->bmi.cmd_buf, 0, size);

	ath6kl_dbg(ATH6KL_DBG_BMI,
		   "bmi read memory: device: addr: 0x%x, len: %d\n",
		   addr, len);

	len_remain = len;

	while (len_remain) {
		rx_len = (len_remain < ar->bmi.max_data_size) ?
					len_remain : ar->bmi.max_data_size;
		offset = 0;
		memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
		offset += sizeof(cid);
		memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
		offset += sizeof(addr);
		memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
		offset += sizeof(len);

		ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
		if (ret) {
			ath6kl_err("Unable to write to the device: %d\n",
				   ret);
			return ret;
		}
		ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len);
		if (ret) {
			ath6kl_err("Unable to read from the device: %d\n",
				   ret);
			return ret;
		}
		memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len);
		len_remain -= rx_len; addr += rx_len;
	}

	return 0;
}
Пример #12
0
/* mailbox recv message polling */
int ath6kl_hif_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
			      int timeout)
{
	struct ath6kl_irq_proc_registers *rg;
	int status = 0, i;
	u8 htc_mbox = 1 << HTC_MAILBOX;

	for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
		/* this is the standard HIF way, load the reg table */
		status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
					     (u8 *) &dev->irq_proc_reg,
					     sizeof(dev->irq_proc_reg),
					     HIF_RD_SYNC_BYTE_INC);

		if (status) {
			ath6kl_err("failed to read reg table\n");
			return status;
		}

		/* check for MBOX data and valid lookahead */
		if (dev->irq_proc_reg.host_int_status & htc_mbox) {
			if (dev->irq_proc_reg.rx_lkahd_valid &
			    htc_mbox) {
				/*
				 * Mailbox has a message and the look ahead
				 * is valid.
				 */
				rg = &dev->irq_proc_reg;
				*lk_ahd =
					le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
				break;
			}
		}

		/* delay a little  */
		mdelay(ATH6KL_TIME_QUANTUM);
		ath6kl_dbg(ATH6KL_DBG_HIF, "hif retry mbox poll try %d\n", i);
	}

	if (i == 0) {
		ath6kl_err("timeout waiting for recv message\n");
		status = -ETIME;
		/* check if the target asserted */
		if (dev->irq_proc_reg.counter_int_status &
		    ATH6KL_TARGET_DEBUG_INTR_MASK)
			/*
			 * Target failure handler will be called in case of
			 * an assert.
			 */
			ath6kl_hif_proc_dbg_intr(dev);
	}

	return status;
}
Пример #13
0
int ath_netlink_init()
{
#ifdef ATH6KL_SUPPORT_NETLINK_KERNEL3_7
	struct netlink_kernel_cfg netlink_cfg;

	if (ath_nl_sock == NULL) {
		netlink_cfg.groups = 1;
		netlink_cfg.input = ath_netlink_receive;
		netlink_cfg.cb_mutex = NULL;
		netlink_cfg.bind = NULL;
		netlink_cfg.flags = 0;

		ath_nl_sock = (struct sock *)netlink_kernel_create(
					&init_net, NETLINK_ATH_EVENT,
					&netlink_cfg);
		if (ath_nl_sock == NULL) {
			ath6kl_err("%s NetLink Create Failed\n", __func__);
			return -ENODEV;
		}
	}
#elif defined(ATH6KL_SUPPORT_NETLINK_KERNEL3_6)
	struct netlink_kernel_cfg netlink_cfg;

	if (ath_nl_sock == NULL) {
		netlink_cfg.groups = 1;
		netlink_cfg.input = ath_netlink_receive;
		netlink_cfg.cb_mutex = NULL;
		netlink_cfg.bind = NULL;

		ath_nl_sock = (struct sock *)netlink_kernel_create(
					&init_net, NETLINK_ATH_EVENT,
					THIS_MODULE,
					&netlink_cfg);
		if (ath_nl_sock == NULL) {
			ath6kl_err("%s NetLink Create Failed\n", __func__);
			return -ENODEV;
		}
	}
#else
	if (ath_nl_sock == NULL) {
		ath_nl_sock = (struct sock *)netlink_kernel_create(
					&init_net, NETLINK_ATH_EVENT,
					1, &ath_netlink_receive, NULL,
					THIS_MODULE);
		if (ath_nl_sock == NULL) {
			ath6kl_err("%s NetLink Create Failed\n", __func__);
			return -ENODEV;
		}
	}
#endif

	return 0;
}
Пример #14
0
static int ath6kl_sdio_probe(struct platform_device *pdev)
{
	struct ath6kl_platform_data *pdata = NULL;
	struct device *dev = &pdev->dev;
	int ret = 0;
	int length;
	char buf[3];

	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);

	if (!pdata) {
		ath6kl_err("%s: Could not allocate memory for platform data\n",
				__func__);
		up(&wifi_control_sem);
		return -ENOMEM;
	}

	if (ath6kl_dt_parse_vreg_info(dev, &pdata->wifi_chip_pwd,
		"qca,wifi-chip-pwd") != 0) {
		ath6kl_err("%s: parse vreg info error\n", __func__);
		goto err;
	}

	pdata->pdev = pdev;
	platform_set_drvdata(pdev, pdata);
	gpdata = pdata;

	if (pdata->wifi_chip_pwd != NULL) {
		ret = ath6kl_platform_power(pdata, 1);
		if (ret == 0) {
			mdelay(50);
			length = snprintf(buf, sizeof(buf), "%d\n", 1 ? 1 : 0);
			android_readwrite_file(
				"/sys/devices/msm_sdcc.3/polling",
					NULL, buf, length);
			length = snprintf(buf, sizeof(buf), "%d\n", 0 ? 1 : 0);
			android_readwrite_file(
				"/sys/devices/msm_sdcc.3/polling",
					NULL, buf, length);
			mdelay(500);
		}
	}

	up(&wifi_control_sem);
	return ret;

err:
	if (pdata != NULL)
		devm_kfree(dev, pdata);

	up(&wifi_control_sem);
	return -EINVAL;
}
Пример #15
0
struct ath6kl *ath6kl_core_alloc(struct device *sdev)
{
	struct net_device *dev;
	struct ath6kl *ar;
	struct wireless_dev *wdev;

	wdev = ath6kl_cfg80211_init(sdev);
	if (!wdev) {
		ath6kl_err("ath6kl_cfg80211_init failed\n");
		return NULL;
	}

	ar = wdev_priv(wdev);
	ar->dev = sdev;
	ar->wdev = wdev;
	wdev->iftype = NL80211_IFTYPE_STATION;

	dev = alloc_netdev(0, "wlan%d", ether_setup);
	if (!dev) {
		ath6kl_err("no memory for network device instance\n");
		ath6kl_cfg80211_deinit(ar);
		return NULL;
	}

	dev->ieee80211_ptr = wdev;
	SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
	wdev->netdev = dev;
	ar->sme_state = SME_DISCONNECTED;
	ar->auto_auth_stage = AUTH_IDLE;

	init_netdev(dev);

	ar->net_dev = dev;
	set_bit(WLAN_ENABLED, &ar->flag);

	ar->wlan_pwr_state = WLAN_POWER_STATE_ON;

	spin_lock_init(&ar->lock);

	ath6kl_init_control_info(ar);
	init_waitqueue_head(&ar->event_wq);
	sema_init(&ar->sem, 1);
	clear_bit(DESTROY_IN_PROGRESS, &ar->flag);

	INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);

	setup_timer(&ar->disconnect_timer, disconnect_timer_handler,
		    (unsigned long) dev);

	return ar;
}
Пример #16
0
int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
{
	u32 cid = BMI_LZ_DATA;
	int ret;
	u32 offset;
	u32 len_remain, tx_len;
	const u32 header = sizeof(cid) + sizeof(len);
	u16 size;

	if (ar->bmi.done_sent) {
		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
		return -EACCES;
	}

	size = ar->bmi.max_data_size + header;
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
	memset(ar->bmi.cmd_buf, 0, size);

	ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n",
		   len);

	len_remain = len;
	while (len_remain) {
		tx_len = (len_remain < (ar->bmi.max_data_size - header)) ?
			  len_remain : (ar->bmi.max_data_size - header);

		offset = 0;
		memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
		offset += sizeof(cid);
		memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
		offset += sizeof(tx_len);
		memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
		       tx_len);
		offset += tx_len;

		ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
		if (ret) {
			ath6kl_err("Unable to write to the device: %d\n",
				   ret);
			return ret;
		}

		len_remain -= tx_len;
	}

	return 0;
}
Пример #17
0
static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
{
	if (!test_bit(WMI_READY, &ar->flag)) {
		ath6kl_err("wmi is not ready\n");
		return false;
	}

	if (!test_bit(WLAN_ENABLED, &ar->flag)) {
		ath6kl_err("wlan disabled\n");
		return false;
	}

	return true;
}
Пример #18
0
static void ap_keepalive_start(unsigned long arg)
{
	struct ap_keepalive_info *ap_keepalive = (struct ap_keepalive_info *) arg;
	struct ath6kl_vif *vif = ap_keepalive->vif;
	int ret;

	BUG_ON(!vif);

	ath6kl_dbg(ATH6KL_DBG_KEEPALIVE,
		   "ap_keepalive timer (vif idx %d) sta_list_index %x %s\n",
		   vif->fw_vif_idx,
		   vif->sta_list_index,
		   (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_PRELOAD_STAT) ? "preload" : "update check");

	if ((vif->nw_type == AP_NETWORK) &&
	    test_bit(CONNECTED, &vif->flags)) {		
	    	if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_PRELOAD_STAT) {
			/* FIXME : get last_txrx_time pre N sec. and to check it in next run. */
			ret = ap_keepalive_preload_txrx_time(vif);
			if (ret) {
				ath6kl_err("preload last_txrx_time fail, ret %d\n", ret);
			}
		} else {
			/* Update and check last TXRX time each stations. */
			ret = ap_keepalive_update_check_txrx_time(vif);
			if (ret) {
				ath6kl_err("update and check last_txrx_time fail, ret %d\n", ret);
			}
	    	}

		if ((ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_START) &&
		    (ap_keepalive->ap_ka_interval)) {
		    	if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_PRELOAD_STAT) {
				mod_timer(&ap_keepalive->ap_ka_timer,
					  jiffies + 
					  msecs_to_jiffies(ATH6KL_AP_KA_PRELOAD_STAT_TIME));
				ap_keepalive->flags &= ~ATH6KL_AP_KA_FLAGS_PRELOAD_STAT;
		    	} else {
				mod_timer(&ap_keepalive->ap_ka_timer,
					  jiffies + 
					  msecs_to_jiffies(ap_keepalive->ap_ka_interval) -
					  msecs_to_jiffies(ATH6KL_AP_KA_PRELOAD_STAT_TIME));
				ap_keepalive->flags |= ATH6KL_AP_KA_FLAGS_PRELOAD_STAT;
		    	}
		}
	}
	
	return;
}
Пример #19
0
int ath6kl_hif_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
			      int timeout)
{
	struct ath6kl_irq_proc_registers *rg;
	int status = 0, i;
	u8 htc_mbox = 1 << HTC_MAILBOX;

	for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
		
		status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
					     (u8 *) &dev->irq_proc_reg,
					     sizeof(dev->irq_proc_reg),
					     HIF_RD_SYNC_BYTE_INC);

		if (status) {
			ath6kl_err("failed to read reg table\n");
			return status;
		}

		
		if (dev->irq_proc_reg.host_int_status & htc_mbox) {
			if (dev->irq_proc_reg.rx_lkahd_valid &
			    htc_mbox) {
				
				rg = &dev->irq_proc_reg;
				*lk_ahd =
					le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
				break;
			}
		}

		
		mdelay(ATH6KL_TIME_QUANTUM);
		ath6kl_dbg(ATH6KL_DBG_HIF, "hif retry mbox poll try %d\n", i);
	}

	if (i == 0) {
		ath6kl_err("timeout waiting for recv message\n");
		status = -ETIME;
		
		if (dev->irq_proc_reg.counter_int_status &
		    ATH6KL_TARGET_DEBUG_INTR_MASK)
			
			ath6kl_hif_proc_dbg_intr(dev);
	}

	return status;
}
Пример #20
0
static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
					  struct net_device *dev,
					  bool pmgmt, int timeout)
{
	struct ath6kl *ar = ath6kl_priv(dev);
	struct wmi_power_mode_cmd mode;

	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
		   __func__, pmgmt, timeout);

	if (!ath6kl_cfg80211_ready(ar))
		return -EIO;

	if (pmgmt) {
		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
		mode.pwr_mode = REC_POWER;
	} else {
		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
		mode.pwr_mode = MAX_PERF_POWER;
	}

	if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
		ath6kl_err("wmi_powermode_cmd failed\n");
		return -EIO;
	}

	return 0;
}
Пример #21
0
void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
			 bool wait_fot_compltn, bool cold_reset)
{
	int status = 0;
	u32 address;
	__le32 data;

	if (target_type != TARGET_TYPE_AR6003 &&
		target_type != TARGET_TYPE_AR6004)
		return;

	data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) :
			    cpu_to_le32(RESET_CONTROL_MBOX_RST);

	switch (target_type) {
	case TARGET_TYPE_AR6003:
		address = AR6003_RESET_CONTROL_ADDRESS;
		break;
	case TARGET_TYPE_AR6004:
		address = AR6004_RESET_CONTROL_ADDRESS;
		break;
	default:
		address = AR6003_RESET_CONTROL_ADDRESS;
		break;
	}

	status = ath6kl_diag_write32(ar, address, data);

	if (status)
		ath6kl_err("failed to reset target\n");
}
Пример #22
0
static int ath6kl_set_auth_type(struct ath6kl *ar,
				enum nl80211_auth_type auth_type)
{

	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);

	switch (auth_type) {
	case NL80211_AUTHTYPE_OPEN_SYSTEM:
		ar->dot11_auth_mode = OPEN_AUTH;
		break;
	case NL80211_AUTHTYPE_SHARED_KEY:
		ar->dot11_auth_mode = SHARED_AUTH;
		break;
	case NL80211_AUTHTYPE_NETWORK_EAP:
		ar->dot11_auth_mode = LEAP_AUTH;
		break;

	case NL80211_AUTHTYPE_AUTOMATIC:
		ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
		break;

	default:
		ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
		return -ENOTSUPP;
	}

	return 0;
}
Пример #23
0
/*
 * We need to differentiate between the surprise and planned removal of the
 * device because of the following consideration:
 *
 * - In case of surprise removal, the hcd already frees up the pending
 *   for the device and hence there is no need to unregister the function
 *   driver inorder to get these requests. For planned removal, the function
 *   driver has to explicitly unregister itself to have the hcd return all the
 *   pending requests before the data structures for the devices are freed up.
 *   Note that as per the current implementation, the function driver will
 *   end up releasing all the devices since there is no API to selectively
 *   release a particular device.
 *
 * - Certain commands issued to the target can be skipped for surprise
 *   removal since they will anyway not go through.
 */
void ath6kl_destroy(struct net_device *dev, unsigned int unregister)
{
	struct ath6kl *ar;

	if (!dev || !ath6kl_priv(dev)) {
		ath6kl_err("failed to get device structure\n");
		return;
	}

	ar = ath6kl_priv(dev);

	destroy_workqueue(ar->ath6kl_wq);

	if (ar->htc_target)
		htc_cleanup(ar->htc_target);

	aggr_module_destroy(ar->aggr_cntxt);

	ath6kl_cookie_cleanup(ar);

	ath6kl_cleanup_amsdu_rxbufs(ar);

	ath6kl_bmi_cleanup(ar);

	if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) {
		unregister_netdev(dev);
		clear_bit(NETDEV_REGISTERED, &ar->flag);
	}

	free_netdev(dev);

	ath6kl_cfg80211_deinit(ar);
}
Пример #24
0
static void ath6kl_calculate_crc(u32 target_type, u8 *data, size_t len)
{
	u16 *crc, *data_idx;
	u16 checksum;
	int i;

	if (target_type == TARGET_TYPE_AR6003) {
		crc = (u16 *)(data + 0x04);
	} else if (target_type == TARGET_TYPE_AR6004) {
		len = 1024;
		crc = (u16 *)(data + 0x04);
	} else {
		ath6kl_err("Invalid target type\n");
		return;
	}

	ath6kl_dbg(ATH6KL_DBG_BOOT, "Old Checksum: %u\n", *crc);

	*crc = 0;
	checksum = 0;
	data_idx = (u16 *)data;

	for (i = 0; i < len; i += 2) {
		checksum = checksum ^ (*data_idx);
		data_idx++;
	}

	*crc = cpu_to_le16(checksum);

	ath6kl_dbg(ATH6KL_DBG_BOOT, "New Checksum: %u\n", checksum);
}
Пример #25
0
void ath6kl_target_failure(struct ath6kl *ar)
{
	ath6kl_err("target asserted\n");

	/* try dumping target assertion information (if any) */
	ath6kl_dump_target_assert_info(ar);

}
Пример #26
0
static void ath6kl_dump_target_assert_info(struct ath6kl *ar)
{
	u32 address;
	u32 regdump_loc = 0;
	int status;
	u32 regdump_val[REGISTER_DUMP_LEN_MAX];
	u32 i;

	if (ar->target_type != TARGET_TYPE_AR6003)
		return;

	/* the reg dump pointer is copied to the host interest area */
	address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
	address = TARG_VTOP(address);

	/* read RAM location through diagnostic window */
	status = ath6kl_read_reg_diag(ar, &address, &regdump_loc);

	if (status || !regdump_loc) {
		ath6kl_err("failed to get ptr to register dump area\n");
		return;
	}

	ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n",
		regdump_loc);

	regdump_loc = TARG_VTOP(regdump_loc);

	/* fetch register dump data */
	status = ath6kl_access_datadiag(ar,
					regdump_loc,
					(u8 *)&regdump_val[0],
					REG_DUMP_COUNT_AR6003 * (sizeof(u32)),
					true);

	if (status) {
		ath6kl_err("failed to get register dump\n");
		return;
	}
	ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n");

	for (i = 0; i < REG_DUMP_COUNT_AR6003; i++)
		ath6kl_dbg(ATH6KL_DBG_TRC, " %d :  0x%8.8X\n",
			   i, regdump_val[i]);

}
Пример #27
0
int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
{
	u32 cid = BMI_EXECUTE;
	int ret;
	u32 offset;
	u16 size;

	if (ar->bmi.done_sent) {
		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
		return -EACCES;
	}

	size = sizeof(cid) + sizeof(addr) + sizeof(param);
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
	memset(ar->bmi.cmd_buf, 0, size);

	ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n",
		   addr, *param);

	offset = 0;
	memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
	offset += sizeof(cid);
	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
	offset += sizeof(addr);
	memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
	offset += sizeof(*param);

	ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to write to the device: %d\n", ret);
		return ret;
	}

	ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
	if (ret) {
		ath6kl_err("Unable to read from the device: %d\n", ret);
		return ret;
	}

	memcpy(param, ar->bmi.cmd_buf, sizeof(*param));

	return 0;
}
Пример #28
0
static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev)
{
	int status;
	u8 error_int_status;
	u8 reg_buf[4];

	ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n");

	error_int_status = dev->irq_proc_reg.error_int_status & 0x0F;
	if (!error_int_status) {
		WARN_ON(1);
		return -EIO;
	}

	ath6kl_dbg(ATH6KL_DBG_IRQ,
		   "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
		   error_int_status);

	if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status))
		ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n");

	if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status))
		ath6kl_err("rx underflow\n");

	if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status))
		ath6kl_err("tx overflow\n");

	/* Clear the interrupt */
	dev->irq_proc_reg.error_int_status &= ~error_int_status;

	/* set W1C value to clear the interrupt, this hits the register first */
	reg_buf[0] = error_int_status;
	reg_buf[1] = 0;
	reg_buf[2] = 0;
	reg_buf[3] = 0;

	status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
				     reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);

	if (status)
		WARN_ON(1);

	return status;
}
Пример #29
0
static int ath6kl_upload_otp(struct ath6kl *ar)
{
	const char *filename;
	u32 address, param;
	int ret;

	switch (ar->version.target_ver) {
	case AR6003_REV2_VERSION:
		filename = AR6003_REV2_OTP_FILE;
		break;
	default:
		filename = AR6003_REV3_OTP_FILE;
		break;
	}

	if (ar->fw_otp == NULL) {
		ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
				    &ar->fw_otp_len);
		if (ret) {
			ath6kl_err("Failed to get OTP file %s: %d\n",
				   filename, ret);
			return ret;
		}
	}

	address = ath6kl_get_load_address(ar->version.target_ver,
					  APP_LOAD_ADDR);

	ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp,
				       ar->fw_otp_len);
	if (ret) {
		ath6kl_err("Failed to upload OTP file: %d\n", ret);
		return ret;
	}

	/* execute the OTP code */
	param = 0;
	address = ath6kl_get_load_address(ar->version.target_ver,
					  APP_START_OVERRIDE_ADDR);
	ath6kl_bmi_execute(ar, address, &param);

	return ret;
}
Пример #30
0
static int ath6kl_upload_patch(struct ath6kl *ar)
{
	const char *filename;
	u32 address, param;
	int ret;

	switch (ar->version.target_ver) {
	case AR6003_REV2_VERSION:
		filename = AR6003_REV2_PATCH_FILE;
		break;
	default:
		filename = AR6003_REV3_PATCH_FILE;
		break;
	}

	if (ar->fw_patch == NULL) {
		ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
				    &ar->fw_patch_len);
		if (ret) {
			ath6kl_err("Failed to get patch file %s: %d\n",
				   filename, ret);
			return ret;
		}
	}

	address = ath6kl_get_load_address(ar->version.target_ver,
					  DATASET_PATCH_ADDR);

	ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len);
	if (ret) {
		ath6kl_err("Failed to write patch file: %d\n", ret);
		return ret;
	}

	param = address;
	ath6kl_bmi_write(ar,
			 ath6kl_get_hi_item_addr(ar,
			 HI_ITEM(hi_dset_list_head)),
			 (unsigned char *) &param, 4);

	return 0;
}