cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

htc_hst.c (13035B)


      1/*
      2 * Copyright (c) 2010-2011 Atheros Communications Inc.
      3 *
      4 * Permission to use, copy, modify, and/or distribute this software for any
      5 * purpose with or without fee is hereby granted, provided that the above
      6 * copyright notice and this permission notice appear in all copies.
      7 *
      8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 */
     16
     17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     18
     19#include "htc.h"
     20
     21static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
     22			  u16 len, u8 flags, u8 epid)
     23
     24{
     25	struct htc_frame_hdr *hdr;
     26	struct htc_endpoint *endpoint = &target->endpoint[epid];
     27	int status;
     28
     29	hdr = skb_push(skb, sizeof(struct htc_frame_hdr));
     30	hdr->endpoint_id = epid;
     31	hdr->flags = flags;
     32	hdr->payload_len = cpu_to_be16(len);
     33	memset(hdr->control, 0, sizeof(hdr->control));
     34
     35	status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
     36
     37	return status;
     38}
     39
     40static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
     41{
     42	enum htc_endpoint_id avail_epid;
     43
     44	for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
     45		if (endpoint[avail_epid].service_id == 0)
     46			return &endpoint[avail_epid];
     47	return NULL;
     48}
     49
     50static u8 service_to_ulpipe(u16 service_id)
     51{
     52	switch (service_id) {
     53	case WMI_CONTROL_SVC:
     54		return 4;
     55	case WMI_BEACON_SVC:
     56	case WMI_CAB_SVC:
     57	case WMI_UAPSD_SVC:
     58	case WMI_MGMT_SVC:
     59	case WMI_DATA_VO_SVC:
     60	case WMI_DATA_VI_SVC:
     61	case WMI_DATA_BE_SVC:
     62	case WMI_DATA_BK_SVC:
     63		return 1;
     64	default:
     65		return 0;
     66	}
     67}
     68
     69static u8 service_to_dlpipe(u16 service_id)
     70{
     71	switch (service_id) {
     72	case WMI_CONTROL_SVC:
     73		return 3;
     74	case WMI_BEACON_SVC:
     75	case WMI_CAB_SVC:
     76	case WMI_UAPSD_SVC:
     77	case WMI_MGMT_SVC:
     78	case WMI_DATA_VO_SVC:
     79	case WMI_DATA_VI_SVC:
     80	case WMI_DATA_BE_SVC:
     81	case WMI_DATA_BK_SVC:
     82		return 2;
     83	default:
     84		return 0;
     85	}
     86}
     87
     88static void htc_process_target_rdy(struct htc_target *target,
     89				   void *buf)
     90{
     91	struct htc_endpoint *endpoint;
     92	struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
     93
     94	target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
     95
     96	endpoint = &target->endpoint[ENDPOINT0];
     97	endpoint->service_id = HTC_CTRL_RSVD_SVC;
     98	endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
     99	atomic_inc(&target->tgt_ready);
    100	complete(&target->target_wait);
    101}
    102
    103static void htc_process_conn_rsp(struct htc_target *target,
    104				 struct htc_frame_hdr *htc_hdr)
    105{
    106	struct htc_conn_svc_rspmsg *svc_rspmsg;
    107	struct htc_endpoint *endpoint, *tmp_endpoint = NULL;
    108	u16 service_id;
    109	u16 max_msglen;
    110	enum htc_endpoint_id epid, tepid;
    111
    112	svc_rspmsg = (struct htc_conn_svc_rspmsg *)
    113		((void *) htc_hdr + sizeof(struct htc_frame_hdr));
    114
    115	if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
    116		epid = svc_rspmsg->endpoint_id;
    117		if (epid < 0 || epid >= ENDPOINT_MAX)
    118			return;
    119
    120		service_id = be16_to_cpu(svc_rspmsg->service_id);
    121		max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
    122		endpoint = &target->endpoint[epid];
    123
    124		for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
    125			tmp_endpoint = &target->endpoint[tepid];
    126			if (tmp_endpoint->service_id == service_id) {
    127				tmp_endpoint->service_id = 0;
    128				break;
    129			}
    130		}
    131
    132		if (tepid == ENDPOINT0)
    133			return;
    134
    135		endpoint->service_id = service_id;
    136		endpoint->max_txqdepth = tmp_endpoint->max_txqdepth;
    137		endpoint->ep_callbacks = tmp_endpoint->ep_callbacks;
    138		endpoint->ul_pipeid = tmp_endpoint->ul_pipeid;
    139		endpoint->dl_pipeid = tmp_endpoint->dl_pipeid;
    140		endpoint->max_msglen = max_msglen;
    141		target->conn_rsp_epid = epid;
    142		complete(&target->cmd_wait);
    143	} else {
    144		target->conn_rsp_epid = ENDPOINT_UNUSED;
    145	}
    146}
    147
    148static int htc_config_pipe_credits(struct htc_target *target)
    149{
    150	struct sk_buff *skb;
    151	struct htc_config_pipe_msg *cp_msg;
    152	int ret;
    153	unsigned long time_left;
    154
    155	skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
    156	if (!skb) {
    157		dev_err(target->dev, "failed to allocate send buffer\n");
    158		return -ENOMEM;
    159	}
    160	skb_reserve(skb, sizeof(struct htc_frame_hdr));
    161
    162	cp_msg = skb_put(skb, sizeof(struct htc_config_pipe_msg));
    163
    164	cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
    165	cp_msg->pipe_id = USB_WLAN_TX_PIPE;
    166	cp_msg->credits = target->credits;
    167
    168	target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
    169
    170	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
    171	if (ret)
    172		goto err;
    173
    174	time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
    175	if (!time_left) {
    176		dev_err(target->dev, "HTC credit config timeout\n");
    177		return -ETIMEDOUT;
    178	}
    179
    180	return 0;
    181err:
    182	kfree_skb(skb);
    183	return -EINVAL;
    184}
    185
    186static int htc_setup_complete(struct htc_target *target)
    187{
    188	struct sk_buff *skb;
    189	struct htc_comp_msg *comp_msg;
    190	int ret = 0;
    191	unsigned long time_left;
    192
    193	skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
    194	if (!skb) {
    195		dev_err(target->dev, "failed to allocate send buffer\n");
    196		return -ENOMEM;
    197	}
    198	skb_reserve(skb, sizeof(struct htc_frame_hdr));
    199
    200	comp_msg = skb_put(skb, sizeof(struct htc_comp_msg));
    201	comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID);
    202
    203	target->htc_flags |= HTC_OP_START_WAIT;
    204
    205	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
    206	if (ret)
    207		goto err;
    208
    209	time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
    210	if (!time_left) {
    211		dev_err(target->dev, "HTC start timeout\n");
    212		return -ETIMEDOUT;
    213	}
    214
    215	return 0;
    216
    217err:
    218	kfree_skb(skb);
    219	return -EINVAL;
    220}
    221
    222/* HTC APIs */
    223
    224int htc_init(struct htc_target *target)
    225{
    226	int ret;
    227
    228	ret = htc_config_pipe_credits(target);
    229	if (ret)
    230		return ret;
    231
    232	return htc_setup_complete(target);
    233}
    234
    235int htc_connect_service(struct htc_target *target,
    236		     struct htc_service_connreq *service_connreq,
    237		     enum htc_endpoint_id *conn_rsp_epid)
    238{
    239	struct sk_buff *skb;
    240	struct htc_endpoint *endpoint;
    241	struct htc_conn_svc_msg *conn_msg;
    242	int ret;
    243	unsigned long time_left;
    244
    245	/* Find an available endpoint */
    246	endpoint = get_next_avail_ep(target->endpoint);
    247	if (!endpoint) {
    248		dev_err(target->dev, "Endpoint is not available for service %d\n",
    249			service_connreq->service_id);
    250		return -EINVAL;
    251	}
    252
    253	endpoint->service_id = service_connreq->service_id;
    254	endpoint->max_txqdepth = service_connreq->max_send_qdepth;
    255	endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id);
    256	endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id);
    257	endpoint->ep_callbacks = service_connreq->ep_callbacks;
    258
    259	skb = alloc_skb(sizeof(struct htc_conn_svc_msg) +
    260			    sizeof(struct htc_frame_hdr), GFP_ATOMIC);
    261	if (!skb) {
    262		dev_err(target->dev, "Failed to allocate buf to send"
    263			"service connect req\n");
    264		return -ENOMEM;
    265	}
    266
    267	skb_reserve(skb, sizeof(struct htc_frame_hdr));
    268
    269	conn_msg = skb_put(skb, sizeof(struct htc_conn_svc_msg));
    270	conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
    271	conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
    272	conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
    273	conn_msg->dl_pipeid = endpoint->dl_pipeid;
    274	conn_msg->ul_pipeid = endpoint->ul_pipeid;
    275
    276	/* To prevent infoleak */
    277	conn_msg->svc_meta_len = 0;
    278	conn_msg->pad = 0;
    279
    280	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
    281	if (ret)
    282		goto err;
    283
    284	time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
    285	if (!time_left) {
    286		dev_err(target->dev, "Service connection timeout for: %d\n",
    287			service_connreq->service_id);
    288		return -ETIMEDOUT;
    289	}
    290
    291	*conn_rsp_epid = target->conn_rsp_epid;
    292	return 0;
    293err:
    294	kfree_skb(skb);
    295	return ret;
    296}
    297
    298int htc_send(struct htc_target *target, struct sk_buff *skb)
    299{
    300	struct ath9k_htc_tx_ctl *tx_ctl;
    301
    302	tx_ctl = HTC_SKB_CB(skb);
    303	return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
    304}
    305
    306int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
    307		  enum htc_endpoint_id epid)
    308{
    309	return htc_issue_send(target, skb, skb->len, 0, epid);
    310}
    311
    312void htc_stop(struct htc_target *target)
    313{
    314	target->hif->stop(target->hif_dev);
    315}
    316
    317void htc_start(struct htc_target *target)
    318{
    319	target->hif->start(target->hif_dev);
    320}
    321
    322void htc_sta_drain(struct htc_target *target, u8 idx)
    323{
    324	target->hif->sta_drain(target->hif_dev, idx);
    325}
    326
    327void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
    328			       struct sk_buff *skb, bool txok)
    329{
    330	struct htc_endpoint *endpoint;
    331	struct htc_frame_hdr *htc_hdr = NULL;
    332
    333	if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
    334		complete(&htc_handle->cmd_wait);
    335		htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
    336		goto ret;
    337	}
    338
    339	if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
    340		complete(&htc_handle->cmd_wait);
    341		htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
    342		goto ret;
    343	}
    344
    345	if (skb) {
    346		htc_hdr = (struct htc_frame_hdr *) skb->data;
    347		if (htc_hdr->endpoint_id >= ARRAY_SIZE(htc_handle->endpoint))
    348			goto ret;
    349		endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
    350		skb_pull(skb, sizeof(struct htc_frame_hdr));
    351
    352		if (endpoint->ep_callbacks.tx) {
    353			endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
    354						  skb, htc_hdr->endpoint_id,
    355						  txok);
    356		} else {
    357			kfree_skb(skb);
    358		}
    359	}
    360
    361	return;
    362ret:
    363	kfree_skb(skb);
    364}
    365
    366static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
    367				      struct sk_buff *skb)
    368{
    369	uint32_t *pattern = (uint32_t *)skb->data;
    370
    371	switch (*pattern) {
    372	case 0x33221199:
    373		{
    374		struct htc_panic_bad_vaddr *htc_panic;
    375		htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
    376		dev_err(htc_handle->dev, "ath: firmware panic! "
    377			"exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
    378			htc_panic->exccause, htc_panic->pc,
    379			htc_panic->badvaddr);
    380		break;
    381		}
    382	case 0x33221299:
    383		{
    384		struct htc_panic_bad_epid *htc_panic;
    385		htc_panic = (struct htc_panic_bad_epid *) skb->data;
    386		dev_err(htc_handle->dev, "ath: firmware panic! "
    387			"bad epid: 0x%08x\n", htc_panic->epid);
    388		break;
    389		}
    390	default:
    391		dev_err(htc_handle->dev, "ath: unknown panic pattern!\n");
    392		break;
    393	}
    394}
    395
    396/*
    397 * HTC Messages are handled directly here and the obtained SKB
    398 * is freed.
    399 *
    400 * Service messages (Data, WMI) passed to the corresponding
    401 * endpoint RX handlers, which have to free the SKB.
    402 */
    403void ath9k_htc_rx_msg(struct htc_target *htc_handle,
    404		      struct sk_buff *skb, u32 len, u8 pipe_id)
    405{
    406	struct htc_frame_hdr *htc_hdr;
    407	enum htc_endpoint_id epid;
    408	struct htc_endpoint *endpoint;
    409	__be16 *msg_id;
    410
    411	if (!htc_handle || !skb)
    412		return;
    413
    414	htc_hdr = (struct htc_frame_hdr *) skb->data;
    415	epid = htc_hdr->endpoint_id;
    416
    417	if (epid == 0x99) {
    418		ath9k_htc_fw_panic_report(htc_handle, skb);
    419		kfree_skb(skb);
    420		return;
    421	}
    422
    423	if (epid < 0 || epid >= ENDPOINT_MAX) {
    424		if (pipe_id != USB_REG_IN_PIPE)
    425			dev_kfree_skb_any(skb);
    426		else
    427			kfree_skb(skb);
    428		return;
    429	}
    430
    431	if (epid == ENDPOINT0) {
    432
    433		/* Handle trailer */
    434		if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
    435			if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
    436				/* Move past the Watchdog pattern */
    437				htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
    438		}
    439
    440		/* Get the message ID */
    441		msg_id = (__be16 *) ((void *) htc_hdr +
    442				     sizeof(struct htc_frame_hdr));
    443
    444		/* Now process HTC messages */
    445		switch (be16_to_cpu(*msg_id)) {
    446		case HTC_MSG_READY_ID:
    447			htc_process_target_rdy(htc_handle, htc_hdr);
    448			break;
    449		case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
    450			htc_process_conn_rsp(htc_handle, htc_hdr);
    451			break;
    452		default:
    453			break;
    454		}
    455
    456		kfree_skb(skb);
    457
    458	} else {
    459		if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
    460			skb_trim(skb, len - htc_hdr->control[0]);
    461
    462		skb_pull(skb, sizeof(struct htc_frame_hdr));
    463
    464		endpoint = &htc_handle->endpoint[epid];
    465		if (endpoint->ep_callbacks.rx)
    466			endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
    467						  skb, epid);
    468	}
    469}
    470
    471struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
    472				      struct ath9k_htc_hif *hif,
    473				      struct device *dev)
    474{
    475	struct htc_endpoint *endpoint;
    476	struct htc_target *target;
    477
    478	target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
    479	if (!target)
    480		return NULL;
    481
    482	init_completion(&target->target_wait);
    483	init_completion(&target->cmd_wait);
    484
    485	target->hif = hif;
    486	target->hif_dev = hif_handle;
    487	target->dev = dev;
    488
    489	/* Assign control endpoint pipe IDs */
    490	endpoint = &target->endpoint[ENDPOINT0];
    491	endpoint->ul_pipeid = hif->control_ul_pipe;
    492	endpoint->dl_pipeid = hif->control_dl_pipe;
    493
    494	atomic_set(&target->tgt_ready, 0);
    495
    496	return target;
    497}
    498
    499void ath9k_htc_hw_free(struct htc_target *htc)
    500{
    501	kfree(htc);
    502}
    503
    504int ath9k_htc_hw_init(struct htc_target *target,
    505		      struct device *dev, u16 devid,
    506		      char *product, u32 drv_info)
    507{
    508	if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
    509		pr_err("Failed to initialize the device\n");
    510		return -ENODEV;
    511	}
    512
    513	return 0;
    514}
    515
    516void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
    517{
    518	if (target)
    519		ath9k_htc_disconnect_device(target, hot_unplug);
    520}