Example #1
0
static int ath6kl_configure_vreg(struct ath6kl_power_vreg_data *vreg)
{
	int rc = 0;

	ath6kl_dbg(ATH6KL_DBG_BOOT, "config %s\n", vreg->name);

	/* Get the regulator handle for vreg */
	if (!(vreg->reg)) {
		rc = ath6kl_vreg_init(vreg);
		if (rc < 0)
			return rc;
	}

	rc = ath6kl_vreg_enable(vreg);
	if (rc < 0)
		return rc;

	return rc;
}
void ath6kl_ap_keepalive_deinit(struct ath6kl_vif *vif)
{
	struct ap_keepalive_info *ap_keepalive = vif->ap_keepalive_ctx;

	if (ap_keepalive) {
		if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_START)
			del_timer(&ap_keepalive->ap_ka_timer);

		kfree(ap_keepalive);
	}

	vif->ap_keepalive_ctx = NULL;

	ath6kl_dbg(ATH6KL_DBG_KEEPALIVE,
		   "ap_keepalive deinit (vif idx %d)\n",
		   vif->fw_vif_idx);

	return;
}
int rttm_issue_request(void *buf, u32 len)
{
	struct rttm_context *prttm = NULL;
	struct nsp_header hdr;
	u32 ftype;
	struct ath6kl *ar = NULL;
	enum wmi_cmd_id cmd_id = WMI_RTT_MEASREQ_CMDID;
	prttm = DEV_GETRTT_HDL();

	ar = prttm->ar;
	memcpy(&hdr, buf, NSP_HDR_LEN);
	ftype = hdr.frame_type;
	ath6kl_dbg(ATH6KL_DBG_RTT, "RTT Req Type : %d Len : %d ", ftype, len);
	if (ftype == NSP_MRQST) {
		struct nsp_mrqst *pstmrqst =
				(struct nsp_mrqst *)(buf + NSP_HDR_LEN);
		ath6kl_dbg(ATH6KL_DBG_RTT, "NSP Request ID:%d mode:%d  "
				"channel : %d NoMeas : %d Rate : %x\n ",
				pstmrqst->request_id, pstmrqst->mode,
				pstmrqst->channel, pstmrqst->no_of_measurements,
				pstmrqst->transmit_rate);
		if (pstmrqst->no_of_measurements > 10) {
			ath6kl_dbg(ATH6KL_DBG_RTT,
					"RTTREQ No Measurements >10 : %d ",
					pstmrqst->no_of_measurements);
			return -EINVAL;
		}
		cmd_id = WMI_RTT_MEASREQ_CMDID;
	} else if (ftype == NSP_RTTCONFIG) {
		struct nsp_rtt_config *pstrttcfg =
				(struct nsp_rtt_config *)(buf + NSP_HDR_LEN);
		ath6kl_dbg(ATH6KL_DBG_RTT, "NSP RTTCFG 2gCal%d 5gCal:%d "
				"FFTScale: %d RngScale:%d "
				"CLKSpeed2g : %d\n CLKSpeed5g : %d",
				pstrttcfg->ClkCal[0], pstrttcfg->ClkCal[1],
				pstrttcfg->FFTScale, pstrttcfg->RangeScale,
				pstrttcfg->ClkSpeed[0], pstrttcfg->ClkSpeed[1]);
		cmd_id = WMI_RTT_CONFIG_CMDID;
	} else if (ftype == NSP_RTTCLKCAL_INFO) {
		ath6kl_dbg(ATH6KL_DBG_RTT, "NSP CLK CALINFO CMD\n");
		cmd_id = WMI_RTT_CLKCALINFO_CMDID;
	}

	if (wmi_rtt_req(ar->wmi, cmd_id, buf + NSP_HDR_LEN,
			len - NSP_HDR_LEN)) {
		ath6kl_dbg(ATH6KL_DBG_RTT, "RTT Req Fail ");
		return -EIO;
	}
	return 0;
}
int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
{
	u32 cid = BMI_READ_SOC_REGISTER;
	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 read SOC reg: 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;
	}

	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;
}
Example #5
0
/*
 * Set HTC/Mbox operational parameters, this can only be called when the
 * target is in the BMI phase.
 */
static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
				 u8 htc_ctrl_buf)
{
	int status;
	u32 blk_size;

	blk_size = ar->mbox_info.block_size;

	if (htc_ctrl_buf)
		blk_size |=  ((u32)htc_ctrl_buf) << 16;

	/* set the host interest area for the block size */
	status = ath6kl_bmi_write(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_mbox_io_block_sz)),
			(u8 *)&blk_size,
			4);
	if (status) {
		ath6kl_err("bmi_write_memory for IO block size failed\n");
		goto out;
	}

	ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n",
		   blk_size,
		   ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz)));

	if (mbox_isr_yield_val) {
		/* set the host interest area for the mbox ISR yield limit */
		status = ath6kl_bmi_write(ar,
				ath6kl_get_hi_item_addr(ar,
				HI_ITEM(hi_mbox_isr_yield_limit)),
				(u8 *)&mbox_isr_yield_val,
				4);
		if (status) {
			ath6kl_err("bmi_write_memory for yield limit failed\n");
			goto out;
		}
	}

