brintos

brintos / linux-shallow public Read only

0
0
Text · 44.5 KiB · 45fbcbd Raw
1688 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2014 Broadcom Corporation4 */5 6/*******************************************************************************7 * Communicates with the dongle by using dcmd codes.8 * For certain dcmd codes, the dongle interprets string data from the host.9 ******************************************************************************/10 11#include <linux/types.h>12#include <linux/netdevice.h>13#include <linux/etherdevice.h>14 15#include <brcmu_utils.h>16#include <brcmu_wifi.h>17 18#include "core.h"19#include "debug.h"20#include "proto.h"21#include "msgbuf.h"22#include "commonring.h"23#include "flowring.h"24#include "bus.h"25#include "tracepoint.h"26 27 28#define MSGBUF_IOCTL_RESP_TIMEOUT		msecs_to_jiffies(2000)29 30#define MSGBUF_TYPE_GEN_STATUS			0x131#define MSGBUF_TYPE_RING_STATUS			0x232#define MSGBUF_TYPE_FLOW_RING_CREATE		0x333#define MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT	0x434#define MSGBUF_TYPE_FLOW_RING_DELETE		0x535#define MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT	0x636#define MSGBUF_TYPE_FLOW_RING_FLUSH		0x737#define MSGBUF_TYPE_FLOW_RING_FLUSH_CMPLT	0x838#define MSGBUF_TYPE_IOCTLPTR_REQ		0x939#define MSGBUF_TYPE_IOCTLPTR_REQ_ACK		0xA40#define MSGBUF_TYPE_IOCTLRESP_BUF_POST		0xB41#define MSGBUF_TYPE_IOCTL_CMPLT			0xC42#define MSGBUF_TYPE_EVENT_BUF_POST		0xD43#define MSGBUF_TYPE_WL_EVENT			0xE44#define MSGBUF_TYPE_TX_POST			0xF45#define MSGBUF_TYPE_TX_STATUS			0x1046#define MSGBUF_TYPE_RXBUF_POST			0x1147#define MSGBUF_TYPE_RX_CMPLT			0x1248#define MSGBUF_TYPE_LPBK_DMAXFER		0x1349#define MSGBUF_TYPE_LPBK_DMAXFER_CMPLT		0x1450 51#define NR_TX_PKTIDS				204852#define NR_RX_PKTIDS				102453 54#define BRCMF_IOCTL_REQ_PKTID			0xFFFE55 56#define BRCMF_MSGBUF_MAX_PKT_SIZE		204857#define BRCMF_MSGBUF_MAX_CTL_PKT_SIZE           819258#define BRCMF_MSGBUF_RXBUFPOST_THRESHOLD	3259#define BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST	860#define BRCMF_MSGBUF_MAX_EVENTBUF_POST		861 62#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3	0x0163#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11	0x0264#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK	0x0765#define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT	566 67#define BRCMF_MSGBUF_TX_FLUSH_CNT1		3268#define BRCMF_MSGBUF_TX_FLUSH_CNT2		9669 70#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS	9671#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS	3272#define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS		4873 74#define BRCMF_MAX_TXSTATUS_WAIT_RETRIES		1075 76struct msgbuf_common_hdr {77	u8				msgtype;78	u8				ifidx;79	u8				flags;80	u8				rsvd0;81	__le32				request_id;82};83 84struct msgbuf_ioctl_req_hdr {85	struct msgbuf_common_hdr	msg;86	__le32				cmd;87	__le16				trans_id;88	__le16				input_buf_len;89	__le16				output_buf_len;90	__le16				rsvd0[3];91	struct msgbuf_buf_addr		req_buf_addr;92	__le32				rsvd1[2];93};94 95struct msgbuf_tx_msghdr {96	struct msgbuf_common_hdr	msg;97	u8				txhdr[ETH_HLEN];98	u8				flags;99	u8				seg_cnt;100	struct msgbuf_buf_addr		metadata_buf_addr;101	struct msgbuf_buf_addr		data_buf_addr;102	__le16				metadata_buf_len;103	__le16				data_len;104	__le32				rsvd0;105};106 107struct msgbuf_rx_bufpost {108	struct msgbuf_common_hdr	msg;109	__le16				metadata_buf_len;110	__le16				data_buf_len;111	__le32				rsvd0;112	struct msgbuf_buf_addr		metadata_buf_addr;113	struct msgbuf_buf_addr		data_buf_addr;114};115 116struct msgbuf_rx_ioctl_resp_or_event {117	struct msgbuf_common_hdr	msg;118	__le16				host_buf_len;119	__le16				rsvd0[3];120	struct msgbuf_buf_addr		host_buf_addr;121	__le32				rsvd1[4];122};123 124struct msgbuf_completion_hdr {125	__le16				status;126	__le16				flow_ring_id;127};128 129/* Data struct for the MSGBUF_TYPE_GEN_STATUS */130struct msgbuf_gen_status {131	struct msgbuf_common_hdr	msg;132	struct msgbuf_completion_hdr	compl_hdr;133	__le16				write_idx;134	__le32				rsvd0[3];135};136 137/* Data struct for the MSGBUF_TYPE_RING_STATUS */138struct msgbuf_ring_status {139	struct msgbuf_common_hdr	msg;140	struct msgbuf_completion_hdr	compl_hdr;141	__le16				write_idx;142	__le16				rsvd0[5];143};144 145struct msgbuf_rx_event {146	struct msgbuf_common_hdr	msg;147	struct msgbuf_completion_hdr	compl_hdr;148	__le16				event_data_len;149	__le16				seqnum;150	__le16				rsvd0[4];151};152 153struct msgbuf_ioctl_resp_hdr {154	struct msgbuf_common_hdr	msg;155	struct msgbuf_completion_hdr	compl_hdr;156	__le16				resp_len;157	__le16				trans_id;158	__le32				cmd;159	__le32				rsvd0;160};161 162struct msgbuf_tx_status {163	struct msgbuf_common_hdr	msg;164	struct msgbuf_completion_hdr	compl_hdr;165	__le16				metadata_len;166	__le16				tx_status;167};168 169struct msgbuf_rx_complete {170	struct msgbuf_common_hdr	msg;171	struct msgbuf_completion_hdr	compl_hdr;172	__le16				metadata_len;173	__le16				data_len;174	__le16				data_offset;175	__le16				flags;176	__le32				rx_status_0;177	__le32				rx_status_1;178	__le32				rsvd0;179};180 181struct msgbuf_tx_flowring_create_req {182	struct msgbuf_common_hdr	msg;183	u8				da[ETH_ALEN];184	u8				sa[ETH_ALEN];185	u8				tid;186	u8				if_flags;187	__le16				flow_ring_id;188	u8				tc;189	u8				priority;190	__le16				int_vector;191	__le16				max_items;192	__le16				len_item;193	struct msgbuf_buf_addr		flow_ring_addr;194};195 196struct msgbuf_tx_flowring_delete_req {197	struct msgbuf_common_hdr	msg;198	__le16				flow_ring_id;199	__le16				reason;200	__le32				rsvd0[7];201};202 203struct msgbuf_flowring_create_resp {204	struct msgbuf_common_hdr	msg;205	struct msgbuf_completion_hdr	compl_hdr;206	__le32				rsvd0[3];207};208 209struct msgbuf_flowring_delete_resp {210	struct msgbuf_common_hdr	msg;211	struct msgbuf_completion_hdr	compl_hdr;212	__le32				rsvd0[3];213};214 215struct msgbuf_flowring_flush_resp {216	struct msgbuf_common_hdr	msg;217	struct msgbuf_completion_hdr	compl_hdr;218	__le32				rsvd0[3];219};220 221struct brcmf_msgbuf_work_item {222	struct list_head queue;223	u32 flowid;224	int ifidx;225	u8 sa[ETH_ALEN];226	u8 da[ETH_ALEN];227};228 229struct brcmf_msgbuf {230	struct brcmf_pub *drvr;231 232	struct brcmf_commonring **commonrings;233	struct brcmf_commonring **flowrings;234	dma_addr_t *flowring_dma_handle;235 236	u16 max_flowrings;237	u16 max_submissionrings;238	u16 max_completionrings;239 240	u16 rx_dataoffset;241	u32 max_rxbufpost;242	u16 rx_metadata_offset;243	u32 rxbufpost;244 245	u32 max_ioctlrespbuf;246	u32 cur_ioctlrespbuf;247	u32 max_eventbuf;248	u32 cur_eventbuf;249 250	void *ioctbuf;251	dma_addr_t ioctbuf_handle;252	u32 ioctbuf_phys_hi;253	u32 ioctbuf_phys_lo;254	int ioctl_resp_status;255	u32 ioctl_resp_ret_len;256	u32 ioctl_resp_pktid;257 258	u16 data_seq_no;259	u16 ioctl_seq_no;260	u32 reqid;261	wait_queue_head_t ioctl_resp_wait;262	bool ctl_completed;263 264	struct brcmf_msgbuf_pktids *tx_pktids;265	struct brcmf_msgbuf_pktids *rx_pktids;266	struct brcmf_flowring *flow;267 268	struct workqueue_struct *txflow_wq;269	struct work_struct txflow_work;270	unsigned long *flow_map;271	unsigned long *txstatus_done_map;272 273	struct work_struct flowring_work;274	spinlock_t flowring_work_lock;275	struct list_head work_queue;276};277 278struct brcmf_msgbuf_pktid {279	atomic_t  allocated;280	u16 data_offset;281	struct sk_buff *skb;282	dma_addr_t physaddr;283};284 285struct brcmf_msgbuf_pktids {286	u32 array_size;287	u32 last_allocated_idx;288	enum dma_data_direction direction;289	struct brcmf_msgbuf_pktid *array;290};291 292static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf);293 294 295static struct brcmf_msgbuf_pktids *296brcmf_msgbuf_init_pktids(u32 nr_array_entries,297			 enum dma_data_direction direction)298{299	struct brcmf_msgbuf_pktid *array;300	struct brcmf_msgbuf_pktids *pktids;301 302	array = kcalloc(nr_array_entries, sizeof(*array), GFP_KERNEL);303	if (!array)304		return NULL;305 306	pktids = kzalloc(sizeof(*pktids), GFP_KERNEL);307	if (!pktids) {308		kfree(array);309		return NULL;310	}311	pktids->array = array;312	pktids->array_size = nr_array_entries;313 314	return pktids;315}316 317 318static int319brcmf_msgbuf_alloc_pktid(struct device *dev,320			 struct brcmf_msgbuf_pktids *pktids,321			 struct sk_buff *skb, u16 data_offset,322			 dma_addr_t *physaddr, u32 *idx)323{324	struct brcmf_msgbuf_pktid *array;325	u32 count;326 327	array = pktids->array;328 329	*physaddr = dma_map_single(dev, skb->data + data_offset,330				   skb->len - data_offset, pktids->direction);331 332	if (dma_mapping_error(dev, *physaddr)) {333		brcmf_err("dma_map_single failed !!\n");334		return -ENOMEM;335	}336 337	*idx = pktids->last_allocated_idx;338 339	count = 0;340	do {341		(*idx)++;342		if (*idx == pktids->array_size)343			*idx = 0;344		if (array[*idx].allocated.counter == 0)345			if (atomic_cmpxchg(&array[*idx].allocated, 0, 1) == 0)346				break;347		count++;348	} while (count < pktids->array_size);349 350	if (count == pktids->array_size) {351		dma_unmap_single(dev, *physaddr, skb->len - data_offset,352				 pktids->direction);353		return -ENOMEM;354	}355 356	array[*idx].data_offset = data_offset;357	array[*idx].physaddr = *physaddr;358	array[*idx].skb = skb;359 360	pktids->last_allocated_idx = *idx;361 362	return 0;363}364 365 366static struct sk_buff *367brcmf_msgbuf_get_pktid(struct device *dev, struct brcmf_msgbuf_pktids *pktids,368		       u32 idx)369{370	struct brcmf_msgbuf_pktid *pktid;371	struct sk_buff *skb;372 373	if (idx >= pktids->array_size) {374		brcmf_err("Invalid packet id %d (max %d)\n", idx,375			  pktids->array_size);376		return NULL;377	}378	if (pktids->array[idx].allocated.counter) {379		pktid = &pktids->array[idx];380		dma_unmap_single(dev, pktid->physaddr,381				 pktid->skb->len - pktid->data_offset,382				 pktids->direction);383		skb = pktid->skb;384		pktid->allocated.counter = 0;385		return skb;386	} else {387		brcmf_err("Invalid packet id %d (not in use)\n", idx);388	}389 390	return NULL;391}392 393 394static void395brcmf_msgbuf_release_array(struct device *dev,396			   struct brcmf_msgbuf_pktids *pktids)397{398	struct brcmf_msgbuf_pktid *array;399	struct brcmf_msgbuf_pktid *pktid;400	u32 count;401 402	array = pktids->array;403	count = 0;404	do {405		if (array[count].allocated.counter) {406			pktid = &array[count];407			dma_unmap_single(dev, pktid->physaddr,408					 pktid->skb->len - pktid->data_offset,409					 pktids->direction);410			brcmu_pkt_buf_free_skb(pktid->skb);411		}412		count++;413	} while (count < pktids->array_size);414 415	kfree(array);416	kfree(pktids);417}418 419 420static void brcmf_msgbuf_release_pktids(struct brcmf_msgbuf *msgbuf)421{422	if (msgbuf->rx_pktids)423		brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev,424					   msgbuf->rx_pktids);425	if (msgbuf->tx_pktids)426		brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev,427					   msgbuf->tx_pktids);428}429 430 431static int brcmf_msgbuf_tx_ioctl(struct brcmf_pub *drvr, int ifidx,432				 uint cmd, void *buf, uint len)433{434	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;435	struct brcmf_commonring *commonring;436	struct msgbuf_ioctl_req_hdr *request;437	u16 buf_len;438	void *ret_ptr;439	int err;440 441	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];442	brcmf_commonring_lock(commonring);443	ret_ptr = brcmf_commonring_reserve_for_write(commonring);444	if (!ret_ptr) {445		bphy_err(drvr, "Failed to reserve space in commonring\n");446		brcmf_commonring_unlock(commonring);447		return -ENOMEM;448	}449 450	msgbuf->reqid++;451 452	request = (struct msgbuf_ioctl_req_hdr *)ret_ptr;453	request->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;454	request->msg.ifidx = (u8)ifidx;455	request->msg.flags = 0;456	request->msg.request_id = cpu_to_le32(BRCMF_IOCTL_REQ_PKTID);457	request->cmd = cpu_to_le32(cmd);458	request->output_buf_len = cpu_to_le16(len);459	request->trans_id = cpu_to_le16(msgbuf->reqid);460 461	buf_len = min_t(u16, len, BRCMF_TX_IOCTL_MAX_MSG_SIZE);462	request->input_buf_len = cpu_to_le16(buf_len);463	request->req_buf_addr.high_addr = cpu_to_le32(msgbuf->ioctbuf_phys_hi);464	request->req_buf_addr.low_addr = cpu_to_le32(msgbuf->ioctbuf_phys_lo);465	if (buf)466		memcpy(msgbuf->ioctbuf, buf, buf_len);467	else468		memset(msgbuf->ioctbuf, 0, buf_len);469 470	err = brcmf_commonring_write_complete(commonring);471	brcmf_commonring_unlock(commonring);472 473	return err;474}475 476 477static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf)478{479	return wait_event_timeout(msgbuf->ioctl_resp_wait,480				  msgbuf->ctl_completed,481				  MSGBUF_IOCTL_RESP_TIMEOUT);482}483 484 485static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf)486{487	msgbuf->ctl_completed = true;488	wake_up(&msgbuf->ioctl_resp_wait);489}490 491 492static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,493				   uint cmd, void *buf, uint len, int *fwerr)494{495	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;496	struct sk_buff *skb = NULL;497	int timeout;498	int err;499 500	brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len);501	*fwerr = 0;502	msgbuf->ctl_completed = false;503	err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len);504	if (err)505		return err;506 507	timeout = brcmf_msgbuf_ioctl_resp_wait(msgbuf);508	if (!timeout) {509		bphy_err(drvr, "Timeout on response for query command\n");510		return -EIO;511	}512 513	skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,514				     msgbuf->rx_pktids,515				     msgbuf->ioctl_resp_pktid);516	if (msgbuf->ioctl_resp_ret_len != 0) {517		if (!skb)518			return -EBADF;519 520		memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ?521				       len : msgbuf->ioctl_resp_ret_len);522	}523	brcmu_pkt_buf_free_skb(skb);524 525	*fwerr = msgbuf->ioctl_resp_status;526	return 0;527}528 529 530static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx,531				 uint cmd, void *buf, uint len, int *fwerr)532{533	return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len, fwerr);534}535 536 537static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,538				struct sk_buff *skb, struct brcmf_if **ifp)539{540	return -ENODEV;541}542 543static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)544{545}546 547static void548brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)549{550	u32 dma_sz;551	void *dma_buf;552 553	brcmf_dbg(MSGBUF, "Removing flowring %d\n", flowid);554 555	dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE;556	dma_buf = msgbuf->flowrings[flowid]->buf_addr;557	dma_free_coherent(msgbuf->drvr->bus_if->dev, dma_sz, dma_buf,558			  msgbuf->flowring_dma_handle[flowid]);559 560	brcmf_flowring_delete(msgbuf->flow, flowid);561}562 563 564static struct brcmf_msgbuf_work_item *565brcmf_msgbuf_dequeue_work(struct brcmf_msgbuf *msgbuf)566{567	struct brcmf_msgbuf_work_item *work = NULL;568	ulong flags;569 570	spin_lock_irqsave(&msgbuf->flowring_work_lock, flags);571	if (!list_empty(&msgbuf->work_queue)) {572		work = list_first_entry(&msgbuf->work_queue,573					struct brcmf_msgbuf_work_item, queue);574		list_del(&work->queue);575	}576	spin_unlock_irqrestore(&msgbuf->flowring_work_lock, flags);577 578	return work;579}580 581 582static u32583brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf,584				    struct brcmf_msgbuf_work_item *work)585{586	struct brcmf_pub *drvr = msgbuf->drvr;587	struct msgbuf_tx_flowring_create_req *create;588	struct brcmf_commonring *commonring;589	void *ret_ptr;590	u32 flowid;591	void *dma_buf;592	u32 dma_sz;593	u64 address;594	int err;595 596	flowid = work->flowid;597	dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE;598	dma_buf = dma_alloc_coherent(msgbuf->drvr->bus_if->dev, dma_sz,599				     &msgbuf->flowring_dma_handle[flowid],600				     GFP_KERNEL);601	if (!dma_buf) {602		bphy_err(drvr, "dma_alloc_coherent failed\n");603		brcmf_flowring_delete(msgbuf->flow, flowid);604		return BRCMF_FLOWRING_INVALID_ID;605	}606 607	brcmf_commonring_config(msgbuf->flowrings[flowid],608				BRCMF_H2D_TXFLOWRING_MAX_ITEM,609				BRCMF_H2D_TXFLOWRING_ITEMSIZE, dma_buf);610 611	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];612	brcmf_commonring_lock(commonring);613	ret_ptr = brcmf_commonring_reserve_for_write(commonring);614	if (!ret_ptr) {615		bphy_err(drvr, "Failed to reserve space in commonring\n");616		brcmf_commonring_unlock(commonring);617		brcmf_msgbuf_remove_flowring(msgbuf, flowid);618		return BRCMF_FLOWRING_INVALID_ID;619	}620 621	create = (struct msgbuf_tx_flowring_create_req *)ret_ptr;622	create->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;623	create->msg.ifidx = work->ifidx;624	create->msg.request_id = 0;625	create->tid = brcmf_flowring_tid(msgbuf->flow, flowid);626	create->flow_ring_id = cpu_to_le16(flowid +627					   BRCMF_H2D_MSGRING_FLOWRING_IDSTART);628	memcpy(create->sa, work->sa, ETH_ALEN);629	memcpy(create->da, work->da, ETH_ALEN);630	address = (u64)msgbuf->flowring_dma_handle[flowid];631	create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32);632	create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff);633	create->max_items = cpu_to_le16(BRCMF_H2D_TXFLOWRING_MAX_ITEM);634	create->len_item = cpu_to_le16(BRCMF_H2D_TXFLOWRING_ITEMSIZE);635 636	brcmf_dbg(MSGBUF, "Send Flow Create Req flow ID %d for peer %pM prio %d ifindex %d\n",637		  flowid, work->da, create->tid, work->ifidx);638 639	err = brcmf_commonring_write_complete(commonring);640	brcmf_commonring_unlock(commonring);641	if (err) {642		bphy_err(drvr, "Failed to write commonring\n");643		brcmf_msgbuf_remove_flowring(msgbuf, flowid);644		return BRCMF_FLOWRING_INVALID_ID;645	}646 647	return flowid;648}649 650 651static void brcmf_msgbuf_flowring_worker(struct work_struct *work)652{653	struct brcmf_msgbuf *msgbuf;654	struct brcmf_msgbuf_work_item *create;655 656	msgbuf = container_of(work, struct brcmf_msgbuf, flowring_work);657 658	while ((create = brcmf_msgbuf_dequeue_work(msgbuf))) {659		brcmf_msgbuf_flowring_create_worker(msgbuf, create);660		kfree(create);661	}662}663 664 665static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,666					struct sk_buff *skb)667{668	struct brcmf_msgbuf_work_item *create;669	struct ethhdr *eh = (struct ethhdr *)(skb->data);670	u32 flowid;671	ulong flags;672 673	create = kzalloc(sizeof(*create), GFP_ATOMIC);674	if (create == NULL)675		return BRCMF_FLOWRING_INVALID_ID;676 677	flowid = brcmf_flowring_create(msgbuf->flow, eh->h_dest,678				       skb->priority, ifidx);679	if (flowid == BRCMF_FLOWRING_INVALID_ID) {680		kfree(create);681		return flowid;682	}683 684	create->flowid = flowid;685	create->ifidx = ifidx;686	memcpy(create->sa, eh->h_source, ETH_ALEN);687	memcpy(create->da, eh->h_dest, ETH_ALEN);688 689	spin_lock_irqsave(&msgbuf->flowring_work_lock, flags);690	list_add_tail(&create->queue, &msgbuf->work_queue);691	spin_unlock_irqrestore(&msgbuf->flowring_work_lock, flags);692	schedule_work(&msgbuf->flowring_work);693 694	return flowid;695}696 697 698static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)699{700	struct brcmf_flowring *flow = msgbuf->flow;701	struct brcmf_pub *drvr = msgbuf->drvr;702	struct brcmf_commonring *commonring;703	void *ret_ptr;704	u32 count;705	struct sk_buff *skb;706	dma_addr_t physaddr;707	u32 pktid;708	struct msgbuf_tx_msghdr *tx_msghdr;709	u64 address;710 711	commonring = msgbuf->flowrings[flowid];712	if (!brcmf_commonring_write_available(commonring))713		return;714 715	brcmf_commonring_lock(commonring);716 717	count = BRCMF_MSGBUF_TX_FLUSH_CNT2 - BRCMF_MSGBUF_TX_FLUSH_CNT1;718	while (brcmf_flowring_qlen(flow, flowid)) {719		skb = brcmf_flowring_dequeue(flow, flowid);720		if (skb == NULL) {721			bphy_err(drvr, "No SKB, but qlen %d\n",722				 brcmf_flowring_qlen(flow, flowid));723			break;724		}725		skb_orphan(skb);726		if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,727					     msgbuf->tx_pktids, skb, ETH_HLEN,728					     &physaddr, &pktid)) {729			brcmf_flowring_reinsert(flow, flowid, skb);730			bphy_err(drvr, "No PKTID available !!\n");731			break;732		}733		ret_ptr = brcmf_commonring_reserve_for_write(commonring);734		if (!ret_ptr) {735			brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,736					       msgbuf->tx_pktids, pktid);737			brcmf_flowring_reinsert(flow, flowid, skb);738			break;739		}740		count++;741 742		tx_msghdr = (struct msgbuf_tx_msghdr *)ret_ptr;743 744		tx_msghdr->msg.msgtype = MSGBUF_TYPE_TX_POST;745		tx_msghdr->msg.request_id = cpu_to_le32(pktid + 1);746		tx_msghdr->msg.ifidx = brcmf_flowring_ifidx_get(flow, flowid);747		tx_msghdr->flags = BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3;748		tx_msghdr->flags |= (skb->priority & 0x07) <<749				    BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT;750		tx_msghdr->seg_cnt = 1;751		memcpy(tx_msghdr->txhdr, skb->data, ETH_HLEN);752		tx_msghdr->data_len = cpu_to_le16(skb->len - ETH_HLEN);753		address = (u64)physaddr;754		tx_msghdr->data_buf_addr.high_addr = cpu_to_le32(address >> 32);755		tx_msghdr->data_buf_addr.low_addr =756			cpu_to_le32(address & 0xffffffff);757		tx_msghdr->metadata_buf_len = 0;758		tx_msghdr->metadata_buf_addr.high_addr = 0;759		tx_msghdr->metadata_buf_addr.low_addr = 0;760		atomic_inc(&commonring->outstanding_tx);761		if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) {762			brcmf_commonring_write_complete(commonring);763			count = 0;764		}765	}766	if (count)767		brcmf_commonring_write_complete(commonring);768	brcmf_commonring_unlock(commonring);769}770 771 772static void brcmf_msgbuf_txflow_worker(struct work_struct *worker)773{774	struct brcmf_msgbuf *msgbuf;775	u32 flowid;776 777	msgbuf = container_of(worker, struct brcmf_msgbuf, txflow_work);778	for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->max_flowrings) {779		clear_bit(flowid, msgbuf->flow_map);780		brcmf_msgbuf_txflow(msgbuf, flowid);781	}782}783 784 785static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,786					bool force)787{788	struct brcmf_commonring *commonring;789 790	set_bit(flowid, msgbuf->flow_map);791	commonring = msgbuf->flowrings[flowid];792	if ((force) || (atomic_read(&commonring->outstanding_tx) <793			BRCMF_MSGBUF_DELAY_TXWORKER_THRS))794		queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);795 796	return 0;797}798 799 800static int brcmf_msgbuf_tx_queue_data(struct brcmf_pub *drvr, int ifidx,801				      struct sk_buff *skb)802{803	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;804	struct brcmf_flowring *flow = msgbuf->flow;805	struct ethhdr *eh = (struct ethhdr *)(skb->data);806	u32 flowid;807	u32 queue_count;808	bool force;809 810	flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);811	if (flowid == BRCMF_FLOWRING_INVALID_ID) {812		flowid = brcmf_msgbuf_flowring_create(msgbuf, ifidx, skb);813		if (flowid == BRCMF_FLOWRING_INVALID_ID) {814			return -ENOMEM;815		} else {816			brcmf_flowring_enqueue(flow, flowid, skb);817			return 0;818		}819	}820	queue_count = brcmf_flowring_enqueue(flow, flowid, skb);821	force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);822	brcmf_msgbuf_schedule_txdata(msgbuf, flowid, force);823 824	return 0;825}826 827 828static void829brcmf_msgbuf_configure_addr_mode(struct brcmf_pub *drvr, int ifidx,830				 enum proto_addr_mode addr_mode)831{832	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;833 834	brcmf_flowring_configure_addr_mode(msgbuf->flow, ifidx, addr_mode);835}836 837 838static void839brcmf_msgbuf_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])840{841	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;842 843	brcmf_flowring_delete_peer(msgbuf->flow, ifidx, peer);844}845 846 847static void848brcmf_msgbuf_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])849{850	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;851 852	brcmf_flowring_add_tdls_peer(msgbuf->flow, ifidx, peer);853}854 855 856static void857brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf)858{859	struct msgbuf_ioctl_resp_hdr *ioctl_resp;860 861	ioctl_resp = (struct msgbuf_ioctl_resp_hdr *)buf;862 863	msgbuf->ioctl_resp_status =864			(s16)le16_to_cpu(ioctl_resp->compl_hdr.status);865	msgbuf->ioctl_resp_ret_len = le16_to_cpu(ioctl_resp->resp_len);866	msgbuf->ioctl_resp_pktid = le32_to_cpu(ioctl_resp->msg.request_id);867 868	brcmf_msgbuf_ioctl_resp_wake(msgbuf);869 870	if (msgbuf->cur_ioctlrespbuf)871		msgbuf->cur_ioctlrespbuf--;872	brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);873}874 875 876static void877brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)878{879	struct brcmf_commonring *commonring;880	struct msgbuf_tx_status *tx_status;881	u32 idx;882	struct sk_buff *skb;883	u16 flowid;884 885	tx_status = (struct msgbuf_tx_status *)buf;886	idx = le32_to_cpu(tx_status->msg.request_id) - 1;887	flowid = le16_to_cpu(tx_status->compl_hdr.flow_ring_id);888	flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;889	skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,890				     msgbuf->tx_pktids, idx);891	if (!skb)892		return;893 894	set_bit(flowid, msgbuf->txstatus_done_map);895	commonring = msgbuf->flowrings[flowid];896	atomic_dec(&commonring->outstanding_tx);897 898	brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),899			 skb, true);900}901 902 903static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count)904{905	struct brcmf_pub *drvr = msgbuf->drvr;906	struct brcmf_commonring *commonring;907	void *ret_ptr;908	struct sk_buff *skb;909	u16 alloced;910	u32 pktlen;911	dma_addr_t physaddr;912	struct msgbuf_rx_bufpost *rx_bufpost;913	u64 address;914	u32 pktid;915	u32 i;916 917	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT];918	ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring,919							      count,920							      &alloced);921	if (!ret_ptr) {922		brcmf_dbg(MSGBUF, "Failed to reserve space in commonring\n");923		return 0;924	}925 926	for (i = 0; i < alloced; i++) {927		rx_bufpost = (struct msgbuf_rx_bufpost *)ret_ptr;928		memset(rx_bufpost, 0, sizeof(*rx_bufpost));929 930		skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_PKT_SIZE);931 932		if (skb == NULL) {933			bphy_err(drvr, "Failed to alloc SKB\n");934			brcmf_commonring_write_cancel(commonring, alloced - i);935			break;936		}937 938		pktlen = skb->len;939		if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,940					     msgbuf->rx_pktids, skb, 0,941					     &physaddr, &pktid)) {942			dev_kfree_skb_any(skb);943			bphy_err(drvr, "No PKTID available !!\n");944			brcmf_commonring_write_cancel(commonring, alloced - i);945			break;946		}947 948		if (msgbuf->rx_metadata_offset) {949			address = (u64)physaddr;950			rx_bufpost->metadata_buf_len =951				cpu_to_le16(msgbuf->rx_metadata_offset);952			rx_bufpost->metadata_buf_addr.high_addr =953				cpu_to_le32(address >> 32);954			rx_bufpost->metadata_buf_addr.low_addr =955				cpu_to_le32(address & 0xffffffff);956 957			skb_pull(skb, msgbuf->rx_metadata_offset);958			pktlen = skb->len;959			physaddr += msgbuf->rx_metadata_offset;960		}961		rx_bufpost->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;962		rx_bufpost->msg.request_id = cpu_to_le32(pktid);963 964		address = (u64)physaddr;965		rx_bufpost->data_buf_len = cpu_to_le16((u16)pktlen);966		rx_bufpost->data_buf_addr.high_addr =967			cpu_to_le32(address >> 32);968		rx_bufpost->data_buf_addr.low_addr =969			cpu_to_le32(address & 0xffffffff);970 971		ret_ptr += brcmf_commonring_len_item(commonring);972	}973 974	if (i)975		brcmf_commonring_write_complete(commonring);976 977	return i;978}979 980 981static void982brcmf_msgbuf_rxbuf_data_fill(struct brcmf_msgbuf *msgbuf)983{984	u32 fillbufs;985	u32 retcount;986 987	fillbufs = msgbuf->max_rxbufpost - msgbuf->rxbufpost;988 989	while (fillbufs) {990		retcount = brcmf_msgbuf_rxbuf_data_post(msgbuf, fillbufs);991		if (!retcount)992			break;993		msgbuf->rxbufpost += retcount;994		fillbufs -= retcount;995	}996}997 998 999static void1000brcmf_msgbuf_update_rxbufpost_count(struct brcmf_msgbuf *msgbuf, u16 rxcnt)1001{1002	msgbuf->rxbufpost -= rxcnt;1003	if (msgbuf->rxbufpost <= (msgbuf->max_rxbufpost -1004				  BRCMF_MSGBUF_RXBUFPOST_THRESHOLD))1005		brcmf_msgbuf_rxbuf_data_fill(msgbuf);1006}1007 1008 1009static u321010brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf,1011			     u32 count)1012{1013	struct brcmf_pub *drvr = msgbuf->drvr;1014	struct brcmf_commonring *commonring;1015	void *ret_ptr;1016	struct sk_buff *skb;1017	u16 alloced;1018	u32 pktlen;1019	dma_addr_t physaddr;1020	struct msgbuf_rx_ioctl_resp_or_event *rx_bufpost;1021	u64 address;1022	u32 pktid;1023	u32 i;1024 1025	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];1026	brcmf_commonring_lock(commonring);1027	ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring,1028							      count,1029							      &alloced);1030	if (!ret_ptr) {1031		bphy_err(drvr, "Failed to reserve space in commonring\n");1032		brcmf_commonring_unlock(commonring);1033		return 0;1034	}1035 1036	for (i = 0; i < alloced; i++) {1037		rx_bufpost = (struct msgbuf_rx_ioctl_resp_or_event *)ret_ptr;1038		memset(rx_bufpost, 0, sizeof(*rx_bufpost));1039 1040		skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_CTL_PKT_SIZE);1041 1042		if (skb == NULL) {1043			bphy_err(drvr, "Failed to alloc SKB\n");1044			brcmf_commonring_write_cancel(commonring, alloced - i);1045			break;1046		}1047 1048		pktlen = skb->len;1049		if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,1050					     msgbuf->rx_pktids, skb, 0,1051					     &physaddr, &pktid)) {1052			dev_kfree_skb_any(skb);1053			bphy_err(drvr, "No PKTID available !!\n");1054			brcmf_commonring_write_cancel(commonring, alloced - i);1055			break;1056		}1057		if (event_buf)1058			rx_bufpost->msg.msgtype = MSGBUF_TYPE_EVENT_BUF_POST;1059		else1060			rx_bufpost->msg.msgtype =1061				MSGBUF_TYPE_IOCTLRESP_BUF_POST;1062		rx_bufpost->msg.request_id = cpu_to_le32(pktid);1063 1064		address = (u64)physaddr;1065		rx_bufpost->host_buf_len = cpu_to_le16((u16)pktlen);1066		rx_bufpost->host_buf_addr.high_addr =1067			cpu_to_le32(address >> 32);1068		rx_bufpost->host_buf_addr.low_addr =1069			cpu_to_le32(address & 0xffffffff);1070 1071		ret_ptr += brcmf_commonring_len_item(commonring);1072	}1073 1074	if (i)1075		brcmf_commonring_write_complete(commonring);1076 1077	brcmf_commonring_unlock(commonring);1078 1079	return i;1080}1081 1082 1083static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf)1084{1085	u32 count;1086 1087	count = msgbuf->max_ioctlrespbuf - msgbuf->cur_ioctlrespbuf;1088	count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, false, count);1089	msgbuf->cur_ioctlrespbuf += count;1090}1091 1092 1093static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf)1094{1095	u32 count;1096 1097	count = msgbuf->max_eventbuf - msgbuf->cur_eventbuf;1098	count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, true, count);1099	msgbuf->cur_eventbuf += count;1100}1101 1102 1103static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)1104{1105	struct brcmf_pub *drvr = msgbuf->drvr;1106	struct msgbuf_rx_event *event;1107	u32 idx;1108	u16 buflen;1109	struct sk_buff *skb;1110	struct brcmf_if *ifp;1111 1112	event = (struct msgbuf_rx_event *)buf;1113	idx = le32_to_cpu(event->msg.request_id);1114	buflen = le16_to_cpu(event->event_data_len);1115 1116	if (msgbuf->cur_eventbuf)1117		msgbuf->cur_eventbuf--;1118	brcmf_msgbuf_rxbuf_event_post(msgbuf);1119 1120	skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,1121				     msgbuf->rx_pktids, idx);1122	if (!skb)1123		return;1124 1125	if (msgbuf->rx_dataoffset)1126		skb_pull(skb, msgbuf->rx_dataoffset);1127 1128	skb_trim(skb, buflen);1129 1130	ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);1131	if (!ifp || !ifp->ndev) {1132		bphy_err(drvr, "Received pkt for invalid ifidx %d\n",1133			 event->msg.ifidx);1134		goto exit;1135	}1136 1137	skb->protocol = eth_type_trans(skb, ifp->ndev);1138 1139	brcmf_fweh_process_skb(ifp->drvr, skb, 0, GFP_KERNEL);1140 1141exit:1142	brcmu_pkt_buf_free_skb(skb);1143}1144 1145 1146static void1147brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)1148{1149	struct brcmf_pub *drvr = msgbuf->drvr;1150	struct msgbuf_rx_complete *rx_complete;1151	struct sk_buff *skb;1152	u16 data_offset;1153	u16 buflen;1154	u16 flags;1155	u32 idx;1156	struct brcmf_if *ifp;1157 1158	brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);1159 1160	rx_complete = (struct msgbuf_rx_complete *)buf;1161	data_offset = le16_to_cpu(rx_complete->data_offset);1162	buflen = le16_to_cpu(rx_complete->data_len);1163	idx = le32_to_cpu(rx_complete->msg.request_id);1164	flags = le16_to_cpu(rx_complete->flags);1165 1166	skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,1167				     msgbuf->rx_pktids, idx);1168	if (!skb)1169		return;1170 1171	if (data_offset)1172		skb_pull(skb, data_offset);1173	else if (msgbuf->rx_dataoffset)1174		skb_pull(skb, msgbuf->rx_dataoffset);1175 1176	skb_trim(skb, buflen);1177 1178	if ((flags & BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK) ==1179	    BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11) {1180		ifp = msgbuf->drvr->mon_if;1181 1182		if (!ifp) {1183			bphy_err(drvr, "Received unexpected monitor pkt\n");1184			brcmu_pkt_buf_free_skb(skb);1185			return;1186		}1187 1188		brcmf_netif_mon_rx(ifp, skb);1189		return;1190	}1191 1192	ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);1193	if (!ifp || !ifp->ndev) {1194		bphy_err(drvr, "Received pkt for invalid ifidx %d\n",1195			 rx_complete->msg.ifidx);1196		brcmu_pkt_buf_free_skb(skb);1197		return;1198	}1199 1200	skb->protocol = eth_type_trans(skb, ifp->ndev);1201	brcmf_netif_rx(ifp, skb);1202}1203 1204static void brcmf_msgbuf_process_gen_status(struct brcmf_msgbuf *msgbuf,1205					    void *buf)1206{1207	struct msgbuf_gen_status *gen_status = buf;1208	struct brcmf_pub *drvr = msgbuf->drvr;1209	int err;1210 1211	err = le16_to_cpu(gen_status->compl_hdr.status);1212	if (err)1213		bphy_err(drvr, "Firmware reported general error: %d\n", err);1214}1215 1216static void brcmf_msgbuf_process_ring_status(struct brcmf_msgbuf *msgbuf,1217					     void *buf)1218{1219	struct msgbuf_ring_status *ring_status = buf;1220	struct brcmf_pub *drvr = msgbuf->drvr;1221	int err;1222 1223	err = le16_to_cpu(ring_status->compl_hdr.status);1224	if (err) {1225		int ring = le16_to_cpu(ring_status->compl_hdr.flow_ring_id);1226 1227		bphy_err(drvr, "Firmware reported ring %d error: %d\n", ring,1228			 err);1229	}1230}1231 1232static void1233brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf,1234					       void *buf)1235{1236	struct brcmf_pub *drvr = msgbuf->drvr;1237	struct msgbuf_flowring_create_resp *flowring_create_resp;1238	u16 status;1239	u16 flowid;1240 1241	flowring_create_resp = (struct msgbuf_flowring_create_resp *)buf;1242 1243	flowid = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id);1244	flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;1245	status =  le16_to_cpu(flowring_create_resp->compl_hdr.status);1246 1247	if (status) {1248		bphy_err(drvr, "Flowring creation failed, code %d\n", status);1249		brcmf_msgbuf_remove_flowring(msgbuf, flowid);1250		return;1251	}1252	brcmf_dbg(MSGBUF, "Flowring %d Create response status %d\n", flowid,1253		  status);1254 1255	brcmf_flowring_open(msgbuf->flow, flowid);1256 1257	brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);1258}1259 1260 1261static void1262brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf,1263					       void *buf)1264{1265	struct brcmf_pub *drvr = msgbuf->drvr;1266	struct msgbuf_flowring_delete_resp *flowring_delete_resp;1267	u16 status;1268	u16 flowid;1269 1270	flowring_delete_resp = (struct msgbuf_flowring_delete_resp *)buf;1271 1272	flowid = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id);1273	flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;1274	status =  le16_to_cpu(flowring_delete_resp->compl_hdr.status);1275 1276	if (status) {1277		bphy_err(drvr, "Flowring deletion failed, code %d\n", status);1278		brcmf_flowring_delete(msgbuf->flow, flowid);1279		return;1280	}1281	brcmf_dbg(MSGBUF, "Flowring %d Delete response status %d\n", flowid,1282		  status);1283 1284	brcmf_msgbuf_remove_flowring(msgbuf, flowid);1285}1286 1287 1288static void brcmf_msgbuf_process_msgtype(struct brcmf_msgbuf *msgbuf, void *buf)1289{1290	struct brcmf_pub *drvr = msgbuf->drvr;1291	struct msgbuf_common_hdr *msg;1292 1293	msg = (struct msgbuf_common_hdr *)buf;1294	switch (msg->msgtype) {1295	case MSGBUF_TYPE_GEN_STATUS:1296		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_GEN_STATUS\n");1297		brcmf_msgbuf_process_gen_status(msgbuf, buf);1298		break;1299	case MSGBUF_TYPE_RING_STATUS:1300		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RING_STATUS\n");1301		brcmf_msgbuf_process_ring_status(msgbuf, buf);1302		break;1303	case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:1304		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT\n");1305		brcmf_msgbuf_process_flow_ring_create_response(msgbuf, buf);1306		break;1307	case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:1308		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT\n");1309		brcmf_msgbuf_process_flow_ring_delete_response(msgbuf, buf);1310		break;1311	case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:1312		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTLPTR_REQ_ACK\n");1313		break;1314	case MSGBUF_TYPE_IOCTL_CMPLT:1315		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTL_CMPLT\n");1316		brcmf_msgbuf_process_ioctl_complete(msgbuf, buf);1317		break;1318	case MSGBUF_TYPE_WL_EVENT:1319		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_WL_EVENT\n");1320		brcmf_msgbuf_process_event(msgbuf, buf);1321		break;1322	case MSGBUF_TYPE_TX_STATUS:1323		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_TX_STATUS\n");1324		brcmf_msgbuf_process_txstatus(msgbuf, buf);1325		break;1326	case MSGBUF_TYPE_RX_CMPLT:1327		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RX_CMPLT\n");1328		brcmf_msgbuf_process_rx_complete(msgbuf, buf);1329		break;1330	default:1331		bphy_err(drvr, "Unsupported msgtype %d\n", msg->msgtype);1332		break;1333	}1334}1335 1336 1337static void brcmf_msgbuf_process_rx(struct brcmf_msgbuf *msgbuf,1338				    struct brcmf_commonring *commonring)1339{1340	void *buf;1341	u16 count;1342	u16 processed;1343 1344again:1345	buf = brcmf_commonring_get_read_ptr(commonring, &count);1346	if (buf == NULL)1347		return;1348 1349	processed = 0;1350	while (count) {1351		brcmf_msgbuf_process_msgtype(msgbuf,1352					     buf + msgbuf->rx_dataoffset);1353		buf += brcmf_commonring_len_item(commonring);1354		processed++;1355		if (processed == BRCMF_MSGBUF_UPDATE_RX_PTR_THRS) {1356			brcmf_commonring_read_complete(commonring, processed);1357			processed = 0;1358		}1359		count--;1360	}1361	if (processed)1362		brcmf_commonring_read_complete(commonring, processed);1363 1364	if (commonring->r_ptr == 0)1365		goto again;1366}1367 1368 1369int brcmf_proto_msgbuf_rx_trigger(struct device *dev)1370{1371	struct brcmf_bus *bus_if = dev_get_drvdata(dev);1372	struct brcmf_pub *drvr = bus_if->drvr;1373	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1374	struct brcmf_commonring *commonring;1375	void *buf;1376	u32 flowid;1377	int qlen;1378 1379	buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];1380	brcmf_msgbuf_process_rx(msgbuf, buf);1381	buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];1382	brcmf_msgbuf_process_rx(msgbuf, buf);1383	buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];1384	brcmf_msgbuf_process_rx(msgbuf, buf);1385 1386	for_each_set_bit(flowid, msgbuf->txstatus_done_map,1387			 msgbuf->max_flowrings) {1388		clear_bit(flowid, msgbuf->txstatus_done_map);1389		commonring = msgbuf->flowrings[flowid];1390		qlen = brcmf_flowring_qlen(msgbuf->flow, flowid);1391		if ((qlen > BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) ||1392		    ((qlen) && (atomic_read(&commonring->outstanding_tx) <1393				BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS)))1394			brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);1395	}1396 1397	return 0;1398}1399 1400 1401void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)1402{1403	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1404	struct msgbuf_tx_flowring_delete_req *delete;1405	struct brcmf_commonring *commonring;1406	struct brcmf_commonring *commonring_del = msgbuf->flowrings[flowid];1407	struct brcmf_flowring *flow = msgbuf->flow;1408	void *ret_ptr;1409	u8 ifidx;1410	int err;1411	int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES;1412 1413	/* make sure it is not in txflow */1414	brcmf_commonring_lock(commonring_del);1415	flow->rings[flowid]->status = RING_CLOSING;1416	brcmf_commonring_unlock(commonring_del);1417 1418	/* wait for commonring txflow finished */1419	while (retry && atomic_read(&commonring_del->outstanding_tx)) {1420		usleep_range(5000, 10000);1421		retry--;1422	}1423	if (!retry) {1424		brcmf_err("timed out waiting for txstatus\n");1425		atomic_set(&commonring_del->outstanding_tx, 0);1426	}1427 1428	/* no need to submit if firmware can not be reached */1429	if (drvr->bus_if->state != BRCMF_BUS_UP) {1430		brcmf_dbg(MSGBUF, "bus down, flowring will be removed\n");1431		brcmf_msgbuf_remove_flowring(msgbuf, flowid);1432		return;1433	}1434 1435	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];1436	brcmf_commonring_lock(commonring);1437	ret_ptr = brcmf_commonring_reserve_for_write(commonring);1438	if (!ret_ptr) {1439		bphy_err(drvr, "FW unaware, flowring will be removed !!\n");1440		brcmf_commonring_unlock(commonring);1441		brcmf_msgbuf_remove_flowring(msgbuf, flowid);1442		return;1443	}1444 1445	delete = (struct msgbuf_tx_flowring_delete_req *)ret_ptr;1446 1447	ifidx = brcmf_flowring_ifidx_get(msgbuf->flow, flowid);1448 1449	delete->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;1450	delete->msg.ifidx = ifidx;1451	delete->msg.request_id = 0;1452 1453	delete->flow_ring_id = cpu_to_le16(flowid +1454					   BRCMF_H2D_MSGRING_FLOWRING_IDSTART);1455	delete->reason = 0;1456 1457	brcmf_dbg(MSGBUF, "Send Flow Delete Req flow ID %d, ifindex %d\n",1458		  flowid, ifidx);1459 1460	err = brcmf_commonring_write_complete(commonring);1461	brcmf_commonring_unlock(commonring);1462	if (err) {1463		bphy_err(drvr, "Failed to submit RING_DELETE, flowring will be removed\n");1464		brcmf_msgbuf_remove_flowring(msgbuf, flowid);1465	}1466}1467 1468#ifdef DEBUG1469static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)1470{1471	struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);1472	struct brcmf_pub *drvr = bus_if->drvr;1473	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1474	struct brcmf_commonring *commonring;1475	u16 i;1476	struct brcmf_flowring_ring *ring;1477	struct brcmf_flowring_hash *hash;1478 1479	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];1480	seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n",1481		   commonring->r_ptr, commonring->w_ptr, commonring->depth);1482	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT];1483	seq_printf(seq, "h2d_rx_submit:  rp %4u, wp %4u, depth %4u\n",1484		   commonring->r_ptr, commonring->w_ptr, commonring->depth);1485	commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];1486	seq_printf(seq, "d2h_ctl_cmplt:  rp %4u, wp %4u, depth %4u\n",1487		   commonring->r_ptr, commonring->w_ptr, commonring->depth);1488	commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];1489	seq_printf(seq, "d2h_tx_cmplt:   rp %4u, wp %4u, depth %4u\n",1490		   commonring->r_ptr, commonring->w_ptr, commonring->depth);1491	commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];1492	seq_printf(seq, "d2h_rx_cmplt:   rp %4u, wp %4u, depth %4u\n",1493		   commonring->r_ptr, commonring->w_ptr, commonring->depth);1494 1495	seq_printf(seq, "\nh2d_flowrings: depth %u\n",1496		   BRCMF_H2D_TXFLOWRING_MAX_ITEM);1497	seq_puts(seq, "Active flowrings:\n");1498	for (i = 0; i < msgbuf->flow->nrofrings; i++) {1499		if (!msgbuf->flow->rings[i])1500			continue;1501		ring = msgbuf->flow->rings[i];1502		if (ring->status != RING_OPEN)1503			continue;1504		commonring = msgbuf->flowrings[i];1505		hash = &msgbuf->flow->hash[ring->hash_id];1506		seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n"1507				"        ifidx %u, fifo %u, da %pM\n",1508				i, commonring->r_ptr, commonring->w_ptr,1509				skb_queue_len(&ring->skblist), ring->blocked,1510				hash->ifidx, hash->fifo, hash->mac);1511	}1512 1513	return 0;1514}1515#else1516static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)1517{1518	return 0;1519}1520#endif1521 1522static void brcmf_msgbuf_debugfs_create(struct brcmf_pub *drvr)1523{1524	brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read);1525}1526 1527int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)1528{1529	struct brcmf_bus_msgbuf *if_msgbuf;1530	struct brcmf_msgbuf *msgbuf;1531	u64 address;1532	u32 count;1533 1534	if_msgbuf = drvr->bus_if->msgbuf;1535 1536	if (if_msgbuf->max_flowrings >= BRCMF_FLOWRING_HASHSIZE) {1537		bphy_err(drvr, "driver not configured for this many flowrings %d\n",1538			 if_msgbuf->max_flowrings);1539		if_msgbuf->max_flowrings = BRCMF_FLOWRING_HASHSIZE - 1;1540	}1541 1542	msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL);1543	if (!msgbuf)1544		goto fail;1545 1546	msgbuf->txflow_wq = create_singlethread_workqueue("msgbuf_txflow");1547	if (msgbuf->txflow_wq == NULL) {1548		bphy_err(drvr, "workqueue creation failed\n");1549		goto fail;1550	}1551	INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker);1552	count = BITS_TO_LONGS(if_msgbuf->max_flowrings);1553	count = count * sizeof(unsigned long);1554	msgbuf->flow_map = kzalloc(count, GFP_KERNEL);1555	if (!msgbuf->flow_map)1556		goto fail;1557 1558	msgbuf->txstatus_done_map = kzalloc(count, GFP_KERNEL);1559	if (!msgbuf->txstatus_done_map)1560		goto fail;1561 1562	msgbuf->drvr = drvr;1563	msgbuf->ioctbuf = dma_alloc_coherent(drvr->bus_if->dev,1564					     BRCMF_TX_IOCTL_MAX_MSG_SIZE,1565					     &msgbuf->ioctbuf_handle,1566					     GFP_KERNEL);1567	if (!msgbuf->ioctbuf)1568		goto fail;1569	address = (u64)msgbuf->ioctbuf_handle;1570	msgbuf->ioctbuf_phys_hi = address >> 32;1571	msgbuf->ioctbuf_phys_lo = address & 0xffffffff;1572 1573	drvr->proto->hdrpull = brcmf_msgbuf_hdrpull;1574	drvr->proto->query_dcmd = brcmf_msgbuf_query_dcmd;1575	drvr->proto->set_dcmd = brcmf_msgbuf_set_dcmd;1576	drvr->proto->tx_queue_data = brcmf_msgbuf_tx_queue_data;1577	drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode;1578	drvr->proto->delete_peer = brcmf_msgbuf_delete_peer;1579	drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer;1580	drvr->proto->rxreorder = brcmf_msgbuf_rxreorder;1581	drvr->proto->debugfs_create = brcmf_msgbuf_debugfs_create;1582	drvr->proto->pd = msgbuf;1583 1584	init_waitqueue_head(&msgbuf->ioctl_resp_wait);1585 1586	msgbuf->commonrings =1587		(struct brcmf_commonring **)if_msgbuf->commonrings;1588	msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings;1589	msgbuf->max_flowrings = if_msgbuf->max_flowrings;1590	msgbuf->flowring_dma_handle =1591		kcalloc(msgbuf->max_flowrings,1592			sizeof(*msgbuf->flowring_dma_handle), GFP_KERNEL);1593	if (!msgbuf->flowring_dma_handle)1594		goto fail;1595 1596	msgbuf->rx_dataoffset = if_msgbuf->rx_dataoffset;1597	msgbuf->max_rxbufpost = if_msgbuf->max_rxbufpost;1598 1599	msgbuf->max_ioctlrespbuf = BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST;1600	msgbuf->max_eventbuf = BRCMF_MSGBUF_MAX_EVENTBUF_POST;1601 1602	msgbuf->tx_pktids = brcmf_msgbuf_init_pktids(NR_TX_PKTIDS,1603						     DMA_TO_DEVICE);1604	if (!msgbuf->tx_pktids)1605		goto fail;1606	msgbuf->rx_pktids = brcmf_msgbuf_init_pktids(NR_RX_PKTIDS,1607						     DMA_FROM_DEVICE);1608	if (!msgbuf->rx_pktids)1609		goto fail;1610 1611	msgbuf->flow = brcmf_flowring_attach(drvr->bus_if->dev,1612					     if_msgbuf->max_flowrings);1613	if (!msgbuf->flow)1614		goto fail;1615 1616 1617	brcmf_dbg(MSGBUF, "Feeding buffers, rx data %d, rx event %d, rx ioctl resp %d\n",1618		  msgbuf->max_rxbufpost, msgbuf->max_eventbuf,1619		  msgbuf->max_ioctlrespbuf);1620	count = 0;1621	do {1622		brcmf_msgbuf_rxbuf_data_fill(msgbuf);1623		if (msgbuf->max_rxbufpost != msgbuf->rxbufpost)1624			msleep(10);1625		else1626			break;1627		count++;1628	} while (count < 10);1629	brcmf_msgbuf_rxbuf_event_post(msgbuf);1630	brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);1631 1632	INIT_WORK(&msgbuf->flowring_work, brcmf_msgbuf_flowring_worker);1633	spin_lock_init(&msgbuf->flowring_work_lock);1634	INIT_LIST_HEAD(&msgbuf->work_queue);1635 1636	return 0;1637 1638fail:1639	if (msgbuf) {1640		kfree(msgbuf->flow_map);1641		kfree(msgbuf->txstatus_done_map);1642		brcmf_msgbuf_release_pktids(msgbuf);1643		kfree(msgbuf->flowring_dma_handle);1644		if (msgbuf->ioctbuf)1645			dma_free_coherent(drvr->bus_if->dev,1646					  BRCMF_TX_IOCTL_MAX_MSG_SIZE,1647					  msgbuf->ioctbuf,1648					  msgbuf->ioctbuf_handle);1649		if (msgbuf->txflow_wq)1650			destroy_workqueue(msgbuf->txflow_wq);1651		kfree(msgbuf);1652	}1653	return -ENOMEM;1654}1655 1656 1657void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr)1658{1659	struct brcmf_msgbuf *msgbuf;1660	struct brcmf_msgbuf_work_item *work;1661 1662	brcmf_dbg(TRACE, "Enter\n");1663	if (drvr->proto->pd) {1664		msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1665		cancel_work_sync(&msgbuf->flowring_work);1666		while (!list_empty(&msgbuf->work_queue)) {1667			work = list_first_entry(&msgbuf->work_queue,1668						struct brcmf_msgbuf_work_item,1669						queue);1670			list_del(&work->queue);1671			kfree(work);1672		}1673		kfree(msgbuf->flow_map);1674		kfree(msgbuf->txstatus_done_map);1675		if (msgbuf->txflow_wq)1676			destroy_workqueue(msgbuf->txflow_wq);1677 1678		brcmf_flowring_detach(msgbuf->flow);1679		dma_free_coherent(drvr->bus_if->dev,1680				  BRCMF_TX_IOCTL_MAX_MSG_SIZE,1681				  msgbuf->ioctbuf, msgbuf->ioctbuf_handle);1682		brcmf_msgbuf_release_pktids(msgbuf);1683		kfree(msgbuf->flowring_dma_handle);1684		kfree(msgbuf);1685		drvr->proto->pd = NULL;1686	}1687}1688