cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c

/*
 * Copyright (c) 2010 Broadcom Corporation
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*******************************************************************************
 * Communicates with the dongle by using dcmd codes.
 * For certain dcmd codes, the dongle interprets string data from the host.
 ******************************************************************************/

#include <linux/types.h>
#include <linux/netdevice.h>

#include <brcmu_utils.h>
#include <brcmu_wifi.h>

#include "core.h"
#include "bus.h"
#include "fwsignal.h"
#include "debug.h"
#include "tracepoint.h"
#include "proto.h"
#include "bcdc.h"


struct brcmf_proto_bcdc_dcmd {
	
__le32 cmd;	/* dongle command value */
	
__le32 len;	/* lower 16: output buflen;
                         * upper 16: input buflen (excludes header) */
	
__le32 flags;	/* flag defns given below */
	
__le32 status;	/* status code returned from the device */
};

/* BCDC flag definitions */

#define BCDC_DCMD_ERROR		0x01		
/* 1=cmd failed */

#define BCDC_DCMD_SET		0x02		
/* 0=get, 1=set cmd */

#define BCDC_DCMD_IF_MASK	0xF000		
/* I/F index */

#define BCDC_DCMD_IF_SHIFT	12

#define BCDC_DCMD_ID_MASK	0xFFFF0000	
/* id an cmd pairing */

#define BCDC_DCMD_ID_SHIFT	16		
/* ID Mask shift bits */

#define BCDC_DCMD_ID(flags)	\
	(((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT)

/*
 * BCDC header - Broadcom specific extension of CDC.
 * Used on data packets to convey priority across USB.
 */

#define	BCDC_HEADER_LEN		4

#define BCDC_PROTO_VER		2	
/* Protocol version */

#define BCDC_FLAG_VER_MASK	0xf0	
/* Protocol version mask */

#define BCDC_FLAG_VER_SHIFT	4	
/* Protocol version shift */

#define BCDC_FLAG_SUM_GOOD	0x04	
/* Good RX checksums */

#define BCDC_FLAG_SUM_NEEDED	0x08	
/* Dongle needs to do TX checksums */

#define BCDC_PRIORITY_MASK	0x7

#define BCDC_FLAG2_IF_MASK	0x0f	
/* packet rx interface in APSTA */

#define BCDC_FLAG2_IF_SHIFT	0


#define BCDC_GET_IF_IDX(hdr) \
	((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT))

#define BCDC_SET_IF_IDX(hdr, idx) \
	((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \
        ((idx) << BCDC_FLAG2_IF_SHIFT)))

/**
 * struct brcmf_proto_bcdc_header - BCDC header format
 *
 * @flags: flags contain protocol and checksum info.
 * @priority: 802.1d priority and USB flow control info (bit 4:7).
 * @flags2: additional flags containing dongle interface index.
 * @data_offset: start of packet data. header is following by firmware signals.
 */

struct brcmf_proto_bcdc_header {
	
u8 flags;
	
u8 priority;
	
u8 flags2;
	
u8 data_offset;
};

/*
 * maximum length of firmware signal data between
 * the BCDC header and packet data in the tx path.
 */

#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES	12


#define RETRIES 2 
/* # of retries to retrieve matching dcmd response */

#define BUS_HEADER_LEN	(16+64)		
/* Must be atleast SDPCM_RESERVE
                                         * (amount of header tha might be added)
                                         * plus any space that might be needed
                                         * for bus alignment padding.
                                         */

struct brcmf_bcdc {
	
u16 reqid;
	
u8 bus_header[BUS_HEADER_LEN];
	
struct brcmf_proto_bcdc_dcmd msg;
	
unsigned char buf[BRCMF_DCMD_MAXLEN];
};



static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len, bool set) { struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; u32 flags; brcmf_dbg(BCDC, "Enter\n"); memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd)); msg->cmd = cpu_to_le32(cmd); msg->len = cpu_to_le32(len); flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT); if (set) flags |= BCDC_DCMD_SET; flags = (flags & ~BCDC_DCMD_IF_MASK) | (ifidx << BCDC_DCMD_IF_SHIFT); msg->flags = cpu_to_le32(flags); if (buf) memcpy(bcdc->buf, buf, len); len += sizeof(*msg); if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE) len = BRCMF_TX_IOCTL_MAX_MSG_SIZE; /* Send request */ return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); }

Contributors

PersonTokensPropCommitsCommitProp
Hante Meuleman13972.77%457.14%
Arend Van Spriel5126.70%228.57%
Franky Lin10.52%114.29%
Total191100.00%7100.00%


static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) { int ret; struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; brcmf_dbg(BCDC, "Enter\n"); len += sizeof(struct brcmf_proto_bcdc_dcmd); do { ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); if (ret < 0) break; } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel8583.33%240.00%
Hante Meuleman1615.69%240.00%
Franky Lin10.98%120.00%
Total102100.00%5100.00%


static int brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len) { struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; void *info; int ret = 0, retries = 0; u32 id, flags; brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false); if (ret < 0) { brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n", ret); goto done; } retry: /* wait for interrupt and get first fragment */ ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); if (ret < 0) goto done; flags = le32_to_cpu(msg->flags); id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; if ((id < bcdc->reqid) && (++retries < RETRIES)) goto retry; if (id != bcdc->reqid) { brcmf_err("%s: unexpected request id %d (expected %d)\n", brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id, bcdc->reqid); ret = -EINVAL; goto done; } /* Check info buffer */ info = (void *)&bcdc->buf[0]; /* Copy info buffer */ if (buf) { if (ret < (int)len) len = ret; memcpy(buf, info, len); } /* Check the ERROR flag */ if (flags & BCDC_DCMD_ERROR) ret = le32_to_cpu(msg->status); done: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel24787.59%337.50%
Hante Meuleman3512.41%562.50%
Total282100.00%8100.00%


static int brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len) { struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; int ret = 0; u32 flags, id; brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true); if (ret < 0) goto done; ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); if (ret < 0) goto done; flags = le32_to_cpu(msg->flags); id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; if (id != bcdc->reqid) { brcmf_err("%s: unexpected request id %d (expected %d)\n", brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id, bcdc->reqid); ret = -EINVAL; goto done; } /* Check the ERROR flag */ if (flags & BCDC_DCMD_ERROR) ret = le32_to_cpu(msg->status); done: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel16583.33%228.57%
Hante Meuleman3316.67%571.43%
Total198100.00%7100.00%


static void brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *pktbuf) { struct brcmf_proto_bcdc_header *h; brcmf_dbg(BCDC, "Enter\n"); /* Push BDC header used to convey priority for buses that don't */ skb_push(pktbuf, BCDC_HEADER_LEN); h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT); if (pktbuf->ip_summed == CHECKSUM_PARTIAL) h->flags |= BCDC_FLAG_SUM_NEEDED; h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK); h->flags2 = 0; h->data_offset = offset; BCDC_SET_IF_IDX(h, ifidx); trace_brcmf_bcdchdr(pktbuf->data); }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel10085.47%350.00%
Hante Meuleman1613.68%233.33%
Franky Lin10.85%116.67%
Total117100.00%6100.00%


static int brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, struct sk_buff *pktbuf, struct brcmf_if **ifp) { struct brcmf_proto_bcdc_header *h; struct brcmf_if *tmp_if; brcmf_dbg(BCDC, "Enter\n"); /* Pop BCDC header used to convey priority for buses that don't */ if (pktbuf->len <= BCDC_HEADER_LEN) { brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", pktbuf->len, BCDC_HEADER_LEN); return -EBADE; } trace_brcmf_bcdchdr(pktbuf->data); h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); if (!tmp_if) { brcmf_dbg(INFO, "no matching ifp found\n"); return -EBADE; } if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != BCDC_PROTO_VER) { brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", brcmf_ifname(tmp_if), h->flags); return -EBADE; } if (h->flags & BCDC_FLAG_SUM_GOOD) { brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", brcmf_ifname(tmp_if), h->flags); pktbuf->ip_summed = CHECKSUM_UNNECESSARY; } pktbuf->priority = h->priority & BCDC_PRIORITY_MASK; skb_pull(pktbuf, BCDC_HEADER_LEN); if (do_fws) brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf); else skb_pull(pktbuf, h->data_offset << 2); if (pktbuf->len == 0) return -ENODATA; if (ifp != NULL) *ifp = tmp_if; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel21582.69%753.85%
Hante Meuleman238.85%323.08%
Franky Lin114.23%17.69%
Per Forlin62.31%17.69%
Piotr Haber51.92%17.69%
Total260100.00%13100.00%


static int brcmf_proto_bcdc_tx_queue_data(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb) { struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx); if (!brcmf_fws_queue_skbs(drvr->fws)) return brcmf_proto_txdata(drvr, ifidx, 0, skb); return brcmf_fws_process_skb(ifp, skb); }

Contributors

PersonTokensPropCommitsCommitProp
Rafał Miłecki61100.00%1100.00%
Total61100.00%1100.00%


static int brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *pktbuf) { brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf); return brcmf_bus_txdata(drvr->bus_if, pktbuf); }

Contributors

PersonTokensPropCommitsCommitProp
Hante Meuleman43100.00%1100.00%
Total43100.00%1100.00%


static void brcmf_proto_bcdc_configure_addr_mode(struct brcmf_pub *drvr, int ifidx, enum proto_addr_mode addr_mode) { }

Contributors

PersonTokensPropCommitsCommitProp
Hante Meuleman17100.00%1100.00%
Total17100.00%1100.00%


static void brcmf_proto_bcdc_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) { }

Contributors

PersonTokensPropCommitsCommitProp
Hante Meuleman19100.00%1100.00%
Total19100.00%1100.00%


static void brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) { }

Contributors

PersonTokensPropCommitsCommitProp
Hante Meuleman19100.00%1100.00%
Total19100.00%1100.00%


static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb) { brcmf_fws_rxreorder(ifp, skb); }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel23100.00%1100.00%
Total23100.00%1100.00%


int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { struct brcmf_bcdc *bcdc; bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC); if (!bcdc) goto fail; /* ensure that the msg buf directly follows the cdc msg struct */ if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) { brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n"); goto fail; } drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull; drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; drvr->proto->tx_queue_data = brcmf_proto_bcdc_tx_queue_data; drvr->proto->txdata = brcmf_proto_bcdc_txdata; drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode; drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer; drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer; drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder; drvr->proto->pd = bcdc; drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + sizeof(struct brcmf_proto_bcdc_dcmd); return 0; fail: kfree(bcdc); return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel10355.38%436.36%
Hante Meuleman7339.25%545.45%
Rafał Miłecki84.30%19.09%
Franky Lin21.08%19.09%
Total186100.00%11100.00%


void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) { kfree(drvr->proto->pd); drvr->proto->pd = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel2074.07%150.00%
Hante Meuleman725.93%150.00%
Total27100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Arend Van Spriel118067.12%1237.50%
Hante Meuleman47827.19%1237.50%
Rafał Miłecki693.92%13.12%
Franky Lin201.14%515.62%
Per Forlin60.34%13.12%
Piotr Haber50.28%13.12%
Total1758100.00%32100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.