out:
	return status;
}
int ath6kl_bmi_done(struct ath6kl *ar)
{
	int ret;
	u32 cid = BMI_DONE;

	if (ar->bmi.done_sent) {
		ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n");
		return 0;
	}

	ar->bmi.done_sent = true;

	ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
	if (ret) {
		ath6kl_err("Unable to send bmi done: %d\n", ret);
		return ret;
	}

	return 0;
}
Example #7
0
static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
	int ret;

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

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

	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
		ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
		if (ret != 0) {
			ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
			return -EIO;
		}
	}

	return 0;
}
Example #8
0
void ath6kl_mangle_mac_address(struct ath6kl *ar, u8 locally_administered_bit)
{
	u8 *ptr_mac;
	int i, ret;

	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;
	}

	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]);


	ret = ath6kl_fetch_mac_file(ar);
	if (ret) {
		ath6kl_err("MAC address file not found\n");
		return;
	}

	for (i = 0; i < ETH_ALEN; ++i) {
	   ptr_mac[i] = ath6kl_softmac[i] & 0xff;
	}

	kfree(ath6kl_softmac);

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

	ath6kl_calculate_crc(ar->target_type, ar->fw_board, ar->fw_board_len);
}
Example #9
0
int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
{
	u32 cid = BMI_WRITE_SOC_REGISTER;
	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 > MAX_BMI_CMDBUF_SZ) {
		WARN_ON(1);
		return -EINVAL;
	}
	memset(ar->bmi.cmd_buf, 0, size);

	ath6kl_dbg(ATH6KL_DBG_BMI,
		   "bmi write SOC reg: 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_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to write to the device: %d\n", ret);
		return ret;
	}

	return 0;
}
Example #10
0
static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
{
	u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto;
	u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len :
		&ar->grp_crypto_len;

	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
		   __func__, cipher, ucast);

	switch (cipher) {
	case 0:
		/* our own hack to use value 0 as no crypto used */
		*ar_cipher = NONE_CRYPT;
		*ar_cipher_len = 0;
		break;
	case WLAN_CIPHER_SUITE_WEP40:
		*ar_cipher = WEP_CRYPT;
		*ar_cipher_len = 5;
		break;
	case WLAN_CIPHER_SUITE_WEP104:
		*ar_cipher = WEP_CRYPT;
		*ar_cipher_len = 13;
		break;
	case WLAN_CIPHER_SUITE_TKIP:
		*ar_cipher = TKIP_CRYPT;
		*ar_cipher_len = 0;
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		*ar_cipher = AES_CRYPT;
		*ar_cipher_len = 0;
		break;
	default:
		ath6kl_err("cipher 0x%x not supported\n", cipher);
		return -ENOTSUPP;
	}

	return 0;
}
Example #11
0
static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
					struct net_device *ndev,
					enum nl80211_iftype type, u32 *flags,
					struct vif_params *params)
{
	struct ath6kl *ar = ath6kl_priv(ndev);
	struct wireless_dev *wdev = ar->wdev;

	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);

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

	switch (type) {
	case NL80211_IFTYPE_STATION:
		ar->next_mode = INFRA_NETWORK;
		break;
	case NL80211_IFTYPE_ADHOC:
		ar->next_mode = ADHOC_NETWORK;
		break;
	case NL80211_IFTYPE_AP:
		ar->next_mode = AP_NETWORK;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
		ar->next_mode = INFRA_NETWORK;
		break;
	case NL80211_IFTYPE_P2P_GO:
		ar->next_mode = AP_NETWORK;
		break;
	default:
		ath6kl_err("invalid interface type %u\n", type);
		return -EOPNOTSUPP;
	}

	wdev->iftype = type;

	return 0;
}
Example #12
0
int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
{
	u32 cid = BMI_LZ_STREAM_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 LZ stream 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 start LZ stream to the device: %d\n",
			   ret);
		return ret;
	}

	return 0;
}
Example #13
0
static int ath6kl_vreg_init(struct ath6kl_power_vreg_data *vreg)
{
	int rc = 0;
	struct device *dev = &(gpdata->pdev->dev);

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

	/* Get the regulator handle */
	vreg->reg = regulator_get(dev, vreg->name);
	if (IS_ERR(vreg->reg)) {
		rc = PTR_ERR(vreg->reg);
		ath6kl_err("%s: regulator_get(%s) failed. rc=%d\n",
			__func__, vreg->name, rc);
		goto out;
	}

	if ((regulator_count_voltages(vreg->reg) > 0)
			&& (vreg->low_vol_level) && (vreg->high_vol_level))
		vreg->set_voltage_sup = 1;

out:
	return rc;
}
Example #14
0
void ath6kl_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, bool ismcast)
{
	struct ath6kl_sta *sta;
	struct ath6kl *ar = vif->ar;
	u8 tsc[6];

	/*
	 * For AP case, keyid will have aid of STA which sent pkt with
	 * MIC error. Use this aid to get MAC & send it to hostapd.
	 */
	if (vif->nw_type == AP_NETWORK) {
		sta = ath6kl_find_sta_by_aid(ar, (keyid >> 2));
		if (!sta)
			return;

		ath6kl_dbg(ATH6KL_DBG_TRC,
			   "ap tkip mic error received from aid=%d\n", keyid);

		memset(tsc, 0, sizeof(tsc)); /* FIX: get correct TSC */
		cfg80211_michael_mic_failure(vif->ndev, sta->mac,
					     NL80211_KEYTYPE_PAIRWISE, keyid,
					     tsc, GFP_KERNEL);
	} else
Example #15
0
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
{
	struct ath6kl *ar = devt;

	memcpy(ar->mac_addr, datap, ETH_ALEN);
	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n",
		   __func__, ar->mac_addr);

	ar->version.wlan_ver = sw_ver;
	ar->version.abi_ver = abi_ver;

	snprintf(ar->wiphy->fw_version,
		 sizeof(ar->wiphy->fw_version),
		 "%u.%u.%u.%u",
		 (ar->version.wlan_ver & 0xf0000000) >> 28,
		 (ar->version.wlan_ver & 0x0f000000) >> 24,
		 (ar->version.wlan_ver & 0x00ff0000) >> 16,
		 (ar->version.wlan_ver & 0x0000ffff));

	/* indicate to the waiting thread that the ready event was received */
	set_bit(WMI_READY, &ar->flag);
	wake_up(&ar->event_wq);
}
int ath6kl_ap_keepalive_start(struct ath6kl_vif *vif)
{
	struct ap_keepalive_info *ap_keepalive = vif->ap_keepalive_ctx;

	BUG_ON(!ap_keepalive);
	BUG_ON(vif->nw_type != AP_NETWORK);

	ath6kl_dbg(ATH6KL_DBG_KEEPALIVE,
		   "ap_keepalive start (vif idx %d) flags %x\n",
		   vif->fw_vif_idx,
		   ap_keepalive->flags);

	if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_ENABLED) {
		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_START | 
					ATH6KL_AP_KA_FLAGS_PRELOAD_STAT);		
	}

	return 0;
}
Example #17
0
int ath6kl_hsic_bind(int bind)
{
	char buf[16];
	int length;

	ath6kl_dbg(ATH6KL_DBG_BOOT, "%s, bind: %d\n", __func__, bind);

	if (bind) {
		length = snprintf(buf, sizeof(buf), "%s\n", "msm_hsic_host");

		android_readwrite_file(
			"/sys/bus/platform/drivers/msm_hsic_host/bind",
			NULL, buf, length);
	} else {
		length = snprintf(buf, sizeof(buf), "%s\n", "msm_hsic_host");

		android_readwrite_file(
			"/sys/bus/platform/drivers/msm_hsic_host/unbind",
			NULL, buf, length);
	}

	return 0;
}
Example #18
0
int ath6kl_hif_setup(struct ath6kl_device *dev)
{
	int status = 0;

	spin_lock_init(&dev->lock);

	/*
	 * NOTE: we actually get the block size of a mailbox other than 0,
	 * for SDIO the block size on mailbox 0 is artificially set to 1.
	 * So we use the block size that is set for the other 3 mailboxes.
	 */
	dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size;

	/* must be a power of 2 */
	if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) {
		WARN_ON(1);
		status = -EINVAL;
		goto fail_setup;
	}

	/* assemble mask, used for padding to a block */
	dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1;

	ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
		   dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);

	/* usb doesn't support enabling interrupts */
	/* FIXME: remove check once USB support is implemented */
	if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
		return 0;

	status = ath6kl_hif_disable_intrs(dev);

fail_setup:
	return status;

}
u32 ath6kl_ap_keepalive_get_inactive_time(struct ath6kl_vif *vif, u8 *mac)
{
	struct ath6kl_sta *conn;
	u32 inact_time;

	conn = ath6kl_find_sta(vif, mac);

	if (conn) {
		inact_time = ap_keepalive_get_inactive_time(vif, conn);
	} else {
		inact_time = 0;		/* FIXME : return -1 ? */

		ath6kl_err("can't find sta %02x:%02x:%02x:%02x:%02x:%02x vif-idx %d\n", 
			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], 
			vif->fw_vif_idx);
	}

	ath6kl_dbg(ATH6KL_DBG_KEEPALIVE,
		   "ap_keepalive inact aid %d inact_time %d ms \n",
		   (conn ? (conn->aid) : 0),
		   inact_time);

	return inact_time;
}
Example #20
0
int ath6kl_configure_target(struct ath6kl *ar)
{
	u32 param, ram_reserved_size;
	u8 fw_iftype;

	fw_iftype = ath6kl_get_fw_iftype(ar);
	if (fw_iftype == 0xff)
		return -EINVAL;

	/* Tell target which HTC version it is used*/
	param = HTC_PROTOCOL_VERSION;
	if (ath6kl_bmi_write(ar,
			     ath6kl_get_hi_item_addr(ar,
			     HI_ITEM(hi_app_host_interest)),
			     (u8 *)&param, 4) != 0) {
		ath6kl_err("bmi_write_memory for htc version failed\n");
		return -EIO;
	}

	/* set the firmware mode to STA/IBSS/AP */
	param = 0;

	if (ath6kl_bmi_read(ar,
			    ath6kl_get_hi_item_addr(ar,
			    HI_ITEM(hi_option_flag)),
			    (u8 *)&param, 4) != 0) {
		ath6kl_err("bmi_read_memory for setting fwmode failed\n");
		return -EIO;
	}

	param |= (1 << HI_OPTION_NUM_DEV_SHIFT);
	param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT);
	param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
	param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);

	if (ath6kl_bmi_write(ar,
			     ath6kl_get_hi_item_addr(ar,
			     HI_ITEM(hi_option_flag)),
			     (u8 *)&param,
			     4) != 0) {
		ath6kl_err("bmi_write_memory for setting fwmode failed\n");
		return -EIO;
	}

	ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n");

	/*
	 * Hardcode the address use for the extended board data
	 * Ideally this should be pre-allocate by the OS at boot time
	 * But since it is a new feature and board data is loaded
	 * at init time, we have to workaround this from host.
	 * It is difficult to patch the firmware boot code,
	 * but possible in theory.
	 */

	if (ar->target_type == TARGET_TYPE_AR6003) {
		if (ar->version.target_ver == AR6003_REV2_VERSION) {
			param = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
			ram_reserved_size =  AR6003_REV2_RAM_RESERVE_SIZE;
		} else {
			param = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
			ram_reserved_size =  AR6003_REV3_RAM_RESERVE_SIZE;
		}

		if (ath6kl_bmi_write(ar,
				     ath6kl_get_hi_item_addr(ar,
				     HI_ITEM(hi_board_ext_data)),
				     (u8 *)&param, 4) != 0) {
			ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
			return -EIO;
		}
		if (ath6kl_bmi_write(ar,
				     ath6kl_get_hi_item_addr(ar,
				     HI_ITEM(hi_end_ram_reserve_sz)),
				     (u8 *)&ram_reserved_size, 4) != 0) {
			ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
			return -EIO;
		}
	}

	/* set the block size for the target */
	if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0))
		/* use default number of control buffers */
		return -EIO;

	return 0;
}
Example #21
0
int ath6kl_core_init(struct ath6kl *ar)
{
	int ret = 0;
	struct ath6kl_bmi_target_info targ_info;

	ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
	if (!ar->ath6kl_wq)
		return -ENOMEM;

	ret = ath6kl_bmi_init(ar);
	if (ret)
		goto err_wq;

	ret = ath6kl_bmi_get_target_info(ar, &targ_info);
	if (ret)
		goto err_bmi_cleanup;

	ar->version.target_ver = le32_to_cpu(targ_info.version);
	ar->target_type = le32_to_cpu(targ_info.type);
	ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version);

	ret = ath6kl_configure_target(ar);
	if (ret)
		goto err_bmi_cleanup;

	ar->htc_target = ath6kl_htc_create(ar);

	if (!ar->htc_target) {
		ret = -ENOMEM;
		goto err_bmi_cleanup;
	}

	ar->aggr_cntxt = aggr_init(ar->net_dev);
	if (!ar->aggr_cntxt) {
		ath6kl_err("failed to initialize aggr\n");
		ret = -ENOMEM;
		goto err_htc_cleanup;
	}

	ret = ath6kl_init_upload(ar);
	if (ret)
		goto err_htc_cleanup;

	ret = ath6kl_init(ar->net_dev);
	if (ret)
		goto err_htc_cleanup;

	/* This runs the init function if registered */
	ret = register_netdev(ar->net_dev);
	if (ret) {
		ath6kl_err("register_netdev failed\n");
		ath6kl_destroy(ar->net_dev, 0);
		return ret;
	}

	set_bit(NETDEV_REGISTERED, &ar->flag);

	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
			__func__, ar->net_dev->name, ar->net_dev, ar);

	return ret;

err_htc_cleanup:
	ath6kl_htc_cleanup(ar->htc_target);
err_bmi_cleanup:
	ath6kl_bmi_cleanup(ar);
err_wq:
	destroy_workqueue(ar->ath6kl_wq);
	return ret;
}
Example #22
0
static int ath6kl_init(struct net_device *dev)
{
	struct ath6kl *ar = ath6kl_priv(dev);
	int status = 0;
	s32 timeleft;

	if (!ar)
		return -EIO;

	/* Do we need to finish the BMI phase */
	if (ath6kl_bmi_done(ar)) {
		status = -EIO;
		goto ath6kl_init_done;
	}

	/* Indicate that WMI is enabled (although not ready yet) */
	set_bit(WMI_ENABLED, &ar->flag);
	ar->wmi = ath6kl_wmi_init(ar);
	if (!ar->wmi) {
		ath6kl_err("failed to initialize wmi\n");
		status = -EIO;
		goto ath6kl_init_done;
	}

	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);

	wlan_node_table_init(&ar->scan_table);

	/*
	 * The reason we have to wait for the target here is that the
	 * driver layer has to init BMI in order to set the host block
	 * size.
	 */
	if (ath6kl_htc_wait_target(ar->htc_target)) {
		status = -EIO;
		goto err_node_cleanup;
	}

	if (ath6kl_init_service_ep(ar)) {
		status = -EIO;
		goto err_cleanup_scatter;
	}

	/* setup access class priority mappings */
	ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest  */
	ar->ac_stream_pri_map[WMM_AC_BE] = 1;
	ar->ac_stream_pri_map[WMM_AC_VI] = 2;
	ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */

	/* give our connected endpoints some buffers */
	ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
	ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);

	/* allocate some buffers that handle larger AMSDU frames */
	ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);

	/* setup credit distribution */
	ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info);

	ath6kl_cookie_init(ar);

	/* start HTC */
	status = ath6kl_htc_start(ar->htc_target);

	if (status) {
		ath6kl_cookie_cleanup(ar);
		goto err_rxbuf_cleanup;
	}

	/* Wait for Wmi event to be ready */
	timeleft = wait_event_interruptible_timeout(ar->event_wq,
						    test_bit(WMI_READY,
							     &ar->flag),
						    WMI_TIMEOUT);

	if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
		ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
			   ATH6KL_ABI_VERSION, ar->version.abi_ver);
		status = -EIO;
		goto err_htc_stop;
	}

	if (!timeleft || signal_pending(current)) {
		ath6kl_err("wmi is not ready or wait was interrupted\n");
		status = -EIO;
		goto err_htc_stop;
	}

	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__);

	/* communicate the wmi protocol verision to the target */
	if ((ath6kl_set_host_app_area(ar)) != 0)
		ath6kl_err("unable to set the host app area\n");

	ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
			 ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;

	status = ath6kl_target_config_wlan_params(ar);
	if (!status)
		goto ath6kl_init_done;

err_htc_stop:
	ath6kl_htc_stop(ar->htc_target);
err_rxbuf_cleanup:
	ath6kl_htc_flush_rx_buf(ar->htc_target);
	ath6kl_cleanup_amsdu_rxbufs(ar);
err_cleanup_scatter:
	ath6kl_hif_cleanup_scatter(ar);
err_node_cleanup:
	wlan_node_table_cleanup(&ar->scan_table);
	ath6kl_wmi_shutdown(ar->wmi);
	clear_bit(WMI_ENABLED, &ar->flag);
	ar->wmi = NULL;

ath6kl_init_done:
	return status;
}
Example #23
0
static void get_htc_packet_credit_based(struct htc_target *target,
					struct htc_endpoint *ep,
					struct list_head *queue)
{
	int credits_required;
	int remainder;
	u8 send_flags;
	struct htc_packet *packet;
	unsigned int transfer_len;

	/* NOTE : the TX lock is held when this function is called */

	/* loop until we can grab as many packets out of the queue as we can */
	while (true) {
		send_flags = 0;
		if (list_empty(&ep->txq))
			break;

		/* get packet at head, but don't remove it */
		packet = list_first_entry(&ep->txq, struct htc_packet, list);
		if (packet == NULL)
			break;

		ath6kl_dbg(ATH6KL_DBG_HTC,
			   "%s: got head packet:0x%p , queue depth: %d\n",
			   __func__, packet, get_queue_depth(&ep->txq));

		transfer_len = packet->act_len + HTC_HDR_LENGTH;

		if (transfer_len <= target->tgt_cred_sz) {
			credits_required = 1;
		} else {
			/* figure out how many credits this message requires */
			credits_required = transfer_len / target->tgt_cred_sz;
			remainder = transfer_len % target->tgt_cred_sz;

			if (remainder)
				credits_required++;
		}

		ath6kl_dbg(ATH6KL_DBG_HTC, "%s: creds required:%d got:%d\n",
			   __func__, credits_required, ep->cred_dist.credits);

		if (ep->eid == ENDPOINT_0) {
			/*
			 * endpoint 0 is special, it always has a credit and
			 * does not require credit based flow control
			 */
			credits_required = 0;

		} else {

			if (ep->cred_dist.credits < credits_required)
				break;

			ep->cred_dist.credits -= credits_required;
			ep->ep_st.cred_cosumd += credits_required;

			/* check if we need credits back from the target */
			if (ep->cred_dist.credits <
					ep->cred_dist.cred_per_msg) {
				/* tell the target we need credits ASAP! */
				send_flags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
				ep->ep_st.cred_low_indicate += 1;
				ath6kl_dbg(ATH6KL_DBG_HTC,
					   "%s: host needs credits\n",
					   __func__);
			}
		}

		/* now we can fully dequeue */
		packet = list_first_entry(&ep->txq, struct htc_packet, list);

		list_del(&packet->list);
		/* save the number of credits this packet consumed */
		packet->info.tx.cred_used = credits_required;
		/* save send flags */
		packet->info.tx.flags = send_flags;
		packet->info.tx.seqno = ep->seqno;
		ep->seqno++;
		/* queue this packet into the caller's queue */
		list_add_tail(&packet->list, queue);
	}

}
Example #24
0
static enum htc_send_queue_result htc_try_send(struct htc_target *target,
					       struct htc_endpoint *ep,
					       struct list_head *txq)
{
	struct list_head send_queue;	/* temp queue to hold packets */
	struct htc_packet *packet, *tmp_pkt;
	struct ath6kl *ar = target->dev->ar;
	enum htc_send_full_action action;
	int tx_resources, overflow, txqueue_depth, i, good_pkts;
	u8 pipeid;

	ath6kl_dbg(ATH6KL_DBG_HTC, "%s: (queue:0x%p depth:%d)\n",
		   __func__, txq,
		   (txq == NULL) ? 0 : get_queue_depth(txq));

	/* init the local send queue */
	INIT_LIST_HEAD(&send_queue);

	/*
	 * txq equals to NULL means
	 * caller didn't provide a queue, just wants us to
	 * check queues and send
	 */
	if (txq != NULL) {
		if (list_empty(txq)) {
			/* empty queue */
			return HTC_SEND_QUEUE_DROP;
		}

		spin_lock_bh(&target->tx_lock);
		txqueue_depth = get_queue_depth(&ep->txq);
		spin_unlock_bh(&target->tx_lock);

		if (txqueue_depth >= ep->max_txq_depth) {
			/* we've already overflowed */
			overflow = get_queue_depth(txq);
		} else {
			/* get how much we will overflow by */
			overflow = txqueue_depth;
			overflow += get_queue_depth(txq);
			/* get how much we will overflow the TX queue by */
			overflow -= ep->max_txq_depth;
		}

		/* if overflow is negative or zero, we are okay */
		if (overflow > 0) {
			ath6kl_dbg(ATH6KL_DBG_HTC,
				   "%s: Endpoint %d, TX queue will overflow :%d, Tx Depth:%d, Max:%d\n",
				   __func__, ep->eid, overflow, txqueue_depth,
				   ep->max_txq_depth);
		}
		if ((overflow <= 0) ||
		    (ep->ep_cb.tx_full == NULL)) {
			/*
			 * all packets will fit or caller did not provide send
			 * full indication handler -- just move all of them
			 * to the local send_queue object
			 */
			list_splice_tail_init(txq, &send_queue);
		} else {
			good_pkts = get_queue_depth(txq) - overflow;
			if (good_pkts < 0) {
				WARN_ON_ONCE(1);
				return HTC_SEND_QUEUE_DROP;
			}

			/* we have overflowed, and a callback is provided */
			/* dequeue all non-overflow packets to the sendqueue */
			for (i = 0; i < good_pkts; i++) {
				/* pop off caller's queue */
				packet = list_first_entry(txq,
							  struct htc_packet,
							  list);
				list_del(&packet->list);
				/* insert into local queue */
				list_add_tail(&packet->list, &send_queue);
			}

			/*
			 * the caller's queue has all the packets that won't fit
			 * walk through the caller's queue and indicate each to
			 * the send full handler
			 */
			list_for_each_entry_safe(packet, tmp_pkt,
						 txq, list) {

				ath6kl_dbg(ATH6KL_DBG_HTC,
					   "%s: Indicat overflowed TX pkts: %p\n",
					   __func__, packet);
				action = ep->ep_cb.tx_full(ep->target, packet);
				if (action == HTC_SEND_FULL_DROP) {
					/* callback wants the packet dropped */
					ep->ep_st.tx_dropped += 1;

					/* leave this one in the caller's queue
					 * for cleanup */
				} else {
					/* callback wants to keep this packet,
					 * remove from caller's queue */
					list_del(&packet->list);
					/* put it in the send queue */
					list_add_tail(&packet->list,
						      &send_queue);
				}

			}

			if (list_empty(&send_queue)) {
				/* no packets made it in, caller will cleanup */
				return HTC_SEND_QUEUE_DROP;
			}
		}
	}
int ath6kl_ap_keepalive_config(struct ath6kl_vif *vif, 
			       u32 ap_ka_interval, 
			       u32 ap_ka_reclaim_cycle)
{
	struct ap_keepalive_info *ap_keepalive = vif->ap_keepalive_ctx;
	int restart = 0;

	if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_BY_SUPP) {
		ath6kl_dbg(ATH6KL_DBG_INFO,
			"already offlad to supplicant/hostapd, bypass it.\n");
		return 0;
	}

	/* FIXME : the better code protection by the spin-lock. */

	if ((ap_ka_interval != 0) &&
	    (ap_ka_interval < ATH6KL_AP_KA_INTERVAL_MIN))
		ap_ka_interval = ATH6KL_AP_KA_INTERVAL_MIN;

	if (ap_ka_reclaim_cycle == 0)
		ap_ka_reclaim_cycle = 1;

	if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_START) {
		del_timer(&ap_keepalive->ap_ka_timer);
		ap_keepalive->flags &= ~(ATH6KL_AP_KA_FLAGS_START | 
					 ATH6KL_AP_KA_FLAGS_PRELOAD_STAT);
		restart = 1;
	}

	if (ap_ka_interval == 0) {
		ap_keepalive->ap_ka_interval = 0;
		ap_keepalive->ap_ka_reclaim_cycle = 0;
		ap_keepalive->flags &= ~ATH6KL_AP_KA_FLAGS_ENABLED;
	} else {
		if (ap_ka_interval * ap_ka_reclaim_cycle < ATH6KL_AP_KA_RECLAIM_TIME_MAX) {
			ap_keepalive->ap_ka_interval = ap_ka_interval;
			ap_keepalive->ap_ka_reclaim_cycle = ap_ka_reclaim_cycle;
		} else {
			ap_keepalive->ap_ka_interval = ATH6KL_AP_KA_INTERVAL_DEFAULT;
			ap_keepalive->ap_ka_reclaim_cycle = ATH6KL_AP_KA_RECLAIM_CYCLE_DEFAULT;
		}

		ap_keepalive->ap_ka_remove_time = ap_keepalive->ap_ka_interval * ap_keepalive->ap_ka_reclaim_cycle;
		ap_keepalive->flags |= ATH6KL_AP_KA_FLAGS_ENABLED;	
			
		if (restart) {
			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 * 1000));
			ap_keepalive->flags |= (ATH6KL_AP_KA_FLAGS_START | 
						ATH6KL_AP_KA_FLAGS_PRELOAD_STAT);
		}
	}

	ath6kl_dbg(ATH6KL_DBG_KEEPALIVE,
		   "ap_keepalive config (vif idx %d interval %d cycle %d %s restart %d)\n",
		   vif->fw_vif_idx,
		   ap_keepalive->ap_ka_interval,
		   ap_keepalive->ap_ka_reclaim_cycle,
		   (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_ENABLED) ? "ON" : "OFF",
		   restart);


	return 0;
}
Example #26
0
static bool ath6kl_parse_data_pkt_for_wake_lock(struct ath6kl *ar,
						struct sk_buff *skb)
{
	struct net_device *ndev;
	struct ath6kl_vif *vif;
	struct ethhdr *hdr;
	bool need_wake = false;
	u16 dst_port;

	vif = ath6kl_vif_first(ar);
	if (!vif)
		return need_wake;

	if (skb->len < sizeof(struct ethhdr))
		return need_wake;

	hdr = (struct ethhdr *) skb->data;

#if 0 // by bbelief
	if (test_and_clear_bit(WOW_RESUME_PRINT, &ar->flag)) {
		ath6kl_dbg(ATH6KL_DBG_SUSPEND,
			   "(wow) dest mac:%pM, src mac:%pM, type/len :%04x\n",
			   hdr->h_dest, hdr->h_source,
			   be16_to_cpu(hdr->h_proto));
	}
#endif

	if (!is_multicast_ether_addr(hdr->h_dest)) {
		switch (ntohs(hdr->h_proto)) {
		case 0x0800: /* IP */
			need_wake = ath6kl_parse_ip_pkt_for_wake_lock(skb);
			break;
		case 0x888e: /* EAPOL */
		case 0x88c7: /* RSN_PREAUTH */
		case 0x88b4: /* WAPI */
			need_wake = true;
			break;
		default:
			break;
		}
	} else if (!is_broadcast_ether_addr(hdr->h_dest)) {
		if (skb->len >= 14 + 20) { /* mDNS packets */
			u8 *dst_ipaddr = (u8 *)(skb->data + 14 + 20 - 4);
			ndev = vif->ndev;
			if (((dst_ipaddr[3] & 0xf8) == 0xf8) &&
				(vif->nw_type == AP_NETWORK ||
				(ndev->flags & IFF_ALLMULTI ||
				ndev->flags & IFF_MULTICAST)))
					need_wake = true;
		}
	} else if (vif->nw_type == AP_NETWORK) {
		switch (ntohs(hdr->h_proto)) {
		case 0x0800: /* IP */
			if (skb->len >= 14 + 20 + 2) {
				dst_port = *(u16 *)(skb->data + 14 + 20);
				/* dhcp req */
				need_wake = (ntohs(dst_port) == 0x43);
			}
			break;
		case 0x0806:
			need_wake = true;
		default:
			break;
		}
	}

	return need_wake;
}
Example #27
0
int ath6kl_bmi_get_target_info(struct ath6kl *ar,
			       struct ath6kl_bmi_target_info *targ_info)
{
	int ret;
	u32 cid = BMI_GET_TARGET_INFO;

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

	ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
	if (ret) {
		ath6kl_err("Unable to send get target info: %d\n", ret);
		return ret;
	}

	if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
		ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
					  sizeof(*targ_info));
	} else {
		ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
				sizeof(targ_info->version));
	}

	if (ret) {
		ath6kl_err("Unable to recv target info: %d\n", ret);
		return ret;
	}

	if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
		
		ret = ath6kl_hif_bmi_read(ar,
				   (u8 *)&targ_info->byte_count,
				   sizeof(targ_info->byte_count));
		if (ret) {
			ath6kl_err("unable to read target info byte count: %d\n",
				   ret);
			return ret;
		}

		if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
			WARN_ON(1);
			return -EINVAL;
		}

		
		ret = ath6kl_hif_bmi_read(ar,
				   ((u8 *)targ_info) +
				   sizeof(targ_info->byte_count),
				   sizeof(*targ_info) -
				   sizeof(targ_info->byte_count));

		if (ret) {
			ath6kl_err("Unable to read target info (%d bytes): %d\n",
				   targ_info->byte_count, ret);
			return ret;
		}
	}

	ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
		   targ_info->version, targ_info->type);

	return 0;
}
Example #28
0
static int ath6kl_upload_board_file(struct ath6kl *ar)
{
	u32 board_address, board_ext_address, param;
	int ret;

	if (ar->fw_board == NULL) {
		ret = ath6kl_fetch_board_file(ar);
		if (ret)
			return ret;
	}

	/* Determine where in Target RAM to write Board Data */
	ath6kl_bmi_read(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_board_data)),
			(u8 *) &board_address, 4);
	ath6kl_dbg(ATH6KL_DBG_TRC, "board data download addr: 0x%x\n",
		   board_address);

	/* determine where in target ram to write extended board data */
	ath6kl_bmi_read(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_board_ext_data)),
			(u8 *) &board_ext_address, 4);

	ath6kl_dbg(ATH6KL_DBG_TRC, "board file download addr: 0x%x\n",
		   board_ext_address);

	if (board_ext_address == 0) {
		ath6kl_err("Failed to get board file target address.\n");
		return -EINVAL;
	}

	if (ar->fw_board_len == (AR6003_BOARD_DATA_SZ +
				 AR6003_BOARD_EXT_DATA_SZ)) {
		/* write extended board data */
		ret = ath6kl_bmi_write(ar, board_ext_address,
				       ar->fw_board + AR6003_BOARD_DATA_SZ,
				       AR6003_BOARD_EXT_DATA_SZ);

		if (ret) {
			ath6kl_err("Failed to write extended board data: %d\n",
				   ret);
			return ret;
		}

		/* record that extended board data is initialized */
		param = (AR6003_BOARD_EXT_DATA_SZ << 16) | 1;
		ath6kl_bmi_write(ar,
				 ath6kl_get_hi_item_addr(ar,
				 HI_ITEM(hi_board_ext_data_config)),
				 (unsigned char *) &param, 4);
	}

	if (ar->fw_board_len < AR6003_BOARD_DATA_SZ) {
		ath6kl_err("Too small board file: %zu\n", ar->fw_board_len);
		ret = -EINVAL;
		return ret;
	}

	ret = ath6kl_bmi_write(ar, board_address, ar->fw_board,
			       AR6003_BOARD_DATA_SZ);

	if (ret) {
		ath6kl_err("Board file bmi write failed: %d\n", ret);
		return ret;
	}

	/* record the fact that Board Data IS initialized */
	param = 1;
	ath6kl_bmi_write(ar,
			 ath6kl_get_hi_item_addr(ar,
			 HI_ITEM(hi_board_data_initialized)),
			 (u8 *)&param, 4);

	return ret;
}
Example #29
0
static int ath6kl_init_upload(struct ath6kl *ar)
{
	u32 param, options, sleep, address;
	int status = 0;

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

	/* temporarily disable system sleep */
	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
	status = ath6kl_bmi_reg_read(ar, address, &param);
	if (status)
		return status;

	options = param;

	param |= ATH6KL_OPTION_SLEEP_DISABLE;
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
	status = ath6kl_bmi_reg_read(ar, address, &param);
	if (status)
		return status;

	sleep = param;

	param |= SM(SYSTEM_SLEEP_DISABLE, 1);
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n",
		   options, sleep);

	/* program analog PLL register */
	status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER,
				      0xF9104001);
	if (status)
		return status;

	/* Run at 80/88MHz by default */
	param = SM(CPU_CLOCK_STANDARD, 1);

	address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	param = 0;
	address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;
	param = SM(LPO_CAL_ENABLE, 1);
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	/* WAR to avoid SDIO CRC err */
	if (ar->version.target_ver == AR6003_REV2_VERSION) {
		ath6kl_err("temporary war to avoid sdio crc error\n");

		param = 0x20;

		address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;

		address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;

		address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;

		address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;
	}

	/* write EEPROM data to Target RAM */
	status = ath6kl_upload_board_file(ar);
	if (status)
		return status;

	/* transfer One time Programmable data */
	status = ath6kl_upload_otp(ar);
	if (status)
		return status;

	/* Download Target firmware */
	status = ath6kl_upload_firmware(ar);
	if (status)
		return status;

	status = ath6kl_upload_patch(ar);
	if (status)
		return status;

	/* Restore system sleep */
	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
	status = ath6kl_bmi_reg_write(ar, address, sleep);
	if (status)
		return status;

	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
	param = options | 0x20;
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	/* Configure GPIO AR6003 UART */
	param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
	status = ath6kl_bmi_write(ar,
				  ath6kl_get_hi_item_addr(ar,
				  HI_ITEM(hi_dbg_uart_txpin)),
				  (u8 *)&param, 4);

	return status;
}
Example #30
0
static int htc_issue_packets(struct htc_target *target,
			     struct htc_endpoint *ep,
			     struct list_head *pkt_queue)
{
	int status = 0;
	u16 payload_len;
	struct sk_buff *skb;
	struct htc_frame_hdr *htc_hdr;
	struct htc_packet *packet;

