Commit 9a1bb602 authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville

brcmfmac: Adding msgbuf protocol.

This patch will add the msgbuf protocol. This protocol is used by
the soon to be added new bus interface PCIe. Msgbuf is a protocol
where most data is and remains located on the host (driver) side
and transferred by DMA from and to device. Msgbuf is the protocol
which takes care of the signalling of the buffers between host and
device which identifies this DMA-able data.
Reviewed-by: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarDaniel (Deognyoun) Kim <dekim@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8851cce0
...@@ -31,6 +31,9 @@ brcmfmac-objs += \ ...@@ -31,6 +31,9 @@ brcmfmac-objs += \
p2p.o \ p2p.o \
proto.o \ proto.o \
bcdc.o \ bcdc.o \
commonring.o \
flowring.o \
msgbuf.o \
dhd_common.o \ dhd_common.o \
dhd_linux.o \ dhd_linux.o \
firmware.o \ firmware.o \
......
/* Copyright (c) 2014 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.
*/
#include <linux/types.h>
#include <linux/netdevice.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "commonring.h"
/* dma flushing needs implementation for mips and arm platforms. Should
* be put in util. Note, this is not real flushing. It is virtual non
* cached memory. Only write buffers should have to be drained. Though
* this may be different depending on platform......
* SEE ALSO msgbuf.c
*/
#define brcmf_dma_flush(addr, len)
#define brcmf_dma_invalidate_cache(addr, len)
void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
int (*cr_ring_bell)(void *ctx),
int (*cr_update_rptr)(void *ctx),
int (*cr_update_wptr)(void *ctx),
int (*cr_write_rptr)(void *ctx),
int (*cr_write_wptr)(void *ctx), void *ctx)
{
commonring->cr_ring_bell = cr_ring_bell;
commonring->cr_update_rptr = cr_update_rptr;
commonring->cr_update_wptr = cr_update_wptr;
commonring->cr_write_rptr = cr_write_rptr;
commonring->cr_write_wptr = cr_write_wptr;
commonring->cr_ctx = ctx;
}
void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth,
u16 item_len, void *buf_addr)
{
commonring->depth = depth;
commonring->item_len = item_len;
commonring->buf_addr = buf_addr;
if (!commonring->inited) {
spin_lock_init(&commonring->lock);
commonring->inited = true;
}
commonring->r_ptr = 0;
if (commonring->cr_write_rptr)
commonring->cr_write_rptr(commonring->cr_ctx);
commonring->w_ptr = 0;
if (commonring->cr_write_wptr)
commonring->cr_write_wptr(commonring->cr_ctx);
commonring->f_ptr = 0;
}
void brcmf_commonring_lock(struct brcmf_commonring *commonring)
__acquires(&commonring->lock)
{
unsigned long flags;
spin_lock_irqsave(&commonring->lock, flags);
commonring->flags = flags;
}
void brcmf_commonring_unlock(struct brcmf_commonring *commonring)
__releases(&commonring->lock)
{
spin_unlock_irqrestore(&commonring->lock, commonring->flags);
}
bool brcmf_commonring_write_available(struct brcmf_commonring *commonring)
{
u16 available;
bool retry = true;
again:
if (commonring->r_ptr <= commonring->w_ptr)
available = commonring->depth - commonring->w_ptr +
commonring->r_ptr;
else
available = commonring->r_ptr - commonring->w_ptr;
if (available > 1) {
if (!commonring->was_full)
return true;
if (available > commonring->depth / 8) {
commonring->was_full = false;
return true;
}
if (retry) {
if (commonring->cr_update_rptr)
commonring->cr_update_rptr(commonring->cr_ctx);
retry = false;
goto again;
}
return false;
}
if (retry) {
if (commonring->cr_update_rptr)
commonring->cr_update_rptr(commonring->cr_ctx);
retry = false;
goto again;
}
commonring->was_full = true;
return false;
}
void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring)
{
void *ret_ptr;
u16 available;
bool retry = true;
again:
if (commonring->r_ptr <= commonring->w_ptr)
available = commonring->depth - commonring->w_ptr +
commonring->r_ptr;
else
available = commonring->r_ptr - commonring->w_ptr;
if (available > 1) {
ret_ptr = commonring->buf_addr +
(commonring->w_ptr * commonring->item_len);
commonring->w_ptr++;
if (commonring->w_ptr == commonring->depth)
commonring->w_ptr = 0;
return ret_ptr;
}
if (retry) {
if (commonring->cr_update_rptr)
commonring->cr_update_rptr(commonring->cr_ctx);
retry = false;
goto again;
}
commonring->was_full = true;
return NULL;
}
void *
brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring,
u16 n_items, u16 *alloced)
{
void *ret_ptr;
u16 available;
bool retry = true;
again:
if (commonring->r_ptr <= commonring->w_ptr)
available = commonring->depth - commonring->w_ptr +
commonring->r_ptr;
else
available = commonring->r_ptr - commonring->w_ptr;
if (available > 1) {
ret_ptr = commonring->buf_addr +
(commonring->w_ptr * commonring->item_len);
*alloced = min_t(u16, n_items, available - 1);
if (*alloced + commonring->w_ptr > commonring->depth)
*alloced = commonring->depth - commonring->w_ptr;
commonring->w_ptr += *alloced;
if (commonring->w_ptr == commonring->depth)
commonring->w_ptr = 0;
return ret_ptr;
}
if (retry) {
if (commonring->cr_update_rptr)
commonring->cr_update_rptr(commonring->cr_ctx);
retry = false;
goto again;
}
commonring->was_full = true;
return NULL;
}
int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)
{
void *address;
address = commonring->buf_addr;
address += (commonring->f_ptr * commonring->item_len);
if (commonring->f_ptr > commonring->w_ptr) {
brcmf_dma_flush(address,
(commonring->depth - commonring->f_ptr) *
commonring->item_len);
address = commonring->buf_addr;
commonring->f_ptr = 0;
}
brcmf_dma_flush(address, (commonring->w_ptr - commonring->f_ptr) *
commonring->item_len);
commonring->f_ptr = commonring->w_ptr;
if (commonring->cr_write_wptr)
commonring->cr_write_wptr(commonring->cr_ctx);
if (commonring->cr_ring_bell)
return commonring->cr_ring_bell(commonring->cr_ctx);
return -EIO;
}
void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
u16 n_items)
{
if (commonring->w_ptr == 0)
commonring->w_ptr = commonring->depth - n_items;
else
commonring->w_ptr -= n_items;
}
void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
u16 *n_items)
{
void *ret_addr;
if (commonring->cr_update_wptr)
commonring->cr_update_wptr(commonring->cr_ctx);
*n_items = (commonring->w_ptr >= commonring->r_ptr) ?
(commonring->w_ptr - commonring->r_ptr) :
(commonring->depth - commonring->r_ptr);
if (*n_items == 0)
return NULL;
ret_addr = commonring->buf_addr +
(commonring->r_ptr * commonring->item_len);
commonring->r_ptr += *n_items;
if (commonring->r_ptr == commonring->depth)
commonring->r_ptr = 0;
brcmf_dma_invalidate_cache(ret_addr, *n_ items * commonring->item_len);
return ret_addr;
}
int brcmf_commonring_read_complete(struct brcmf_commonring *commonring)
{
if (commonring->cr_write_rptr)
return commonring->cr_write_rptr(commonring->cr_ctx);
return -EIO;
}
/* Copyright (c) 2014 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.
*/
#ifndef BRCMFMAC_COMMONRING_H
#define BRCMFMAC_COMMONRING_H
struct brcmf_commonring {
u16 r_ptr;
u16 w_ptr;
u16 f_ptr;
u16 depth;
u16 item_len;
void *buf_addr;
int (*cr_ring_bell)(void *ctx);
int (*cr_update_rptr)(void *ctx);
int (*cr_update_wptr)(void *ctx);
int (*cr_write_rptr)(void *ctx);
int (*cr_write_wptr)(void *ctx);
void *cr_ctx;
spinlock_t lock;
unsigned long flags;
bool inited;
bool was_full;
};
void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
int (*cr_ring_bell)(void *ctx),
int (*cr_update_rptr)(void *ctx),
int (*cr_update_wptr)(void *ctx),
int (*cr_write_rptr)(void *ctx),
int (*cr_write_wptr)(void *ctx), void *ctx);
void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth,
u16 item_len, void *buf_addr);
void brcmf_commonring_lock(struct brcmf_commonring *commonring);
void brcmf_commonring_unlock(struct brcmf_commonring *commonring);
bool brcmf_commonring_write_available(struct brcmf_commonring *commonring);
void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring);
void *
brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring,
u16 n_items, u16 *alloced);
int brcmf_commonring_write_complete(struct brcmf_commonring *commonring);
void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
u16 n_items);
void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
u16 *n_items);
int brcmf_commonring_read_complete(struct brcmf_commonring *commonring);
#define brcmf_commonring_n_items(commonring) (commonring->depth)
#define brcmf_commonring_len_item(commonring) (commonring->item_len)
#endif /* BRCMFMAC_COMMONRING_H */
...@@ -19,6 +19,18 @@ ...@@ -19,6 +19,18 @@
#include "dhd_dbg.h" #include "dhd_dbg.h"
/* IDs of the 6 default common rings of msgbuf protocol */
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0
#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT 1
#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE 2
#define BRCMF_D2H_MSGRING_TX_COMPLETE 3
#define BRCMF_D2H_MSGRING_RX_COMPLETE 4
#define BRCMF_NROF_H2D_COMMON_MSGRINGS 2
#define BRCMF_NROF_D2H_COMMON_MSGRINGS 3
#define BRCMF_NROF_COMMON_MSGRINGS (BRCMF_NROF_H2D_COMMON_MSGRINGS + \
BRCMF_NROF_D2H_COMMON_MSGRINGS)
/* The level of bus communication with the dongle */ /* The level of bus communication with the dongle */
enum brcmf_bus_state { enum brcmf_bus_state {
BRCMF_BUS_UNKNOWN, /* Not determined yet */ BRCMF_BUS_UNKNOWN, /* Not determined yet */
...@@ -70,6 +82,25 @@ struct brcmf_bus_ops { ...@@ -70,6 +82,25 @@ struct brcmf_bus_ops {
struct pktq * (*gettxq)(struct device *dev); struct pktq * (*gettxq)(struct device *dev);
}; };
/**
* struct brcmf_bus_msgbuf - bus ringbuf if in case of msgbuf.
*
* @commonrings: commonrings which are always there.
* @flowrings: commonrings which are dynamically created and destroyed for data.
* @rx_dataoffset: if set then all rx data has this this offset.
* @max_rxbufpost: maximum number of buffers to post for rx.
* @nrof_flowrings: number of flowrings.
*/
struct brcmf_bus_msgbuf {
struct brcmf_commonring *commonrings[BRCMF_NROF_COMMON_MSGRINGS];
struct brcmf_commonring **flowrings;
u32 rx_dataoffset;
u32 max_rxbufpost;
u32 nrof_flowrings;
};
/** /**
* struct brcmf_bus - interface structure between common and bus layer * struct brcmf_bus - interface structure between common and bus layer
* *
...@@ -101,6 +132,7 @@ struct brcmf_bus { ...@@ -101,6 +132,7 @@ struct brcmf_bus {
bool always_use_fws_queue; bool always_use_fws_queue;
struct brcmf_bus_ops *ops; struct brcmf_bus_ops *ops;
struct brcmf_bus_msgbuf *msgbuf;
}; };
/* /*
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#define BRCMF_CONN_VAL 0x00008000 #define BRCMF_CONN_VAL 0x00008000
#define BRCMF_BCDC_VAL 0x00010000 #define BRCMF_BCDC_VAL 0x00010000
#define BRCMF_SDIO_VAL 0x00020000 #define BRCMF_SDIO_VAL 0x00020000
#define BRCMF_MSGBUF_VAL 0x00040000
/* set default print format */ /* set default print format */
#undef pr_fmt #undef pr_fmt
......
/* Copyright (c) 2014 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.
*/
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <brcmu_utils.h>
#include "dhd.h"
#include "dhd_dbg.h"
#include "dhd_bus.h"
#include "proto.h"
#include "flowring.h"
#include "msgbuf.h"
#define BRCMF_FLOWRING_HIGH 1024
#define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
#define BRCMF_FLOWRING_INVALID_IFIDX 0xff
#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16)
#define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
static const u8 ALLZEROMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static const u8 brcmf_flowring_prio2fifo[] = {
1,
0,
0,
1,
2,
2,
3,
3
};
u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
u8 prio, u8 ifidx)
{
struct brcmf_flowring_hash *hash;
u8 hash_idx;
u32 i;
bool found;
bool sta;
u8 fifo;
u8 *mac;
fifo = brcmf_flowring_prio2fifo[prio];
sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
mac = da;
if ((!sta) && (is_multicast_ether_addr(da))) {
mac = (u8 *)ALLFFMAC;
fifo = 0;
}
hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
found = false;
hash = flow->hash;
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
if ((sta || (memcmp(hash[hash_idx].mac, mac, ETH_ALEN) == 0)) &&
(hash[hash_idx].fifo == fifo) &&
(hash[hash_idx].ifidx == ifidx)) {
found = true;
break;
}
hash_idx++;
}
if (found)
return hash[hash_idx].flowid;
return BRCMF_FLOWRING_INVALID_ID;
}
u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
u8 prio, u8 ifidx)
{
struct brcmf_flowring_ring *ring;
struct brcmf_flowring_hash *hash;
u8 hash_idx;
u32 i;
bool found;
u8 fifo;
bool sta;
u8 *mac;
fifo = brcmf_flowring_prio2fifo[prio];
sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
mac = da;
if ((!sta) && (is_multicast_ether_addr(da))) {
mac = (u8 *)ALLFFMAC;
fifo = 0;
}
hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
found = false;
hash = flow->hash;
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
if (((sta) &&
(hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX)) ||
((!sta) &&
(memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0))) {
found = true;
break;
}
hash_idx++;
}
if (found) {
for (i = 0; i < flow->nrofrings; i++) {
if (flow->rings[i] == NULL)
break;
}
if (i == flow->nrofrings)
return -ENOMEM;
ring = kzalloc(sizeof(*ring), GFP_ATOMIC);
if (!ring)
return -ENOMEM;
memcpy(hash[hash_idx].mac, mac, ETH_ALEN);
hash[hash_idx].fifo = fifo;
hash[hash_idx].ifidx = ifidx;
hash[hash_idx].flowid = i;
ring->hash_id = hash_idx;
ring->status = RING_CLOSED;
skb_queue_head_init(&ring->skblist);
flow->rings[i] = ring;
return i;
}
return BRCMF_FLOWRING_INVALID_ID;
}
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
{
struct brcmf_flowring_ring *ring;
ring = flow->rings[flowid];
return flow->hash[ring->hash_id].fifo;
}
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
{
struct brcmf_flowring_ring *ring;
u8 hash_idx;
struct sk_buff *skb;
ring = flow->rings[flowid];
if (!ring)
return;
hash_idx = ring->hash_id;
flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
memset(flow->hash[hash_idx].mac, 0, ETH_ALEN);
flow->rings[flowid] = NULL;
skb = skb_dequeue(&ring->skblist);
while (skb) {
brcmu_pkt_buf_free_skb(skb);
skb = skb_dequeue(&ring->skblist);
}
kfree(ring);
}
void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
struct sk_buff *skb)
{
struct brcmf_flowring_ring *ring;
ring = flow->rings[flowid];
skb_queue_tail(&ring->skblist, skb);
if (!ring->blocked &&
(skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
brcmf_txflowblock(flow->dev, true);
brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
ring->blocked = 1;
}
}
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
{
struct brcmf_flowring_ring *ring;
struct sk_buff *skb;
ring = flow->rings[flowid];
if (ring->status != RING_OPEN)
return NULL;
skb = skb_dequeue(&ring->skblist);
if (ring->blocked &&
(skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
brcmf_txflowblock(flow->dev, false);
brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
ring->blocked = 0;
}
return skb;
}
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
struct sk_buff *skb)
{
struct brcmf_flowring_ring *ring;
ring = flow->rings[flowid];
skb_queue_head(&ring->skblist, skb);
}
u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
{
struct brcmf_flowring_ring *ring;
ring = flow->rings[flowid];
if (!ring)
return 0;
if (ring->status != RING_OPEN)
return 0;
return skb_queue_len(&ring->skblist);
}
void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
{
struct brcmf_flowring_ring *ring;
ring = flow->rings[flowid];
if (!ring) {
brcmf_err("Ring NULL, for flowid %d\n", flowid);
return;
}
ring->status = RING_OPEN;
}
u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid)
{
struct brcmf_flowring_ring *ring;
u8 hash_idx;
ring = flow->rings[flowid];
hash_idx = ring->hash_id;
return flow->hash[hash_idx].ifidx;
}
struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
{
struct brcmf_flowring *flow;
u32 i;
flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
if (flow) {
flow->dev = dev;
flow->nrofrings = nrofrings;
for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
flow->addr_mode[i] = ADDR_INDIRECT;
for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
flow->rings = kcalloc(nrofrings, sizeof(*flow->rings),
GFP_ATOMIC);
if (!flow->rings) {
kfree(flow);
flow = NULL;
}
}
return flow;
}
void brcmf_flowring_detach(struct brcmf_flowring *flow)
{
struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
struct brcmf_pub *drvr = bus_if->drvr;
u8 flowid;
for (flowid = 0; flowid < flow->nrofrings; flowid++) {
if (flow->rings[flowid])
brcmf_msgbuf_delete_flowring(drvr, flowid);
}
kfree(flow->rings);
kfree(flow);
}
void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
enum proto_addr_mode addr_mode)
{
struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
struct brcmf_pub *drvr = bus_if->drvr;
u32 i;
u8 flowid;
if (flow->addr_mode[ifidx] != addr_mode) {
for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
if (flow->hash[i].ifidx == ifidx) {
flowid = flow->hash[i].flowid;
if (flow->rings[flowid]->status != RING_OPEN)
continue;
flow->rings[flowid]->status = RING_CLOSING;
brcmf_msgbuf_delete_flowring(drvr, flowid);
}
}
flow->addr_mode[ifidx] = addr_mode;
}
}
void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
u8 peer[ETH_ALEN])
{
struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_flowring_hash *hash;
u32 i;
u8 flowid;
bool sta;
sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
hash = flow->hash;
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
(hash[i].ifidx == ifidx)) {
flowid = flow->hash[i].flowid;
if (flow->rings[flowid]->status == RING_OPEN) {
flow->rings[flowid]->status = RING_CLOSING;
brcmf_msgbuf_delete_flowring(drvr, flowid);
}
}
}
}
/* Copyright (c) 2014 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.
*/
#ifndef BRCMFMAC_FLOWRING_H
#define BRCMFMAC_FLOWRING_H
#define BRCMF_FLOWRING_HASHSIZE 256
#define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF
struct brcmf_flowring_hash {
u8 mac[ETH_ALEN];
u8 fifo;
u8 ifidx;
u8 flowid;
};
enum ring_status {
RING_CLOSED,
RING_CLOSING,
RING_OPEN
};
struct brcmf_flowring_ring {
u8 hash_id;
u8 blocked;
enum ring_status status;
struct sk_buff_head skblist;
};
struct brcmf_flowring {
struct device *dev;
struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE];
struct brcmf_flowring_ring **rings;
enum proto_addr_mode addr_mode[BRCMF_MAX_IFS];
u16 nrofrings;
};
u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
u8 prio, u8 ifidx);
u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
u8 prio, u8 ifidx);
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
struct sk_buff *skb);
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
struct sk_buff *skb);
u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid);
u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid);
struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings);
void brcmf_flowring_detach(struct brcmf_flowring *flow);
void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
enum proto_addr_mode addr_mode);
void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
u8 peer[ETH_ALEN]);
#endif /* BRCMFMAC_FLOWRING_H */
This diff is collapsed.
/* Copyright (c) 2014 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.
*/
#ifndef BRCMFMAC_MSGBUF_H
#define BRCMFMAC_MSGBUF_H
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 20
#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 256
#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 20
#define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024
#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 256
#define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40
#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_ITEMSIZE 32
#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_ITEMSIZE 24
#define BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE 16
#define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE 32
#define BRCMF_H2D_TXFLOWRING_ITEMSIZE 48
int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
#endif /* BRCMFMAC_MSGBUF_H */
...@@ -21,9 +21,11 @@ ...@@ -21,9 +21,11 @@
#include <brcmu_wifi.h> #include <brcmu_wifi.h>
#include "dhd.h" #include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h" #include "dhd_dbg.h"
#include "proto.h" #include "proto.h"
#include "bcdc.h" #include "bcdc.h"
#include "msgbuf.h"
int brcmf_proto_attach(struct brcmf_pub *drvr) int brcmf_proto_attach(struct brcmf_pub *drvr)
...@@ -37,10 +39,18 @@ int brcmf_proto_attach(struct brcmf_pub *drvr) ...@@ -37,10 +39,18 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
goto fail; goto fail;
drvr->proto = proto; drvr->proto = proto;
/* BCDC protocol is only protocol supported for the moment */
if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC) {
if (brcmf_proto_bcdc_attach(drvr)) if (brcmf_proto_bcdc_attach(drvr))
goto fail; goto fail;
} else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF) {
if (brcmf_proto_msgbuf_attach(drvr))
goto fail;
} else {
brcmf_err("Unsupported proto type %d\n",
drvr->bus_if->proto_type);
goto fail;
}
if ((proto->txdata == NULL) || (proto->hdrpull == NULL) || if ((proto->txdata == NULL) || (proto->hdrpull == NULL) ||
(proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) ||
(proto->configure_addr_mode == NULL) || (proto->configure_addr_mode == NULL) ||
...@@ -61,7 +71,10 @@ void brcmf_proto_detach(struct brcmf_pub *drvr) ...@@ -61,7 +71,10 @@ void brcmf_proto_detach(struct brcmf_pub *drvr)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
if (drvr->proto) { if (drvr->proto) {
if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
brcmf_proto_bcdc_detach(drvr); brcmf_proto_bcdc_detach(drvr);
else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF)
brcmf_proto_msgbuf_detach(drvr);
kfree(drvr->proto); kfree(drvr->proto);
drvr->proto = NULL; drvr->proto = NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment