Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmfmac/msgbuf.c
178665 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2014 Broadcom Corporation3*/45/*******************************************************************************6* Communicates with the dongle by using dcmd codes.7* For certain dcmd codes, the dongle interprets string data from the host.8******************************************************************************/910#include <linux/types.h>11#include <linux/netdevice.h>12#include <linux/etherdevice.h>13#if defined(__FreeBSD__)14#include <linux/delay.h>15#ifdef DEBUG16#include <linux/seq_file.h>17#endif18#endif1920#include <brcmu_utils.h>21#include <brcmu_wifi.h>2223#include "core.h"24#include "debug.h"25#include "proto.h"26#include "msgbuf.h"27#include "commonring.h"28#include "flowring.h"29#include "bus.h"30#include "tracepoint.h"313233#define MSGBUF_IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)3435#define MSGBUF_TYPE_GEN_STATUS 0x136#define MSGBUF_TYPE_RING_STATUS 0x237#define MSGBUF_TYPE_FLOW_RING_CREATE 0x338#define MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT 0x439#define MSGBUF_TYPE_FLOW_RING_DELETE 0x540#define MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT 0x641#define MSGBUF_TYPE_FLOW_RING_FLUSH 0x742#define MSGBUF_TYPE_FLOW_RING_FLUSH_CMPLT 0x843#define MSGBUF_TYPE_IOCTLPTR_REQ 0x944#define MSGBUF_TYPE_IOCTLPTR_REQ_ACK 0xA45#define MSGBUF_TYPE_IOCTLRESP_BUF_POST 0xB46#define MSGBUF_TYPE_IOCTL_CMPLT 0xC47#define MSGBUF_TYPE_EVENT_BUF_POST 0xD48#define MSGBUF_TYPE_WL_EVENT 0xE49#define MSGBUF_TYPE_TX_POST 0xF50#define MSGBUF_TYPE_TX_STATUS 0x1051#define MSGBUF_TYPE_RXBUF_POST 0x1152#define MSGBUF_TYPE_RX_CMPLT 0x1253#define MSGBUF_TYPE_LPBK_DMAXFER 0x1354#define MSGBUF_TYPE_LPBK_DMAXFER_CMPLT 0x145556#define NR_TX_PKTIDS 204857#define NR_RX_PKTIDS 10245859#define BRCMF_IOCTL_REQ_PKTID 0xFFFE6061#define BRCMF_MSGBUF_MAX_PKT_SIZE 204862#define BRCMF_MSGBUF_MAX_CTL_PKT_SIZE 819263#define BRCMF_MSGBUF_RXBUFPOST_THRESHOLD 3264#define BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST 865#define BRCMF_MSGBUF_MAX_EVENTBUF_POST 86667#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3 0x0168#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11 0x0269#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK 0x0770#define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT 57172#define BRCMF_MSGBUF_TX_FLUSH_CNT1 3273#define BRCMF_MSGBUF_TX_FLUSH_CNT2 967475#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 9676#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 3277#define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS 487879#define BRCMF_MAX_TXSTATUS_WAIT_RETRIES 108081struct msgbuf_common_hdr {82u8 msgtype;83u8 ifidx;84u8 flags;85u8 rsvd0;86__le32 request_id;87};8889struct msgbuf_ioctl_req_hdr {90struct msgbuf_common_hdr msg;91__le32 cmd;92__le16 trans_id;93__le16 input_buf_len;94__le16 output_buf_len;95__le16 rsvd0[3];96struct msgbuf_buf_addr req_buf_addr;97__le32 rsvd1[2];98};99100struct msgbuf_tx_msghdr {101struct msgbuf_common_hdr msg;102u8 txhdr[ETH_HLEN];103u8 flags;104u8 seg_cnt;105struct msgbuf_buf_addr metadata_buf_addr;106struct msgbuf_buf_addr data_buf_addr;107__le16 metadata_buf_len;108__le16 data_len;109__le32 rsvd0;110};111112struct msgbuf_rx_bufpost {113struct msgbuf_common_hdr msg;114__le16 metadata_buf_len;115__le16 data_buf_len;116__le32 rsvd0;117struct msgbuf_buf_addr metadata_buf_addr;118struct msgbuf_buf_addr data_buf_addr;119};120121struct msgbuf_rx_ioctl_resp_or_event {122struct msgbuf_common_hdr msg;123__le16 host_buf_len;124__le16 rsvd0[3];125struct msgbuf_buf_addr host_buf_addr;126__le32 rsvd1[4];127};128129struct msgbuf_completion_hdr {130__le16 status;131__le16 flow_ring_id;132};133134/* Data struct for the MSGBUF_TYPE_GEN_STATUS */135struct msgbuf_gen_status {136struct msgbuf_common_hdr msg;137struct msgbuf_completion_hdr compl_hdr;138__le16 write_idx;139__le32 rsvd0[3];140};141142/* Data struct for the MSGBUF_TYPE_RING_STATUS */143struct msgbuf_ring_status {144struct msgbuf_common_hdr msg;145struct msgbuf_completion_hdr compl_hdr;146__le16 write_idx;147__le16 rsvd0[5];148};149150struct msgbuf_rx_event {151struct msgbuf_common_hdr msg;152struct msgbuf_completion_hdr compl_hdr;153__le16 event_data_len;154__le16 seqnum;155__le16 rsvd0[4];156};157158struct msgbuf_ioctl_resp_hdr {159struct msgbuf_common_hdr msg;160struct msgbuf_completion_hdr compl_hdr;161__le16 resp_len;162__le16 trans_id;163__le32 cmd;164__le32 rsvd0;165};166167struct msgbuf_tx_status {168struct msgbuf_common_hdr msg;169struct msgbuf_completion_hdr compl_hdr;170__le16 metadata_len;171__le16 tx_status;172};173174struct msgbuf_rx_complete {175struct msgbuf_common_hdr msg;176struct msgbuf_completion_hdr compl_hdr;177__le16 metadata_len;178__le16 data_len;179__le16 data_offset;180__le16 flags;181__le32 rx_status_0;182__le32 rx_status_1;183__le32 rsvd0;184};185186struct msgbuf_tx_flowring_create_req {187struct msgbuf_common_hdr msg;188u8 da[ETH_ALEN];189u8 sa[ETH_ALEN];190u8 tid;191u8 if_flags;192__le16 flow_ring_id;193u8 tc;194u8 priority;195__le16 int_vector;196__le16 max_items;197__le16 len_item;198struct msgbuf_buf_addr flow_ring_addr;199};200201struct msgbuf_tx_flowring_delete_req {202struct msgbuf_common_hdr msg;203__le16 flow_ring_id;204__le16 reason;205__le32 rsvd0[7];206};207208struct msgbuf_flowring_create_resp {209struct msgbuf_common_hdr msg;210struct msgbuf_completion_hdr compl_hdr;211__le32 rsvd0[3];212};213214struct msgbuf_flowring_delete_resp {215struct msgbuf_common_hdr msg;216struct msgbuf_completion_hdr compl_hdr;217__le32 rsvd0[3];218};219220struct msgbuf_flowring_flush_resp {221struct msgbuf_common_hdr msg;222struct msgbuf_completion_hdr compl_hdr;223__le32 rsvd0[3];224};225226struct brcmf_msgbuf_work_item {227struct list_head queue;228u32 flowid;229int ifidx;230u8 sa[ETH_ALEN];231u8 da[ETH_ALEN];232};233234struct brcmf_msgbuf {235struct brcmf_pub *drvr;236237struct brcmf_commonring **commonrings;238struct brcmf_commonring **flowrings;239dma_addr_t *flowring_dma_handle;240241u16 max_flowrings;242u16 max_submissionrings;243u16 max_completionrings;244245u16 rx_dataoffset;246u32 max_rxbufpost;247u16 rx_metadata_offset;248u32 rxbufpost;249250u32 max_ioctlrespbuf;251u32 cur_ioctlrespbuf;252u32 max_eventbuf;253u32 cur_eventbuf;254255void *ioctbuf;256dma_addr_t ioctbuf_handle;257u32 ioctbuf_phys_hi;258u32 ioctbuf_phys_lo;259int ioctl_resp_status;260u32 ioctl_resp_ret_len;261u32 ioctl_resp_pktid;262263u16 data_seq_no;264u16 ioctl_seq_no;265u32 reqid;266wait_queue_head_t ioctl_resp_wait;267bool ctl_completed;268269struct brcmf_msgbuf_pktids *tx_pktids;270struct brcmf_msgbuf_pktids *rx_pktids;271struct brcmf_flowring *flow;272273struct workqueue_struct *txflow_wq;274struct work_struct txflow_work;275unsigned long *flow_map;276unsigned long *txstatus_done_map;277278struct work_struct flowring_work;279spinlock_t flowring_work_lock;280struct list_head work_queue;281};282283struct brcmf_msgbuf_pktid {284atomic_t allocated;285u16 data_offset;286struct sk_buff *skb;287dma_addr_t physaddr;288};289290struct brcmf_msgbuf_pktids {291u32 array_size;292u32 last_allocated_idx;293enum dma_data_direction direction;294struct brcmf_msgbuf_pktid *array;295};296297static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf);298299300static struct brcmf_msgbuf_pktids *301brcmf_msgbuf_init_pktids(u32 nr_array_entries,302enum dma_data_direction direction)303{304struct brcmf_msgbuf_pktid *array;305struct brcmf_msgbuf_pktids *pktids;306307array = kcalloc(nr_array_entries, sizeof(*array), GFP_KERNEL);308if (!array)309return NULL;310311pktids = kzalloc(sizeof(*pktids), GFP_KERNEL);312if (!pktids) {313kfree(array);314return NULL;315}316pktids->array = array;317pktids->array_size = nr_array_entries;318319return pktids;320}321322323static int324brcmf_msgbuf_alloc_pktid(struct device *dev,325struct brcmf_msgbuf_pktids *pktids,326struct sk_buff *skb, u16 data_offset,327dma_addr_t *physaddr, u32 *idx)328{329struct brcmf_msgbuf_pktid *array;330u32 count;331332array = pktids->array;333334*physaddr = dma_map_single(dev, skb->data + data_offset,335skb->len - data_offset, pktids->direction);336337if (dma_mapping_error(dev, *physaddr)) {338brcmf_err("dma_map_single failed !!\n");339return -ENOMEM;340}341342*idx = pktids->last_allocated_idx;343344count = 0;345do {346(*idx)++;347if (*idx == pktids->array_size)348*idx = 0;349if (array[*idx].allocated.counter == 0)350if (atomic_cmpxchg(&array[*idx].allocated, 0, 1) == 0)351break;352count++;353} while (count < pktids->array_size);354355if (count == pktids->array_size) {356dma_unmap_single(dev, *physaddr, skb->len - data_offset,357pktids->direction);358return -ENOMEM;359}360361array[*idx].data_offset = data_offset;362array[*idx].physaddr = *physaddr;363array[*idx].skb = skb;364365pktids->last_allocated_idx = *idx;366367return 0;368}369370371static struct sk_buff *372brcmf_msgbuf_get_pktid(struct device *dev, struct brcmf_msgbuf_pktids *pktids,373u32 idx)374{375struct brcmf_msgbuf_pktid *pktid;376struct sk_buff *skb;377378if (idx >= pktids->array_size) {379brcmf_err("Invalid packet id %d (max %d)\n", idx,380pktids->array_size);381return NULL;382}383if (pktids->array[idx].allocated.counter) {384pktid = &pktids->array[idx];385dma_unmap_single(dev, pktid->physaddr,386pktid->skb->len - pktid->data_offset,387pktids->direction);388skb = pktid->skb;389pktid->allocated.counter = 0;390return skb;391} else {392brcmf_err("Invalid packet id %d (not in use)\n", idx);393}394395return NULL;396}397398399static void400brcmf_msgbuf_release_array(struct device *dev,401struct brcmf_msgbuf_pktids *pktids)402{403struct brcmf_msgbuf_pktid *array;404struct brcmf_msgbuf_pktid *pktid;405u32 count;406407array = pktids->array;408count = 0;409do {410if (array[count].allocated.counter) {411pktid = &array[count];412dma_unmap_single(dev, pktid->physaddr,413pktid->skb->len - pktid->data_offset,414pktids->direction);415brcmu_pkt_buf_free_skb(pktid->skb);416}417count++;418} while (count < pktids->array_size);419420kfree(array);421kfree(pktids);422}423424425static void brcmf_msgbuf_release_pktids(struct brcmf_msgbuf *msgbuf)426{427if (msgbuf->rx_pktids)428brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev,429msgbuf->rx_pktids);430if (msgbuf->tx_pktids)431brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev,432msgbuf->tx_pktids);433}434435436static int brcmf_msgbuf_tx_ioctl(struct brcmf_pub *drvr, int ifidx,437#if defined(__linux__)438uint cmd, void *buf, uint len)439#elif defined(__FreeBSD__)440uint cmd, const void *buf, uint len)441#endif442{443struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;444struct brcmf_commonring *commonring;445struct msgbuf_ioctl_req_hdr *request;446u16 buf_len;447void *ret_ptr;448int err;449450commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];451brcmf_commonring_lock(commonring);452ret_ptr = brcmf_commonring_reserve_for_write(commonring);453if (!ret_ptr) {454bphy_err(drvr, "Failed to reserve space in commonring\n");455brcmf_commonring_unlock(commonring);456return -ENOMEM;457}458459msgbuf->reqid++;460461request = (struct msgbuf_ioctl_req_hdr *)ret_ptr;462request->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;463request->msg.ifidx = (u8)ifidx;464request->msg.flags = 0;465request->msg.request_id = cpu_to_le32(BRCMF_IOCTL_REQ_PKTID);466request->cmd = cpu_to_le32(cmd);467request->output_buf_len = cpu_to_le16(len);468request->trans_id = cpu_to_le16(msgbuf->reqid);469470buf_len = min_t(u16, len, BRCMF_TX_IOCTL_MAX_MSG_SIZE);471request->input_buf_len = cpu_to_le16(buf_len);472request->req_buf_addr.high_addr = cpu_to_le32(msgbuf->ioctbuf_phys_hi);473request->req_buf_addr.low_addr = cpu_to_le32(msgbuf->ioctbuf_phys_lo);474if (buf)475memcpy(msgbuf->ioctbuf, buf, buf_len);476else477memset(msgbuf->ioctbuf, 0, buf_len);478479err = brcmf_commonring_write_complete(commonring);480brcmf_commonring_unlock(commonring);481482return err;483}484485486static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf)487{488return wait_event_timeout(msgbuf->ioctl_resp_wait,489msgbuf->ctl_completed,490MSGBUF_IOCTL_RESP_TIMEOUT);491}492493494static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf)495{496msgbuf->ctl_completed = true;497wake_up(&msgbuf->ioctl_resp_wait);498}499500501static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,502uint cmd, void *buf, uint len, int *fwerr)503{504struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;505struct sk_buff *skb = NULL;506int timeout;507int err;508509brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len);510*fwerr = 0;511msgbuf->ctl_completed = false;512err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len);513if (err)514return err;515516timeout = brcmf_msgbuf_ioctl_resp_wait(msgbuf);517if (!timeout) {518bphy_err(drvr, "Timeout on response for query command\n");519return -EIO;520}521522skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,523msgbuf->rx_pktids,524msgbuf->ioctl_resp_pktid);525if (msgbuf->ioctl_resp_ret_len != 0) {526if (!skb)527return -EBADF;528529memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ?530len : msgbuf->ioctl_resp_ret_len);531}532brcmu_pkt_buf_free_skb(skb);533534*fwerr = msgbuf->ioctl_resp_status;535return 0;536}537538539static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx,540uint cmd, void *buf, uint len, int *fwerr)541{542return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len, fwerr);543}544545546static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,547struct sk_buff *skb, struct brcmf_if **ifp)548{549return -ENODEV;550}551552static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)553{554}555556static void557brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)558{559u32 dma_sz;560void *dma_buf;561562brcmf_dbg(MSGBUF, "Removing flowring %d\n", flowid);563564dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE;565dma_buf = msgbuf->flowrings[flowid]->buf_addr;566dma_free_coherent(msgbuf->drvr->bus_if->dev, dma_sz, dma_buf,567msgbuf->flowring_dma_handle[flowid]);568569brcmf_flowring_delete(msgbuf->flow, flowid);570}571572573static struct brcmf_msgbuf_work_item *574brcmf_msgbuf_dequeue_work(struct brcmf_msgbuf *msgbuf)575{576struct brcmf_msgbuf_work_item *work = NULL;577ulong flags;578579spin_lock_irqsave(&msgbuf->flowring_work_lock, flags);580if (!list_empty(&msgbuf->work_queue)) {581work = list_first_entry(&msgbuf->work_queue,582struct brcmf_msgbuf_work_item, queue);583list_del(&work->queue);584}585spin_unlock_irqrestore(&msgbuf->flowring_work_lock, flags);586587return work;588}589590591static u32592brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf,593struct brcmf_msgbuf_work_item *work)594{595struct brcmf_pub *drvr = msgbuf->drvr;596struct msgbuf_tx_flowring_create_req *create;597struct brcmf_commonring *commonring;598void *ret_ptr;599u32 flowid;600void *dma_buf;601u32 dma_sz;602u64 address;603int err;604605flowid = work->flowid;606dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE;607dma_buf = dma_alloc_coherent(msgbuf->drvr->bus_if->dev, dma_sz,608&msgbuf->flowring_dma_handle[flowid],609GFP_KERNEL);610if (!dma_buf) {611bphy_err(drvr, "dma_alloc_coherent failed\n");612brcmf_flowring_delete(msgbuf->flow, flowid);613return BRCMF_FLOWRING_INVALID_ID;614}615616brcmf_commonring_config(msgbuf->flowrings[flowid],617BRCMF_H2D_TXFLOWRING_MAX_ITEM,618BRCMF_H2D_TXFLOWRING_ITEMSIZE, dma_buf);619620commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];621brcmf_commonring_lock(commonring);622ret_ptr = brcmf_commonring_reserve_for_write(commonring);623if (!ret_ptr) {624bphy_err(drvr, "Failed to reserve space in commonring\n");625brcmf_commonring_unlock(commonring);626brcmf_msgbuf_remove_flowring(msgbuf, flowid);627return BRCMF_FLOWRING_INVALID_ID;628}629630create = (struct msgbuf_tx_flowring_create_req *)ret_ptr;631create->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;632create->msg.ifidx = work->ifidx;633create->msg.request_id = 0;634create->tid = brcmf_flowring_tid(msgbuf->flow, flowid);635create->flow_ring_id = cpu_to_le16(flowid +636BRCMF_H2D_MSGRING_FLOWRING_IDSTART);637memcpy(create->sa, work->sa, ETH_ALEN);638memcpy(create->da, work->da, ETH_ALEN);639address = (u64)msgbuf->flowring_dma_handle[flowid];640create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32);641create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff);642create->max_items = cpu_to_le16(BRCMF_H2D_TXFLOWRING_MAX_ITEM);643create->len_item = cpu_to_le16(BRCMF_H2D_TXFLOWRING_ITEMSIZE);644645brcmf_dbg(MSGBUF, "Send Flow Create Req flow ID %d for peer %pM prio %d ifindex %d\n",646flowid, work->da, create->tid, work->ifidx);647648err = brcmf_commonring_write_complete(commonring);649brcmf_commonring_unlock(commonring);650if (err) {651bphy_err(drvr, "Failed to write commonring\n");652brcmf_msgbuf_remove_flowring(msgbuf, flowid);653return BRCMF_FLOWRING_INVALID_ID;654}655656return flowid;657}658659660static void brcmf_msgbuf_flowring_worker(struct work_struct *work)661{662struct brcmf_msgbuf *msgbuf;663struct brcmf_msgbuf_work_item *create;664665msgbuf = container_of(work, struct brcmf_msgbuf, flowring_work);666667while ((create = brcmf_msgbuf_dequeue_work(msgbuf))) {668brcmf_msgbuf_flowring_create_worker(msgbuf, create);669kfree(create);670}671}672673674static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,675struct sk_buff *skb)676{677struct brcmf_msgbuf_work_item *create;678struct ethhdr *eh = (struct ethhdr *)(skb->data);679u32 flowid;680ulong flags;681682create = kzalloc(sizeof(*create), GFP_ATOMIC);683if (create == NULL)684return BRCMF_FLOWRING_INVALID_ID;685686flowid = brcmf_flowring_create(msgbuf->flow, eh->h_dest,687skb->priority, ifidx);688if (flowid == BRCMF_FLOWRING_INVALID_ID) {689kfree(create);690return flowid;691}692693create->flowid = flowid;694create->ifidx = ifidx;695memcpy(create->sa, eh->h_source, ETH_ALEN);696memcpy(create->da, eh->h_dest, ETH_ALEN);697698spin_lock_irqsave(&msgbuf->flowring_work_lock, flags);699list_add_tail(&create->queue, &msgbuf->work_queue);700spin_unlock_irqrestore(&msgbuf->flowring_work_lock, flags);701schedule_work(&msgbuf->flowring_work);702703return flowid;704}705706707static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)708{709struct brcmf_flowring *flow = msgbuf->flow;710struct brcmf_pub *drvr = msgbuf->drvr;711struct brcmf_commonring *commonring;712void *ret_ptr;713u32 count;714struct sk_buff *skb;715dma_addr_t physaddr;716u32 pktid;717struct msgbuf_tx_msghdr *tx_msghdr;718u64 address;719720commonring = msgbuf->flowrings[flowid];721if (!brcmf_commonring_write_available(commonring))722return;723724brcmf_commonring_lock(commonring);725726count = BRCMF_MSGBUF_TX_FLUSH_CNT2 - BRCMF_MSGBUF_TX_FLUSH_CNT1;727while (brcmf_flowring_qlen(flow, flowid)) {728skb = brcmf_flowring_dequeue(flow, flowid);729if (skb == NULL) {730bphy_err(drvr, "No SKB, but qlen %d\n",731brcmf_flowring_qlen(flow, flowid));732break;733}734skb_orphan(skb);735if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,736msgbuf->tx_pktids, skb, ETH_HLEN,737&physaddr, &pktid)) {738brcmf_flowring_reinsert(flow, flowid, skb);739bphy_err(drvr, "No PKTID available !!\n");740break;741}742ret_ptr = brcmf_commonring_reserve_for_write(commonring);743if (!ret_ptr) {744brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,745msgbuf->tx_pktids, pktid);746brcmf_flowring_reinsert(flow, flowid, skb);747break;748}749count++;750751tx_msghdr = (struct msgbuf_tx_msghdr *)ret_ptr;752753tx_msghdr->msg.msgtype = MSGBUF_TYPE_TX_POST;754tx_msghdr->msg.request_id = cpu_to_le32(pktid + 1);755tx_msghdr->msg.ifidx = brcmf_flowring_ifidx_get(flow, flowid);756tx_msghdr->flags = BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3;757tx_msghdr->flags |= (skb->priority & 0x07) <<758BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT;759tx_msghdr->seg_cnt = 1;760memcpy(tx_msghdr->txhdr, skb->data, ETH_HLEN);761tx_msghdr->data_len = cpu_to_le16(skb->len - ETH_HLEN);762address = (u64)physaddr;763tx_msghdr->data_buf_addr.high_addr = cpu_to_le32(address >> 32);764tx_msghdr->data_buf_addr.low_addr =765cpu_to_le32(address & 0xffffffff);766tx_msghdr->metadata_buf_len = 0;767tx_msghdr->metadata_buf_addr.high_addr = 0;768tx_msghdr->metadata_buf_addr.low_addr = 0;769atomic_inc(&commonring->outstanding_tx);770if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) {771brcmf_commonring_write_complete(commonring);772count = 0;773}774}775if (count)776brcmf_commonring_write_complete(commonring);777brcmf_commonring_unlock(commonring);778}779780781static void brcmf_msgbuf_txflow_worker(struct work_struct *worker)782{783struct brcmf_msgbuf *msgbuf;784u32 flowid;785786msgbuf = container_of(worker, struct brcmf_msgbuf, txflow_work);787for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->max_flowrings) {788clear_bit(flowid, msgbuf->flow_map);789brcmf_msgbuf_txflow(msgbuf, flowid);790}791}792793794static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,795bool force)796{797struct brcmf_commonring *commonring;798799set_bit(flowid, msgbuf->flow_map);800commonring = msgbuf->flowrings[flowid];801if ((force) || (atomic_read(&commonring->outstanding_tx) <802BRCMF_MSGBUF_DELAY_TXWORKER_THRS))803queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);804805return 0;806}807808809static int brcmf_msgbuf_tx_queue_data(struct brcmf_pub *drvr, int ifidx,810struct sk_buff *skb)811{812struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;813struct brcmf_flowring *flow = msgbuf->flow;814struct ethhdr *eh = (struct ethhdr *)(skb->data);815u32 flowid;816u32 queue_count;817bool force;818819flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);820if (flowid == BRCMF_FLOWRING_INVALID_ID) {821flowid = brcmf_msgbuf_flowring_create(msgbuf, ifidx, skb);822if (flowid == BRCMF_FLOWRING_INVALID_ID) {823return -ENOMEM;824} else {825brcmf_flowring_enqueue(flow, flowid, skb);826return 0;827}828}829queue_count = brcmf_flowring_enqueue(flow, flowid, skb);830force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);831brcmf_msgbuf_schedule_txdata(msgbuf, flowid, force);832833return 0;834}835836837static void838brcmf_msgbuf_configure_addr_mode(struct brcmf_pub *drvr, int ifidx,839enum proto_addr_mode addr_mode)840{841struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;842843brcmf_flowring_configure_addr_mode(msgbuf->flow, ifidx, addr_mode);844}845846847static void848#if defined(__linux__)849brcmf_msgbuf_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])850#elif defined(__FreeBSD__)851brcmf_msgbuf_delete_peer(struct brcmf_pub *drvr, int ifidx, const u8 peer[ETH_ALEN])852#endif853{854struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;855856brcmf_flowring_delete_peer(msgbuf->flow, ifidx, peer);857}858859860static void861#if defined(__linux__)862brcmf_msgbuf_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])863#elif defined(__FreeBSD__)864brcmf_msgbuf_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, const u8 peer[ETH_ALEN])865#endif866{867struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;868869brcmf_flowring_add_tdls_peer(msgbuf->flow, ifidx, peer);870}871872873static void874brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf)875{876struct msgbuf_ioctl_resp_hdr *ioctl_resp;877878ioctl_resp = (struct msgbuf_ioctl_resp_hdr *)buf;879880msgbuf->ioctl_resp_status =881(s16)le16_to_cpu(ioctl_resp->compl_hdr.status);882msgbuf->ioctl_resp_ret_len = le16_to_cpu(ioctl_resp->resp_len);883msgbuf->ioctl_resp_pktid = le32_to_cpu(ioctl_resp->msg.request_id);884885brcmf_msgbuf_ioctl_resp_wake(msgbuf);886887if (msgbuf->cur_ioctlrespbuf)888msgbuf->cur_ioctlrespbuf--;889brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);890}891892893static void894brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)895{896struct brcmf_commonring *commonring;897struct msgbuf_tx_status *tx_status;898u32 idx;899struct sk_buff *skb;900u16 flowid;901902tx_status = (struct msgbuf_tx_status *)buf;903idx = le32_to_cpu(tx_status->msg.request_id) - 1;904flowid = le16_to_cpu(tx_status->compl_hdr.flow_ring_id);905flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;906skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,907msgbuf->tx_pktids, idx);908if (!skb)909return;910911set_bit(flowid, msgbuf->txstatus_done_map);912commonring = msgbuf->flowrings[flowid];913atomic_dec(&commonring->outstanding_tx);914915brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),916skb, true);917}918919920static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count)921{922struct brcmf_pub *drvr = msgbuf->drvr;923struct brcmf_commonring *commonring;924#if defined(__linux__)925void *ret_ptr;926#elif defined(__FreeBSD__)927u8 *ret_ptr;928#endif929struct sk_buff *skb;930u16 alloced;931u32 pktlen;932dma_addr_t physaddr;933struct msgbuf_rx_bufpost *rx_bufpost;934u64 address;935u32 pktid;936u32 i;937938commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT];939ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring,940count,941&alloced);942if (!ret_ptr) {943brcmf_dbg(MSGBUF, "Failed to reserve space in commonring\n");944return 0;945}946947for (i = 0; i < alloced; i++) {948rx_bufpost = (struct msgbuf_rx_bufpost *)ret_ptr;949memset(rx_bufpost, 0, sizeof(*rx_bufpost));950951skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_PKT_SIZE);952953if (skb == NULL) {954bphy_err(drvr, "Failed to alloc SKB\n");955brcmf_commonring_write_cancel(commonring, alloced - i);956break;957}958959pktlen = skb->len;960if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,961msgbuf->rx_pktids, skb, 0,962&physaddr, &pktid)) {963dev_kfree_skb_any(skb);964bphy_err(drvr, "No PKTID available !!\n");965brcmf_commonring_write_cancel(commonring, alloced - i);966break;967}968969if (msgbuf->rx_metadata_offset) {970address = (u64)physaddr;971rx_bufpost->metadata_buf_len =972cpu_to_le16(msgbuf->rx_metadata_offset);973rx_bufpost->metadata_buf_addr.high_addr =974cpu_to_le32(address >> 32);975rx_bufpost->metadata_buf_addr.low_addr =976cpu_to_le32(address & 0xffffffff);977978skb_pull(skb, msgbuf->rx_metadata_offset);979pktlen = skb->len;980physaddr += msgbuf->rx_metadata_offset;981}982rx_bufpost->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;983rx_bufpost->msg.request_id = cpu_to_le32(pktid);984985address = (u64)physaddr;986rx_bufpost->data_buf_len = cpu_to_le16((u16)pktlen);987rx_bufpost->data_buf_addr.high_addr =988cpu_to_le32(address >> 32);989rx_bufpost->data_buf_addr.low_addr =990cpu_to_le32(address & 0xffffffff);991992ret_ptr += brcmf_commonring_len_item(commonring);993}994995if (i)996brcmf_commonring_write_complete(commonring);997998return i;999}100010011002static void1003brcmf_msgbuf_rxbuf_data_fill(struct brcmf_msgbuf *msgbuf)1004{1005u32 fillbufs;1006u32 retcount;10071008fillbufs = msgbuf->max_rxbufpost - msgbuf->rxbufpost;10091010while (fillbufs) {1011retcount = brcmf_msgbuf_rxbuf_data_post(msgbuf, fillbufs);1012if (!retcount)1013break;1014msgbuf->rxbufpost += retcount;1015fillbufs -= retcount;1016}1017}101810191020static void1021brcmf_msgbuf_update_rxbufpost_count(struct brcmf_msgbuf *msgbuf, u16 rxcnt)1022{1023msgbuf->rxbufpost -= rxcnt;1024if (msgbuf->rxbufpost <= (msgbuf->max_rxbufpost -1025BRCMF_MSGBUF_RXBUFPOST_THRESHOLD))1026brcmf_msgbuf_rxbuf_data_fill(msgbuf);1027}102810291030static u321031brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf,1032u32 count)1033{1034struct brcmf_pub *drvr = msgbuf->drvr;1035struct brcmf_commonring *commonring;1036#if defined(__linux__)1037void *ret_ptr;1038#elif defined(__FreeBSD__)1039u8 *ret_ptr;1040#endif1041struct sk_buff *skb;1042u16 alloced;1043u32 pktlen;1044dma_addr_t physaddr;1045struct msgbuf_rx_ioctl_resp_or_event *rx_bufpost;1046u64 address;1047u32 pktid;1048u32 i;10491050commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];1051brcmf_commonring_lock(commonring);1052ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring,1053count,1054&alloced);1055if (!ret_ptr) {1056bphy_err(drvr, "Failed to reserve space in commonring\n");1057brcmf_commonring_unlock(commonring);1058return 0;1059}10601061for (i = 0; i < alloced; i++) {1062rx_bufpost = (struct msgbuf_rx_ioctl_resp_or_event *)ret_ptr;1063memset(rx_bufpost, 0, sizeof(*rx_bufpost));10641065skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_CTL_PKT_SIZE);10661067if (skb == NULL) {1068bphy_err(drvr, "Failed to alloc SKB\n");1069brcmf_commonring_write_cancel(commonring, alloced - i);1070break;1071}10721073pktlen = skb->len;1074if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,1075msgbuf->rx_pktids, skb, 0,1076&physaddr, &pktid)) {1077dev_kfree_skb_any(skb);1078bphy_err(drvr, "No PKTID available !!\n");1079brcmf_commonring_write_cancel(commonring, alloced - i);1080break;1081}1082if (event_buf)1083rx_bufpost->msg.msgtype = MSGBUF_TYPE_EVENT_BUF_POST;1084else1085rx_bufpost->msg.msgtype =1086MSGBUF_TYPE_IOCTLRESP_BUF_POST;1087rx_bufpost->msg.request_id = cpu_to_le32(pktid);10881089address = (u64)physaddr;1090rx_bufpost->host_buf_len = cpu_to_le16((u16)pktlen);1091rx_bufpost->host_buf_addr.high_addr =1092cpu_to_le32(address >> 32);1093rx_bufpost->host_buf_addr.low_addr =1094cpu_to_le32(address & 0xffffffff);10951096ret_ptr += brcmf_commonring_len_item(commonring);1097}10981099if (i)1100brcmf_commonring_write_complete(commonring);11011102brcmf_commonring_unlock(commonring);11031104return i;1105}110611071108static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf)1109{1110u32 count;11111112count = msgbuf->max_ioctlrespbuf - msgbuf->cur_ioctlrespbuf;1113count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, false, count);1114msgbuf->cur_ioctlrespbuf += count;1115}111611171118static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf)1119{1120u32 count;11211122count = msgbuf->max_eventbuf - msgbuf->cur_eventbuf;1123count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, true, count);1124msgbuf->cur_eventbuf += count;1125}112611271128static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)1129{1130struct brcmf_pub *drvr = msgbuf->drvr;1131struct msgbuf_rx_event *event;1132u32 idx;1133u16 buflen;1134struct sk_buff *skb;1135struct brcmf_if *ifp;11361137event = (struct msgbuf_rx_event *)buf;1138idx = le32_to_cpu(event->msg.request_id);1139buflen = le16_to_cpu(event->event_data_len);11401141if (msgbuf->cur_eventbuf)1142msgbuf->cur_eventbuf--;1143brcmf_msgbuf_rxbuf_event_post(msgbuf);11441145skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,1146msgbuf->rx_pktids, idx);1147if (!skb)1148return;11491150if (msgbuf->rx_dataoffset)1151skb_pull(skb, msgbuf->rx_dataoffset);11521153skb_trim(skb, buflen);11541155ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);1156if (!ifp || !ifp->ndev) {1157bphy_err(drvr, "Received pkt for invalid ifidx %d\n",1158event->msg.ifidx);1159goto exit;1160}11611162skb->protocol = eth_type_trans(skb, ifp->ndev);11631164brcmf_fweh_process_skb(ifp->drvr, skb, 0, GFP_KERNEL);11651166exit:1167brcmu_pkt_buf_free_skb(skb);1168}116911701171static void1172brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)1173{1174struct brcmf_pub *drvr = msgbuf->drvr;1175struct msgbuf_rx_complete *rx_complete;1176struct sk_buff *skb;1177u16 data_offset;1178u16 buflen;1179u16 flags;1180u32 idx;1181struct brcmf_if *ifp;11821183brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);11841185rx_complete = (struct msgbuf_rx_complete *)buf;1186data_offset = le16_to_cpu(rx_complete->data_offset);1187buflen = le16_to_cpu(rx_complete->data_len);1188idx = le32_to_cpu(rx_complete->msg.request_id);1189flags = le16_to_cpu(rx_complete->flags);11901191skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,1192msgbuf->rx_pktids, idx);1193if (!skb)1194return;11951196if (data_offset)1197skb_pull(skb, data_offset);1198else if (msgbuf->rx_dataoffset)1199skb_pull(skb, msgbuf->rx_dataoffset);12001201skb_trim(skb, buflen);12021203if ((flags & BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK) ==1204BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11) {1205ifp = msgbuf->drvr->mon_if;12061207if (!ifp) {1208bphy_err(drvr, "Received unexpected monitor pkt\n");1209brcmu_pkt_buf_free_skb(skb);1210return;1211}12121213brcmf_netif_mon_rx(ifp, skb);1214return;1215}12161217ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);1218if (!ifp || !ifp->ndev) {1219bphy_err(drvr, "Received pkt for invalid ifidx %d\n",1220rx_complete->msg.ifidx);1221brcmu_pkt_buf_free_skb(skb);1222return;1223}12241225skb->protocol = eth_type_trans(skb, ifp->ndev);1226brcmf_netif_rx(ifp, skb);1227}12281229static void brcmf_msgbuf_process_gen_status(struct brcmf_msgbuf *msgbuf,1230void *buf)1231{1232struct msgbuf_gen_status *gen_status = buf;1233struct brcmf_pub *drvr = msgbuf->drvr;1234int err;12351236err = le16_to_cpu(gen_status->compl_hdr.status);1237if (err)1238bphy_err(drvr, "Firmware reported general error: %d\n", err);1239}12401241static void brcmf_msgbuf_process_ring_status(struct brcmf_msgbuf *msgbuf,1242void *buf)1243{1244struct msgbuf_ring_status *ring_status = buf;1245struct brcmf_pub *drvr = msgbuf->drvr;1246int err;12471248err = le16_to_cpu(ring_status->compl_hdr.status);1249if (err) {1250int ring = le16_to_cpu(ring_status->compl_hdr.flow_ring_id);12511252bphy_err(drvr, "Firmware reported ring %d error: %d\n", ring,1253err);1254}1255}12561257static void1258brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf,1259void *buf)1260{1261struct brcmf_pub *drvr = msgbuf->drvr;1262struct msgbuf_flowring_create_resp *flowring_create_resp;1263u16 status;1264u16 flowid;12651266flowring_create_resp = (struct msgbuf_flowring_create_resp *)buf;12671268flowid = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id);1269flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;1270status = le16_to_cpu(flowring_create_resp->compl_hdr.status);12711272if (status) {1273bphy_err(drvr, "Flowring creation failed, code %d\n", status);1274brcmf_msgbuf_remove_flowring(msgbuf, flowid);1275return;1276}1277brcmf_dbg(MSGBUF, "Flowring %d Create response status %d\n", flowid,1278status);12791280brcmf_flowring_open(msgbuf->flow, flowid);12811282brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);1283}128412851286static void1287brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf,1288void *buf)1289{1290struct brcmf_pub *drvr = msgbuf->drvr;1291struct msgbuf_flowring_delete_resp *flowring_delete_resp;1292u16 status;1293u16 flowid;12941295flowring_delete_resp = (struct msgbuf_flowring_delete_resp *)buf;12961297flowid = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id);1298flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;1299status = le16_to_cpu(flowring_delete_resp->compl_hdr.status);13001301if (status) {1302bphy_err(drvr, "Flowring deletion failed, code %d\n", status);1303brcmf_flowring_delete(msgbuf->flow, flowid);1304return;1305}1306brcmf_dbg(MSGBUF, "Flowring %d Delete response status %d\n", flowid,1307status);13081309brcmf_msgbuf_remove_flowring(msgbuf, flowid);1310}131113121313static void brcmf_msgbuf_process_msgtype(struct brcmf_msgbuf *msgbuf, void *buf)1314{1315struct brcmf_pub *drvr = msgbuf->drvr;1316struct msgbuf_common_hdr *msg;13171318msg = (struct msgbuf_common_hdr *)buf;1319switch (msg->msgtype) {1320case MSGBUF_TYPE_GEN_STATUS:1321brcmf_dbg(MSGBUF, "MSGBUF_TYPE_GEN_STATUS\n");1322brcmf_msgbuf_process_gen_status(msgbuf, buf);1323break;1324case MSGBUF_TYPE_RING_STATUS:1325brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RING_STATUS\n");1326brcmf_msgbuf_process_ring_status(msgbuf, buf);1327break;1328case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:1329brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT\n");1330brcmf_msgbuf_process_flow_ring_create_response(msgbuf, buf);1331break;1332case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:1333brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT\n");1334brcmf_msgbuf_process_flow_ring_delete_response(msgbuf, buf);1335break;1336case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:1337brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTLPTR_REQ_ACK\n");1338break;1339case MSGBUF_TYPE_IOCTL_CMPLT:1340brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTL_CMPLT\n");1341brcmf_msgbuf_process_ioctl_complete(msgbuf, buf);1342break;1343case MSGBUF_TYPE_WL_EVENT:1344brcmf_dbg(MSGBUF, "MSGBUF_TYPE_WL_EVENT\n");1345brcmf_msgbuf_process_event(msgbuf, buf);1346break;1347case MSGBUF_TYPE_TX_STATUS:1348brcmf_dbg(MSGBUF, "MSGBUF_TYPE_TX_STATUS\n");1349brcmf_msgbuf_process_txstatus(msgbuf, buf);1350break;1351case MSGBUF_TYPE_RX_CMPLT:1352brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RX_CMPLT\n");1353brcmf_msgbuf_process_rx_complete(msgbuf, buf);1354break;1355default:1356bphy_err(drvr, "Unsupported msgtype %d\n", msg->msgtype);1357break;1358}1359}136013611362static void brcmf_msgbuf_process_rx(struct brcmf_msgbuf *msgbuf,1363struct brcmf_commonring *commonring)1364{1365#if defined(__linux__)1366void *buf;1367#elif defined(__FreeBSD__)1368u8 *buf;1369#endif1370u16 count;1371u16 processed;13721373again:1374buf = brcmf_commonring_get_read_ptr(commonring, &count);1375if (buf == NULL)1376return;13771378processed = 0;1379while (count) {1380brcmf_msgbuf_process_msgtype(msgbuf,1381buf + msgbuf->rx_dataoffset);1382buf += brcmf_commonring_len_item(commonring);1383processed++;1384if (processed == BRCMF_MSGBUF_UPDATE_RX_PTR_THRS) {1385brcmf_commonring_read_complete(commonring, processed);1386processed = 0;1387}1388count--;1389}1390if (processed)1391brcmf_commonring_read_complete(commonring, processed);13921393if (commonring->r_ptr == 0)1394goto again;1395}139613971398int brcmf_proto_msgbuf_rx_trigger(struct device *dev)1399{1400struct brcmf_bus *bus_if = dev_get_drvdata(dev);1401struct brcmf_pub *drvr = bus_if->drvr;1402struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1403struct brcmf_commonring *commonring;1404void *buf;1405u32 flowid;1406int qlen;14071408buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];1409brcmf_msgbuf_process_rx(msgbuf, buf);1410buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];1411brcmf_msgbuf_process_rx(msgbuf, buf);1412buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];1413brcmf_msgbuf_process_rx(msgbuf, buf);14141415for_each_set_bit(flowid, msgbuf->txstatus_done_map,1416msgbuf->max_flowrings) {1417clear_bit(flowid, msgbuf->txstatus_done_map);1418commonring = msgbuf->flowrings[flowid];1419qlen = brcmf_flowring_qlen(msgbuf->flow, flowid);1420if ((qlen > BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) ||1421((qlen) && (atomic_read(&commonring->outstanding_tx) <1422BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS)))1423brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);1424}14251426return 0;1427}142814291430void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)1431{1432struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1433struct msgbuf_tx_flowring_delete_req *delete;1434struct brcmf_commonring *commonring;1435struct brcmf_commonring *commonring_del = msgbuf->flowrings[flowid];1436struct brcmf_flowring *flow = msgbuf->flow;1437void *ret_ptr;1438u8 ifidx;1439int err;1440int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES;14411442/* make sure it is not in txflow */1443brcmf_commonring_lock(commonring_del);1444flow->rings[flowid]->status = RING_CLOSING;1445brcmf_commonring_unlock(commonring_del);14461447/* wait for commonring txflow finished */1448while (retry && atomic_read(&commonring_del->outstanding_tx)) {1449usleep_range(5000, 10000);1450retry--;1451}1452if (!retry) {1453brcmf_err("timed out waiting for txstatus\n");1454atomic_set(&commonring_del->outstanding_tx, 0);1455}14561457/* no need to submit if firmware can not be reached */1458if (drvr->bus_if->state != BRCMF_BUS_UP) {1459brcmf_dbg(MSGBUF, "bus down, flowring will be removed\n");1460brcmf_msgbuf_remove_flowring(msgbuf, flowid);1461return;1462}14631464commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];1465brcmf_commonring_lock(commonring);1466ret_ptr = brcmf_commonring_reserve_for_write(commonring);1467if (!ret_ptr) {1468bphy_err(drvr, "FW unaware, flowring will be removed !!\n");1469brcmf_commonring_unlock(commonring);1470brcmf_msgbuf_remove_flowring(msgbuf, flowid);1471return;1472}14731474delete = (struct msgbuf_tx_flowring_delete_req *)ret_ptr;14751476ifidx = brcmf_flowring_ifidx_get(msgbuf->flow, flowid);14771478delete->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;1479delete->msg.ifidx = ifidx;1480delete->msg.request_id = 0;14811482delete->flow_ring_id = cpu_to_le16(flowid +1483BRCMF_H2D_MSGRING_FLOWRING_IDSTART);1484delete->reason = 0;14851486brcmf_dbg(MSGBUF, "Send Flow Delete Req flow ID %d, ifindex %d\n",1487flowid, ifidx);14881489err = brcmf_commonring_write_complete(commonring);1490brcmf_commonring_unlock(commonring);1491if (err) {1492bphy_err(drvr, "Failed to submit RING_DELETE, flowring will be removed\n");1493brcmf_msgbuf_remove_flowring(msgbuf, flowid);1494}1495}14961497#ifdef DEBUG1498static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)1499{1500struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);1501struct brcmf_pub *drvr = bus_if->drvr;1502struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1503struct brcmf_commonring *commonring;1504u16 i;1505struct brcmf_flowring_ring *ring;1506struct brcmf_flowring_hash *hash;15071508commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];1509seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n",1510commonring->r_ptr, commonring->w_ptr, commonring->depth);1511commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT];1512seq_printf(seq, "h2d_rx_submit: rp %4u, wp %4u, depth %4u\n",1513commonring->r_ptr, commonring->w_ptr, commonring->depth);1514commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];1515seq_printf(seq, "d2h_ctl_cmplt: rp %4u, wp %4u, depth %4u\n",1516commonring->r_ptr, commonring->w_ptr, commonring->depth);1517commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];1518seq_printf(seq, "d2h_tx_cmplt: rp %4u, wp %4u, depth %4u\n",1519commonring->r_ptr, commonring->w_ptr, commonring->depth);1520commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];1521seq_printf(seq, "d2h_rx_cmplt: rp %4u, wp %4u, depth %4u\n",1522commonring->r_ptr, commonring->w_ptr, commonring->depth);15231524seq_printf(seq, "\nh2d_flowrings: depth %u\n",1525BRCMF_H2D_TXFLOWRING_MAX_ITEM);1526seq_puts(seq, "Active flowrings:\n");1527for (i = 0; i < msgbuf->flow->nrofrings; i++) {1528if (!msgbuf->flow->rings[i])1529continue;1530ring = msgbuf->flow->rings[i];1531if (ring->status != RING_OPEN)1532continue;1533commonring = msgbuf->flowrings[i];1534hash = &msgbuf->flow->hash[ring->hash_id];1535seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n"1536" ifidx %u, fifo %u, da %pM\n",1537i, commonring->r_ptr, commonring->w_ptr,1538skb_queue_len(&ring->skblist), ring->blocked,1539hash->ifidx, hash->fifo, hash->mac);1540}15411542return 0;1543}1544#else1545static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)1546{1547return 0;1548}1549#endif15501551static void brcmf_msgbuf_debugfs_create(struct brcmf_pub *drvr)1552{1553brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read);1554}15551556int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)1557{1558struct brcmf_bus_msgbuf *if_msgbuf;1559struct brcmf_msgbuf *msgbuf;1560u64 address;1561u32 count;15621563if_msgbuf = drvr->bus_if->msgbuf;15641565if (if_msgbuf->max_flowrings >= BRCMF_FLOWRING_HASHSIZE) {1566bphy_err(drvr, "driver not configured for this many flowrings %d\n",1567if_msgbuf->max_flowrings);1568if_msgbuf->max_flowrings = BRCMF_FLOWRING_HASHSIZE - 1;1569}15701571msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL);1572if (!msgbuf)1573goto fail;15741575msgbuf->txflow_wq = create_singlethread_workqueue("msgbuf_txflow");1576if (msgbuf->txflow_wq == NULL) {1577bphy_err(drvr, "workqueue creation failed\n");1578goto fail;1579}1580INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker);1581count = BITS_TO_LONGS(if_msgbuf->max_flowrings);1582count = count * sizeof(unsigned long);1583msgbuf->flow_map = kzalloc(count, GFP_KERNEL);1584if (!msgbuf->flow_map)1585goto fail;15861587msgbuf->txstatus_done_map = kzalloc(count, GFP_KERNEL);1588if (!msgbuf->txstatus_done_map)1589goto fail;15901591msgbuf->drvr = drvr;1592msgbuf->ioctbuf = dma_alloc_coherent(drvr->bus_if->dev,1593BRCMF_TX_IOCTL_MAX_MSG_SIZE,1594&msgbuf->ioctbuf_handle,1595GFP_KERNEL);1596if (!msgbuf->ioctbuf)1597goto fail;1598address = (u64)msgbuf->ioctbuf_handle;1599msgbuf->ioctbuf_phys_hi = address >> 32;1600msgbuf->ioctbuf_phys_lo = address & 0xffffffff;16011602drvr->proto->hdrpull = brcmf_msgbuf_hdrpull;1603drvr->proto->query_dcmd = brcmf_msgbuf_query_dcmd;1604drvr->proto->set_dcmd = brcmf_msgbuf_set_dcmd;1605drvr->proto->tx_queue_data = brcmf_msgbuf_tx_queue_data;1606drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode;1607drvr->proto->delete_peer = brcmf_msgbuf_delete_peer;1608drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer;1609drvr->proto->rxreorder = brcmf_msgbuf_rxreorder;1610drvr->proto->debugfs_create = brcmf_msgbuf_debugfs_create;1611drvr->proto->pd = msgbuf;16121613init_waitqueue_head(&msgbuf->ioctl_resp_wait);16141615msgbuf->commonrings =1616(struct brcmf_commonring **)if_msgbuf->commonrings;1617msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings;1618msgbuf->max_flowrings = if_msgbuf->max_flowrings;1619msgbuf->flowring_dma_handle =1620kcalloc(msgbuf->max_flowrings,1621sizeof(*msgbuf->flowring_dma_handle), GFP_KERNEL);1622if (!msgbuf->flowring_dma_handle)1623goto fail;16241625msgbuf->rx_dataoffset = if_msgbuf->rx_dataoffset;1626msgbuf->max_rxbufpost = if_msgbuf->max_rxbufpost;16271628msgbuf->max_ioctlrespbuf = BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST;1629msgbuf->max_eventbuf = BRCMF_MSGBUF_MAX_EVENTBUF_POST;16301631msgbuf->tx_pktids = brcmf_msgbuf_init_pktids(NR_TX_PKTIDS,1632DMA_TO_DEVICE);1633if (!msgbuf->tx_pktids)1634goto fail;1635msgbuf->rx_pktids = brcmf_msgbuf_init_pktids(NR_RX_PKTIDS,1636DMA_FROM_DEVICE);1637if (!msgbuf->rx_pktids)1638goto fail;16391640msgbuf->flow = brcmf_flowring_attach(drvr->bus_if->dev,1641if_msgbuf->max_flowrings);1642if (!msgbuf->flow)1643goto fail;164416451646brcmf_dbg(MSGBUF, "Feeding buffers, rx data %d, rx event %d, rx ioctl resp %d\n",1647msgbuf->max_rxbufpost, msgbuf->max_eventbuf,1648msgbuf->max_ioctlrespbuf);1649count = 0;1650do {1651brcmf_msgbuf_rxbuf_data_fill(msgbuf);1652if (msgbuf->max_rxbufpost != msgbuf->rxbufpost)1653#if defined(__linux__)1654msleep(10);1655#elif defined(__FreeBSD__)1656linux_msleep(10);1657#endif1658else1659break;1660count++;1661} while (count < 10);1662brcmf_msgbuf_rxbuf_event_post(msgbuf);1663brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);16641665INIT_WORK(&msgbuf->flowring_work, brcmf_msgbuf_flowring_worker);1666spin_lock_init(&msgbuf->flowring_work_lock);1667INIT_LIST_HEAD(&msgbuf->work_queue);16681669return 0;16701671fail:1672if (msgbuf) {1673kfree(msgbuf->flow_map);1674kfree(msgbuf->txstatus_done_map);1675brcmf_msgbuf_release_pktids(msgbuf);1676kfree(msgbuf->flowring_dma_handle);1677if (msgbuf->ioctbuf)1678dma_free_coherent(drvr->bus_if->dev,1679BRCMF_TX_IOCTL_MAX_MSG_SIZE,1680msgbuf->ioctbuf,1681msgbuf->ioctbuf_handle);1682if (msgbuf->txflow_wq)1683destroy_workqueue(msgbuf->txflow_wq);1684kfree(msgbuf);1685}1686return -ENOMEM;1687}168816891690void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr)1691{1692struct brcmf_msgbuf *msgbuf;1693struct brcmf_msgbuf_work_item *work;16941695brcmf_dbg(TRACE, "Enter\n");1696if (drvr->proto->pd) {1697msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;1698cancel_work_sync(&msgbuf->flowring_work);1699while (!list_empty(&msgbuf->work_queue)) {1700work = list_first_entry(&msgbuf->work_queue,1701struct brcmf_msgbuf_work_item,1702queue);1703list_del(&work->queue);1704kfree(work);1705}1706kfree(msgbuf->flow_map);1707kfree(msgbuf->txstatus_done_map);1708if (msgbuf->txflow_wq)1709destroy_workqueue(msgbuf->txflow_wq);17101711brcmf_flowring_detach(msgbuf->flow);1712dma_free_coherent(drvr->bus_if->dev,1713BRCMF_TX_IOCTL_MAX_MSG_SIZE,1714msgbuf->ioctbuf, msgbuf->ioctbuf_handle);1715brcmf_msgbuf_release_pktids(msgbuf);1716kfree(msgbuf->flowring_dma_handle);1717kfree(msgbuf);1718drvr->proto->pd = NULL;1719}1720}172117221723