	ath6kl_dbg(ATH6KL_DBG_HTC,
		   "%s: queue: 0x%p, pkts %d\n", __func__,
		   pkt_queue, get_queue_depth(pkt_queue));

	while (!list_empty(pkt_queue)) {
		packet = list_first_entry(pkt_queue, struct htc_packet, list);
		list_del(&packet->list);

		skb = packet->skb;
		if (!skb) {
			WARN_ON_ONCE(1);
			status = -EINVAL;
			break;
		}

		payload_len = packet->act_len;

		/* setup HTC frame header */
		htc_hdr = (struct htc_frame_hdr *) skb_push(skb,
							    sizeof(*htc_hdr));
		if (!htc_hdr) {
			WARN_ON_ONCE(1);
			status = -EINVAL;
			break;
		}

		packet->info.tx.flags |= HTC_FLAGS_TX_FIXUP_NETBUF;

		/* Endianess? */
		put_unaligned((u16) payload_len, &htc_hdr->payld_len);
		htc_hdr->flags = packet->info.tx.flags;
		htc_hdr->eid = (u8) packet->endpoint;
		htc_hdr->ctrl[0] = 0;
		htc_hdr->ctrl[1] = (u8) packet->info.tx.seqno;

		spin_lock_bh(&target->tx_lock);

		/* store in look up queue to match completions */
		list_add_tail(&packet->list, &ep->pipe.tx_lookup_queue);
		ep->ep_st.tx_issued += 1;
		spin_unlock_bh(&target->tx_lock);

		status = ath6kl_hif_pipe_send(target->dev->ar,
					      ep->pipe.pipeid_ul, NULL, skb);

		if (status != 0) {
			if (status != -ENOMEM) {
				/* TODO: if more than 1 endpoint maps to the
				 * same PipeID, it is possible to run out of
				 * resources in the HIF layer.
				 * Don't emit the error
				 */
				ath6kl_dbg(ATH6KL_DBG_HTC,
					   "%s: failed status:%d\n",
					   __func__, status);
			}
			spin_lock_bh(&target->tx_lock);
			list_del(&packet->list);

			/* reclaim credits */
			ep->cred_dist.credits += packet->info.tx.cred_used;
			spin_unlock_bh(&target->tx_lock);

			/* put it back into the callers queue */
			list_add(&packet->list, pkt_queue);
			break;
		}

	}

	if (status != 0) {
		while (!list_empty(pkt_queue)) {
			if (status != -ENOMEM) {
				ath6kl_dbg(ATH6KL_DBG_HTC,
					   "%s: failed pkt:0x%p status:%d\n",
					   __func__, packet, status);
			}

			packet = list_first_entry(pkt_queue,
						  struct htc_packet, list);
			list_del(&packet->list);
			packet->status = status;
			send_packet_completion(target, packet);
		}
	}

	return status;
}