brcmfmac: enable 80MHz 11ac AP mode and minor changes
cover brcmfmac: enable 80MHz 11ac AP mode and minor changes
The major part of this series are changes to enable 80MHz 11ac AP mode operation. The other changes are minor optimizations and/or redesign to prepare for new features.
The series is intended for v3.16 and applies to the master branch of the wireless-next repository.
Arend van Spriel (8):
brcmfmac: enhance nvram processing
brcmfmac: remove usage of cfg80211_get_chandef_type()
brcm80211: extend channel conversion functions for 80MHz support
brcmfmac: provide VHT capability information to user-space
brcmfmac: enable 80Mhz in 5G custom regulatory rules
brcmfmac: get rid of brcmf_cfg80211_set_channel() function
brcmfmac: handle 80MHz chanspecs in construct_reg_info() function
brcmfmac: determine chanspec from struct cfg80211_chan_def info
Daniel Kim (3):
brcmfmac: Give priority to 5GHz band in selecting target BSS
brcmfmac: Report the support of firmware roaming
brcmfmac: Fix reconnect failure after beacon timeout
Hante Meuleman (3):
brcmfmac: Move out hdrpull from tx_finalize.
brcmfmac: Move handling 802.1x frames to dhd_linux.
brcmfmac: Make FWS queueing configurable.
drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 2 +- drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 1 + .../net/wireless/brcm80211/brcmfmac/dhd_common.c | 18 ++ .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 32 +-- .../net/wireless/brcm80211/brcmfmac/fwil_types.h | 24 +++ drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 80 +++---- drivers/net/wireless/brcm80211/brcmfmac/nvram.c | 220 ++++++++++++++++---- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 1 + .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 200 +++++++++++++----- drivers/net/wireless/brcm80211/brcmutil/d11.c | 93 +++++++-- drivers/net/wireless/brcm80211/include/brcmu_d11.h | 14 +- .../net/wireless/brcm80211/include/brcmu_wifi.h | 1 + 12 files changed, 508 insertions(+), 178 deletions(-)
Signature · 1 line
1.7.9.5
PATCH 1/14 brcmfmac: Give priority to 5GHz band in selecting target BSS
From: Daniel Kim <[email protected]>
When a BSS provides both 2.4GHz and 5GHz bands, in many cases it makes sense to choose 5GHz. Typically a 5GHz channel is less crowded and has less interference and therefore its performance will be better than a crowded 2.4 GHz channel. This patch configures 'join_pref' to induce firmware to preferably select 5GHz BSS.
--- .../net/wireless/brcm80211/brcmfmac/dhd_common.c | 18 +++++++++++++++ .../net/wireless/brcm80211/brcmfmac/fwil_types.h | 24 ++++++++++++++++++++ 2 files changed, 42 insertions(+)
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +18 -0
@@ -32,6 +32,9 @@#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40#define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00" +/* boost value for RSSI_DELTA in preferred join selection */ +#define BRCMF_JOIN_PREF_RSSI_BOOST 8 +bool brcmf_c_prec_enq (struct device *dev,struct pktq *q,struct sk_buff *pkt,int prec)
@@ -246,6 +249,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) {s8 eventmask[BRCMF_EVENTING_MASK_LEN ];u8 buf[BRCMF_DCMD_SMLEN ]; +struct brcmf_join_pref_params join_pref_params[2 ];char *ptr;s32 err;
@@ -298,6 +302,20 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) goto done; } +/* Setup join_pref to select target by RSSI(with boost on 5GHz) */ + join_pref_params[0 ].type =BRCMF_JOIN_PREF_RSSI_DELTA ; + join_pref_params[0 ].len =2 ; + join_pref_params[0 ].rssi_gain =BRCMF_JOIN_PREF_RSSI_BOOST ; + join_pref_params[0 ].band =WLC_BAND_5G ; + join_pref_params[1 ].type =BRCMF_JOIN_PREF_RSSI ; + join_pref_params[1 ].len =2 ; + join_pref_params[1 ].rssi_gain =0 ; + join_pref_params[1 ].band =0 ; + err =brcmf_fil_iovar_data_set (ifp,"join_pref" , join_pref_params, +sizeof (join_pref_params)); +if (err) +brcmf_err ("Set join_pref error (%d)\n" , err); +/* Setup event_msgs, enable E_IF */ err =brcmf_fil_iovar_data_get (ifp,"event_msgs" , eventmask,BRCMF_EVENTING_MASK_LEN );
drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +24 -0
@@ -53,6 +53,14 @@#define BRCMF_OBSS_COEX_OFF 0#define BRCMF_OBSS_COEX_ON 1 +/* join preference types for join_pref iovar */ +enum brcmf_join_pref_types { +BRCMF_JOIN_PREF_RSSI =1 , +BRCMF_JOIN_PREF_WPA , +BRCMF_JOIN_PREF_BAND , +BRCMF_JOIN_PREF_RSSI_DELTA , +}; +enum brcmf_fil_p2p_if_types {BRCMF_FIL_P2P_IF_CLIENT ,BRCMF_FIL_P2P_IF_GO ,
@@ -282,6 +290,22 @@ struct brcmf_assoc_params_le {__le16 chanspec_list[1 ]; }; +/** +* struct join_pref params - parameters for preferred join selection. +* +* @type: preference type (see enum brcmf_join_pref_types). +* @len: length of bytes following (currently always 2). +* @rssi_gain: signal gain for selection (only when @type is RSSI_DELTA). +* @band: band to which selection preference applies. +* This is used if @type is BAND or RSSI_DELTA. +*/ +struct brcmf_join_pref_params { +u8 type; +u8 len; +u8 rssi_gain; +u8 band; +}; +/* used for join with or without a specific bssid and channel list */ struct brcmf_join_params {struct brcmf_ssid_le ssid_le;
Signature · 1 line
1.7.9.5
PATCH 2/14 brcmfmac: Report the support of firmware roaming
In reply to Arend van SprielFrom: Daniel Kim <[email protected]>
Currently firmware roaming support is not reported to cfg80211. This patch reports the support of firmware based roaming when it is enabled.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +2 -0
@@ -4364,6 +4364,8 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)WIPHY_FLAG_OFFCHAN_TX |WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |WIPHY_FLAG_SUPPORTS_TDLS ; +if (!brcmf_roamoff) + wiphy->flags |=WIPHY_FLAG_SUPPORTS_FW_ROAM ; wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration =5000 ;brcmf_wiphy_pno_params (wiphy);
Signature · 1 line
1.7.9.5
PATCH 3/14 brcmfmac: Move out hdrpull from tx_finalize.
In reply to Arend van SprielFrom: Hante Meuleman <[email protected]>
In tx_finalize the hdrpull is performed. For the new protocol msgbuf this is complex, because it does not use protocol headers in front of payload anymore and therefor can not determine interface index in the hdr pulll operation. Move out the hdrpull operation from tx_finalize to make msgbuf implementation easier.
--- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 2 +- .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 27 +++++------ drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 50 +++++++++----------- 3 files changed, 37 insertions(+), 42 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/dhd.h +1 -1
@@ -186,7 +186,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);void brcmf_txflowblock_if (struct brcmf_if *ifp,enum brcmf_netif_stop_reason reason,bool state);u32 brcmf_get_chip_info (struct brcmf_if *ifp); -void brcmf_txfinalize (struct brcmf_pub *drvr,struct sk_buff *txp, +void brcmf_txfinalize (struct brcmf_pub *drvr,struct sk_buff *txp,u8 ifidx,bool success);/* Sets dongle media info (drv_version, mac address). */
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +13 -14
@@ -538,31 +538,26 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)brcmf_netif_rx (ifp, skb); } -void brcmf_txfinalize (struct brcmf_pub *drvr,struct sk_buff *txp, +void brcmf_txfinalize (struct brcmf_pub *drvr,struct sk_buff *txp,u8 ifidx,bool success) {struct brcmf_if *ifp;struct ethhdr *eh; -u8 ifidx;u16 type; -int res; - - res =brcmf_proto_hdrpull (drvr, false, &ifidx, txp); ifp = drvr->iflist[ifidx];if (!ifp) goto done; -if (res ==0 ) { - eh = (struct ethhdr *)(txp->data); - type =ntohs (eh->h_proto); + eh = (struct ethhdr *)(txp->data); + type =ntohs (eh->h_proto); -if (type ==ETH_P_PAE ) { -atomic_dec (&ifp->pend_8021x_cnt); -if (waitqueue_active (&ifp->pend_8021x_wait)) -wake_up (&ifp->pend_8021x_wait); - } +if (type ==ETH_P_PAE ) { +atomic_dec (&ifp->pend_8021x_cnt); +if (waitqueue_active (&ifp->pend_8021x_wait)) +wake_up (&ifp->pend_8021x_wait); } +if (!success) ifp->stats.tx_errors++; done:
@@ -573,13 +568,17 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) {struct brcmf_bus *bus_if =dev_get_drvdata (dev);struct brcmf_pub *drvr = bus_if->drvr; +u8 ifidx;/* await txstatus signal for firmware if active */ if (brcmf_fws_fc_active (drvr->fws)) {if (!success)brcmf_fws_bustxfail (drvr->fws, txp); }else { -brcmf_txfinalize (drvr, txp, success); +if (brcmf_proto_hdrpull (drvr, false, &ifidx, txp)) +brcmu_pkt_buf_free_skb (txp); +else +brcmf_txfinalize (drvr, txp, ifidx, success); } }
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +23 -27
90 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH 4/14 brcmfmac: Move handling 802.1x frames to dhd_linux.
In reply to Arend van SprielFrom: Hante Meuleman <[email protected]>
Tracking and handling of 802.1x frames is done in two modules, it is more logical and clear to move this to dhd_linux module.
--- .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 5 ++++- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 15 +++++---------- 2 files changed, 9 insertions(+), 11 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +4 -1
@@ -190,7 +190,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,int ret;struct brcmf_if *ifp =netdev_priv (ndev);struct brcmf_pub *drvr = ifp->drvr; -struct ethhdr *eh; +struct ethhdr *eh = (struct ethhdr *)(skb->data);brcmf_dbg (DATA ,"Enter, idx=%d\n" , ifp->bssidx);
@@ -236,6 +236,9 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, goto done; } +if (eh->h_proto ==htons (ETH_P_PAE )) +atomic_inc (&ifp->pend_8021x_cnt); + ret =brcmf_fws_process_skb (ifp, skb); done:
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +5 -10
@@ -1863,7 +1863,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)struct ethhdr *eh = (struct ethhdr *)(skb->data);int fifo =BRCMF_FWS_FIFO_BCMC ;bool multicast =is_multicast_ether_addr (eh->h_dest); -bool pae = eh->h_proto ==htons (ETH_P_PAE ); +int rc =0 ;brcmf_dbg (DATA ,"tx proto=0x%X\n" ,ntohs (eh->h_proto));/* determine the priority */
@@ -1871,8 +1871,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) skb->priority =cfg80211_classify8021d (skb,NULL ); drvr->tx_multicast += !!multicast; -if (pae) -atomic_inc (&ifp->pend_8021x_cnt);/* set control buffer information */ skcb->if_flags =0 ;
@@ -1894,15 +1892,12 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)brcmf_fws_schedule_deq (fws); }else {brcmf_err ("drop skb: no hanger slot\n" ); -if (pae) { -atomic_dec (&ifp->pend_8021x_cnt); -if (waitqueue_active (&ifp->pend_8021x_wait)) -wake_up (&ifp->pend_8021x_wait); - } -brcmu_pkt_buf_free_skb (skb); +brcmf_txfinalize (drvr, skb, ifp->ifidx, false); + rc = -ENOMEM ; }brcmf_fws_unlock (fws); -return 0 ; + +return rc; }void brcmf_fws_reset_interface (struct brcmf_if *ifp)
Signature · 1 line
1.7.9.5
PATCH 5/14 brcmfmac: Make FWS queueing configurable.
In reply to Arend van SprielFrom: Hante Meuleman <[email protected]>
FWS is always queuing frames and using a worker for de-queueing, this is not always efficient for all bus layer. For example SDIO has an internal queue and worker making the queueing of FWS unnecessary. Make it possible to bypass the worker if fws mode is none using a bus interface configuration. For USB bus layer this configuration is set true to have fws provide queueing regardless the fws mode.
--- drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 1 + drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 15 +++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/usb.c | 1 + 3 files changed, 17 insertions(+)
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +1 -0
@@ -99,6 +99,7 @@ struct brcmf_bus {unsigned long tx_realloc;u32 chip;u32 chiprev; +bool always_use_fws_queue;struct brcmf_bus_ops *ops; };
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +15 -0
@@ -476,6 +476,7 @@ struct brcmf_fws_info {bool bus_flow_blocked;bool creditmap_received;u8 mode; +bool avoid_queueing; };/*
@@ -1872,6 +1873,13 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) drvr->tx_multicast += !!multicast; +if (fws->avoid_queueing) { + rc =brcmf_proto_txdata (drvr, ifp->ifidx,0 , skb); +if (rc <0 ) +brcmf_txfinalize (drvr, skb, ifp->ifidx, false); +return rc; + } +/* set control buffer information */ skcb->if_flags =0 ; skcb->state =BRCMF_FWS_SKBSTATE_NEW ;
@@ -2030,6 +2038,13 @@ int brcmf_fws_init(struct brcmf_pub *drvr) fws->drvr = drvr; fws->fcmode = fcmode; +if ((drvr->bus_if->always_use_fws_queue == false) && + (fcmode ==BRCMF_FWS_FCMODE_NONE )) { + fws->avoid_queueing = true; +brcmf_dbg (INFO ,"FWS queueing will be avoided\n" ); +return 0 ; + } + fws->fws_wq =create_singlethread_workqueue ("brcmf_fws_wq" );if (fws->fws_wq ==NULL ) {brcmf_err ("workqueue creation failed\n" );
drivers/net/wireless/brcm80211/brcmfmac/usb.c +1 -0
@@ -1254,6 +1254,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) bus->chip = bus_pub->devid; bus->chiprev = bus_pub->chiprev; bus->proto_type =BRCMF_PROTO_BCDC ; + bus->always_use_fws_queue = true;/* Attach to the common driver interface */ ret =brcmf_attach (dev);
Signature · 1 line
1.7.9.5
PATCH 6/14 brcmfmac: enhance nvram processing
In reply to Arend van SprielThe driver serializes the nvram firmware file before sending it to the device. This patch enhances this to assure serialized data is properly formatted and provide warnings on syntax failures.
--- drivers/net/wireless/brcm80211/brcmfmac/nvram.c | 220 ++++++++++++++++++----- 1 file changed, 176 insertions(+), 44 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/nvram.c +176 -44
@@ -18,72 +18,205 @@#include <linux/slab.h> #include <linux/firmware.h> +#include "dhd_dbg.h" #include "nvram.h" -/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a file +enum nvram_parser_state { +IDLE , +KEY , +VALUE , +COMMENT , +END +}; + +/** +* struct nvram_parser - internal info for parser. +* +* @state: current parser state. +* @fwnv: input buffer being parsed. +* @nvram: output buffer with parse result. +* @nvram_len: lenght of parse result. +* @line: current line. +* @column: current column in line. +* @pos: byte offset in input buffer. +* @entry: start position of key,value entry. +*/ +struct nvram_parser { +enum nvram_parser_state state; +const struct firmware *fwnv; +u8 *nvram; +u32 nvram_len; +u32 line; +u32 column; +u32 pos; +u32 entry; +}; + +static bool is_nvram_char (char c) +{ +/* comment marker excluded */ +if (c =='#' ) +return false; + +/* key and value may have any other readable character */ +return (c >0x20 && c <0x7f ); +} + +static bool is_whitespace (char c) +{ +return (c ==' ' || c =='\r' || c =='\n' || c =='\t' ); +} + +static enum nvram_parser_state brcmf_nvram_handle_idle (struct nvram_parser *nvp) +{ +char c; + + c = nvp->fwnv->data[nvp->pos]; +if (c =='\n' ) +return COMMENT ; +if (is_whitespace (c)) + goto proceed; +if (c =='#' ) +return COMMENT ; +if (is_nvram_char (c)) { + nvp->entry = nvp->pos; +return KEY ; + } +brcmf_dbg (INFO ,"warning: ln=%d:col=%d: ignoring invalid character\n" , + nvp->line, nvp->column); +proceed: + nvp->column++; + nvp->pos++; +return IDLE ; +} + +static enum nvram_parser_state brcmf_nvram_handle_key (struct nvram_parser *nvp) +{ +enum nvram_parser_state st = nvp->state; +char c; + + c = nvp->fwnv->data[nvp->pos]; +if (c =='=' ) { + st =VALUE ; + }else if (!is_nvram_char (c)) { +brcmf_dbg (INFO ,"warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n" , + nvp->line, nvp->column); +return COMMENT ; + } + + nvp->column++; + nvp->pos++; +return st; +} + +static enum nvram_parser_state +brcmf_nvram_handle_value (struct nvram_parser *nvp) +{ +char c; +char *skv; +char *ekv; +u32 cplen; + + c = nvp->fwnv->data[nvp->pos]; +if (!is_nvram_char (c)) { +/* key,value pair complete */ + ekv = (u8 *)&nvp->fwnv->data[nvp->pos]; + skv = (u8 *)&nvp->fwnv->data[nvp->entry]; + cplen = ekv - skv; +/* copy to output buffer */ +memcpy (&nvp->nvram[nvp->nvram_len], skv, cplen); + nvp->nvram_len += cplen; + nvp->nvram[nvp->nvram_len] ='\0' ; + nvp->nvram_len++; +return IDLE ; + } + nvp->pos++; + nvp->column++; +return VALUE ; +} + +static enum nvram_parser_state +brcmf_nvram_handle_comment (struct nvram_parser *nvp) +{ +char *eol, *sol; + + sol = (char *)&nvp->fwnv->data[nvp->pos]; + eol =strchr (sol,'\n' ); +if (eol ==NULL ) +return END ; + +/* eat all moving to next line */ + nvp->line++; + nvp->column =1 ; + nvp->pos += (eol - sol) +1 ; +return IDLE ; +} + +static enum nvram_parser_state brcmf_nvram_handle_end (struct nvram_parser *nvp) +{ +/* final state */ +return END ; +} + +static enum nvram_parser_state +(*nv_parser_states[])(struct nvram_parser *nvp) = { + brcmf_nvram_handle_idle, + brcmf_nvram_handle_key, + brcmf_nvram_handle_value, + brcmf_nvram_handle_comment, + brcmf_nvram_handle_end +}; + +static int brcmf_init_nvram_parser (struct nvram_parser *nvp, +const struct firmware *nv) +{ +memset (nvp,0 ,sizeof (*nvp)); + nvp->fwnv = nv; +/* Alloc for extra 0 byte + roundup by 4 + length field */ + nvp->nvram =kzalloc (nv->size +1 +3 +sizeof (u32),GFP_KERNEL ); +if (!nvp->nvram) +return -ENOMEM ; + + nvp->line =1 ; + nvp->column =1 ; +return 0 ; +} + +/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil * and ending in a NUL. Removes carriage returns, empty lines, comment lines, * and converts newlines to NULs. Shortens buffer as needed and pads with NULs. * End of buffer is completed with token identifying length of buffer. */ void *brcmf_nvram_strip (const struct firmware *nv,u32 *new_length) { -u8 *nvram; -u32 i; -u32 len; -u32 column; -u8 val; -bool comment; +struct nvram_parser nvp; +u32 pad;u32 token;__le32 token_le; -/* Alloc for extra 0 byte + roundup by 4 + length field */ - nvram =kmalloc (nv->size +1 +3 +sizeof (token_le),GFP_KERNEL ); -if (!nvram) +if (brcmf_init_nvram_parser (&nvp, nv) <0 )return NULL ; - len =0 ; - column =0 ; - comment = false; -for (i =0 ; i < nv->size; i++) { - val = nv->data[i]; -if (val ==0 ) +while (nvp.pos < nv->size) { + nvp.state = nv_parser_states[nvp.state](&nvp); +if (nvp.state ==END )break ; -if (val =='\r' ) -continue ; -if (comment && (val !='\n' )) -continue ; - comment = false; -if (val =='#' ) { - comment = true; -continue ; - } -if (val =='\n' ) { -if (column ==0 ) -continue ; - nvram[len] =0 ; - len++; - column =0 ; -continue ; - } - nvram[len] = val; - len++; - column++; } - column = len; - *new_length =roundup (len +1 ,4 ); -while (column != *new_length) { - nvram[column] =0 ; - column++; + pad = nvp.nvram_len; + *new_length =roundup (nvp.nvram_len +1 ,4 ); +while (pad != *new_length) { + nvp.nvram[pad] =0 ; + pad++; } token = *new_length /4 ; token = (~token <<16 ) | (token &0x0000FFFF ); token_le =cpu_to_le32 (token); -memcpy (&nvram[*new_length], &token_le,sizeof (token_le)); +memcpy (&nvp.nvram[*new_length], &token_le,sizeof (token_le)); *new_length +=sizeof (token_le); -return nvram; +return nvp.nvram; }void brcmf_nvram_free (void *nvram)
@@ -91,4 +224,3 @@ void brcmf_nvram_free(void *nvram)kfree (nvram); } -
Signature · 1 line
1.7.9.5
PATCH 7/14 brcmfmac: Fix reconnect failure after beacon timeout
In reply to Arend van SprielFrom: Daniel Kim <[email protected]>
The DISASSOC command needs to be sent to firmware when a connection loss is detected by firmware (e.g., beacon timeout). Otherwise the next connect request fails due to a lingering LINK(down) event from firmware. This patch resolves the issue by using brcmf_link_down() handler, instead of the incomplete duplicated codes.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 11 ----------- 1 file changed, 11 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +0 -11
@@ -4687,7 +4687,6 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;struct ieee80211_channel *chan;s32 err =0 ; -u16 reason;if (brcmf_is_apmode (ifp->vif)) { err =brcmf_notify_connect_status_ap (cfg, ndev, e, data);
@@ -4708,16 +4707,6 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,brcmf_dbg (CONN ,"Linkdown\n" );if (!brcmf_is_ibssmode (ifp->vif)) {brcmf_bss_connect_done (cfg, ndev, e, false); -if (test_and_clear_bit (BRCMF_VIF_STATUS_CONNECTED , - &ifp->vif->sme_state)) { - reason =0 ; -if (((e->event_code ==BRCMF_E_DEAUTH_IND ) || - (e->event_code ==BRCMF_E_DISASSOC_IND )) && - (e->reason !=WLAN_REASON_UNSPECIFIED )) - reason = e->reason; -cfg80211_disconnected (ndev, reason,NULL ,0 , -GFP_KERNEL ); - } }brcmf_link_down (ifp->vif);brcmf_init_prof (ndev_to_prof (ndev));
Signature · 1 line
1.7.9.5
PATCH 8/14 brcmfmac: remove usage of cfg80211_get_chandef_type()
In reply to Arend van SprielIn the .start_ap callback cfg80211_get_chandef_type() was used to provide debug log info. However, this causes a warning when the chandef contains VHT channel with 80MHz bandwidth. Avoid the warning by just printing the channel and bandwidth instead.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +3 -4
@@ -3766,10 +3766,9 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,enum nl80211_iftype dev_role;struct brcmf_fil_bss_enable_le bss_enable; -brcmf_dbg (TRACE ,"channel_type=%d, beacon_interval=%d, dtim_period=%d,\n" , -cfg80211_get_chandef_type (&settings->chandef), - settings->beacon_interval, - settings->dtim_period); +brcmf_dbg (TRACE ,"channel=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n" , + settings->chandef.chan->hw_value, settings->chandef.width, + settings->beacon_interval, settings->dtim_period);brcmf_dbg (TRACE ,"ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n" , settings->ssid, settings->ssid_len, settings->auth_type, settings->inactivity_timeout);
Signature · 1 line
1.7.9.5
PATCH 9/14 brcm80211: extend channel conversion functions for 80MHz support
In reply to Arend van SprielThe channel values used by firmware is handled using conversion functions depending on the type of chip. These functions were already in place but lacked proper support for 80MHz channel definitions. This patch adds the support for that.
--- drivers/net/wireless/brcm80211/brcmutil/d11.c | 93 ++++++++++++++++---- drivers/net/wireless/brcm80211/include/brcmu_d11.h | 14 +-- .../net/wireless/brcm80211/include/brcmu_wifi.h | 1 + 3 files changed, 84 insertions(+), 24 deletions(-)
drivers/net/wireless/brcm80211/brcmutil/d11.c +76 -17
@@ -21,43 +21,81 @@#include <brcmu_wifi.h> #include <brcmu_d11.h> -static void brcmu_d11n_encchspec (struct brcmu_chan *ch) +static u16 d11n_sb (enum brcmu_chan_sb sb) { - ch->chspec = ch->chnum &BRCMU_CHSPEC_CH_MASK ; +switch (sb) { +case BRCMU_CHAN_SB_NONE : +return BRCMU_CHSPEC_D11N_SB_N ; +case BRCMU_CHAN_SB_L : +return BRCMU_CHSPEC_D11N_SB_L ; +case BRCMU_CHAN_SB_U : +return BRCMU_CHSPEC_D11N_SB_U ; +default : +WARN_ON (1 ); + } +return 0 ; +} -switch (ch->bw) { +static u16 d11n_bw (enum brcmu_chan_bw bw) +{ +switch (bw) {case BRCMU_CHAN_BW_20 : - ch->chspec |=BRCMU_CHSPEC_D11N_BW_20 |BRCMU_CHSPEC_D11N_SB_N ; -break ; +return BRCMU_CHSPEC_D11N_BW_20 ;case BRCMU_CHAN_BW_40 : +return BRCMU_CHSPEC_D11N_BW_40 ;default : -WARN_ON_ONCE (1 ); -break ; +WARN_ON (1 ); } +return 0 ; +} +static void brcmu_d11n_encchspec (struct brcmu_chan *ch) +{ +if (ch->bw ==BRCMU_CHAN_BW_20 ) + ch->sb =BRCMU_CHAN_SB_NONE ; + +brcmu_maskset16 (&ch->chspec,BRCMU_CHSPEC_CH_MASK , +BRCMU_CHSPEC_CH_SHIFT , ch->chnum); +brcmu_maskset16 (&ch->chspec,BRCMU_CHSPEC_D11N_SB_MASK , +0 ,d11n_sb (ch->sb)); +brcmu_maskset16 (&ch->chspec,BRCMU_CHSPEC_D11N_BW_MASK , +0 ,d11n_bw (ch->bw)); + + ch->chspec &= ~BRCMU_CHSPEC_D11N_BND_MASK ;if (ch->chnum <=CH_MAX_2G_CHANNEL ) ch->chspec |=BRCMU_CHSPEC_D11N_BND_2G ;else ch->chspec |=BRCMU_CHSPEC_D11N_BND_5G ; } -static void brcmu_d11ac_encchspec (struct brcmu_chan *ch) +static u16 d11ac_bw (enum brcmu_chan_bw bw) { - ch->chspec = ch->chnum &BRCMU_CHSPEC_CH_MASK ; - -switch (ch->bw) { +switch (bw) {case BRCMU_CHAN_BW_20 : - ch->chspec |=BRCMU_CHSPEC_D11AC_BW_20 ; -break ; +return BRCMU_CHSPEC_D11AC_BW_20 ;case BRCMU_CHAN_BW_40 : +return BRCMU_CHSPEC_D11AC_BW_40 ;case BRCMU_CHAN_BW_80 : -case BRCMU_CHAN_BW_80P80 : -case BRCMU_CHAN_BW_160 : +return BRCMU_CHSPEC_D11AC_BW_80 ;default : -WARN_ON_ONCE (1 ); -break ; +WARN_ON (1 ); } +return 0 ; +} +static void brcmu_d11ac_encchspec (struct brcmu_chan *ch) +{ +if (ch->bw ==BRCMU_CHAN_BW_20 || ch->sb ==BRCMU_CHAN_SB_NONE ) + ch->sb =BRCMU_CHAN_SB_L ; + +brcmu_maskset16 (&ch->chspec,BRCMU_CHSPEC_CH_MASK , +BRCMU_CHSPEC_CH_SHIFT , ch->chnum); +brcmu_maskset16 (&ch->chspec,BRCMU_CHSPEC_D11AC_SB_MASK , +BRCMU_CHSPEC_D11AC_SB_SHIFT , ch->sb); +brcmu_maskset16 (&ch->chspec,BRCMU_CHSPEC_D11AC_BW_MASK , +0 ,d11ac_bw (ch->bw)); + + ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK ;if (ch->chnum <=CH_MAX_2G_CHANNEL ) ch->chspec |=BRCMU_CHSPEC_D11AC_BND_2G ;else
@@ -73,6 +111,7 @@ static void brcmu_d11n_decchspec(struct brcmu_chan *ch)switch (ch->chspec &BRCMU_CHSPEC_D11N_BW_MASK ) {case BRCMU_CHSPEC_D11N_BW_20 : ch->bw =BRCMU_CHAN_BW_20 ; + ch->sb =BRCMU_CHAN_SB_NONE ;break ;case BRCMU_CHSPEC_D11N_BW_40 : ch->bw =BRCMU_CHAN_BW_40 ;
@@ -112,6 +151,7 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)switch (ch->chspec &BRCMU_CHSPEC_D11AC_BW_MASK ) {case BRCMU_CHSPEC_D11AC_BW_20 : ch->bw =BRCMU_CHAN_BW_20 ; + ch->sb =BRCMU_CHAN_SB_NONE ;break ;case BRCMU_CHSPEC_D11AC_BW_40 : ch->bw =BRCMU_CHAN_BW_40 ;
@@ -128,6 +168,25 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)break ;case BRCMU_CHSPEC_D11AC_BW_80 : ch->bw =BRCMU_CHAN_BW_80 ; + ch->sb =brcmu_maskget16 (ch->chspec,BRCMU_CHSPEC_D11AC_SB_MASK , +BRCMU_CHSPEC_D11AC_SB_SHIFT ); +switch (ch->sb) { +case BRCMU_CHAN_SB_LL : + ch->chnum -=CH_30MHZ_APART ; +break ; +case BRCMU_CHAN_SB_LU : + ch->chnum -=CH_10MHZ_APART ; +break ; +case BRCMU_CHAN_SB_UL : + ch->chnum +=CH_10MHZ_APART ; +break ; +case BRCMU_CHAN_SB_UU : + ch->chnum +=CH_30MHZ_APART ; +break ; +default : +WARN_ON_ONCE (1 ); +break ; + }break ;case BRCMU_CHSPEC_D11AC_BW_8080 :case BRCMU_CHSPEC_D11AC_BW_160 :
drivers/net/wireless/brcm80211/include/brcmu_d11.h +7 -7
@@ -108,13 +108,7 @@ enum brcmu_chan_bw { };enum brcmu_chan_sb { -BRCMU_CHAN_SB_NONE =0 , -BRCMU_CHAN_SB_L , -BRCMU_CHAN_SB_U , -BRCMU_CHAN_SB_LL , -BRCMU_CHAN_SB_LU , -BRCMU_CHAN_SB_UL , -BRCMU_CHAN_SB_UU , +BRCMU_CHAN_SB_NONE =-1 ,BRCMU_CHAN_SB_LLL ,BRCMU_CHAN_SB_LLU ,BRCMU_CHAN_SB_LUL ,
@@ -123,6 +117,12 @@ enum brcmu_chan_sb {BRCMU_CHAN_SB_ULU ,BRCMU_CHAN_SB_UUL ,BRCMU_CHAN_SB_UUU , +BRCMU_CHAN_SB_L =BRCMU_CHAN_SB_LLL , +BRCMU_CHAN_SB_U =BRCMU_CHAN_SB_LLU , +BRCMU_CHAN_SB_LL =BRCMU_CHAN_SB_LLL , +BRCMU_CHAN_SB_LU =BRCMU_CHAN_SB_LLU , +BRCMU_CHAN_SB_UL =BRCMU_CHAN_SB_LUL , + BRCMU_CHAN_SB_UU = BRCMU_CHAN_SB_LUU, }; struct brcmu_chan {
drivers/net/wireless/brcm80211/include/brcmu_wifi.h +1 -0
@@ -29,6 +29,7 @@#define CH_UPPER_SB 0x01#define CH_LOWER_SB 0x02#define CH_EWA_VALID 0x04 +#define CH_30MHZ_APART 6#define CH_20MHZ_APART 4#define CH_10MHZ_APART 2#define CH_5MHZ_APART 1/* 2G band channels are 5 Mhz apart */
Signature · 1 line
1.7.9.5
PATCH 10/14 brcmfmac: provide VHT capability information to user-space
In reply to Arend van SprielAlthough brcmfmac support several 11ac devices it did not advertise VHT related information to cfg80211.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 73 ++++++++++++++++---- 1 file changed, 59 insertions(+), 14 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +59 -14
@@ -5313,13 +5313,63 @@ static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[]) } } +static void brcmf_update_ht_cap (struct ieee80211_supported_band *band, +u32 bw_cap[2 ],u32 nchain) +{ + band->ht_cap.ht_supported = true; +if (bw_cap[band->band] &WLC_BW_40MHZ_BIT ) { + band->ht_cap.cap |=IEEE80211_HT_CAP_SGI_40 ; + band->ht_cap.cap |=IEEE80211_HT_CAP_SUP_WIDTH_20_40 ; + } + band->ht_cap.cap |=IEEE80211_HT_CAP_SGI_20 ; + band->ht_cap.cap |=IEEE80211_HT_CAP_DSSSCCK40 ; + band->ht_cap.ampdu_factor =IEEE80211_HT_MAX_AMPDU_64K ; + band->ht_cap.ampdu_density =IEEE80211_HT_MPDU_DENSITY_16 ; +memset (band->ht_cap.mcs.rx_mask,0xff , nchain); + band->ht_cap.mcs.tx_params =IEEE80211_HT_MCS_TX_DEFINED ; +} + +static __le16 brcmf_get_mcs_map (u32 nchain,enum ieee80211_vht_mcs_support supp) +{ +u16 mcs_map; +int i; + +for (i =0 , mcs_map =0xFFFF ; i < nchain; i++) + mcs_map = (mcs_map <<2 ) | supp; + +return cpu_to_le16 (mcs_map); +} + +static void brcmf_update_vht_cap (struct ieee80211_supported_band *band, +u32 bw_cap[2 ],u32 nchain) +{ +__le16 mcs_map; + +/* not allowed in 2.4G band */ +if (band->band ==IEEE80211_BAND_2GHZ ) +return ; + + band->vht_cap.vht_supported = true; +/* 80MHz is mandatory */ + band->vht_cap.cap |=IEEE80211_VHT_CAP_SHORT_GI_80 ; +if (bw_cap[band->band] &WLC_BW_160MHZ_BIT ) { + band->vht_cap.cap |=IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ; + band->vht_cap.cap |=IEEE80211_VHT_CAP_SHORT_GI_160 ; + } +/* all support 256-QAM */ + mcs_map =brcmf_get_mcs_map (nchain,IEEE80211_VHT_MCS_SUPPORT_0_9 ); + band->vht_cap.vht_mcs.rx_mcs_map = mcs_map; + band->vht_cap.vht_mcs.tx_mcs_map = mcs_map; +} +static s32 brcmf_update_wiphybands (struct brcmf_cfg80211_info *cfg) {struct brcmf_if *ifp =netdev_priv (cfg_to_ndev (cfg));struct wiphy *wiphy;s32 phy_list;u32 band_list[3 ]; -u32 nmode; +u32 nmode =0 ; +u32 vhtmode =0 ;u32 bw_cap[2 ] = {0 ,0 };u32 rxchain;u32 nchain;
@@ -5350,14 +5400,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)brcmf_dbg (INFO ,"BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n" , band_list[0 ], band_list[1 ], band_list[2 ]); + (void )brcmf_fil_iovar_int_get (ifp,"vhtmode" , &vhtmode); err =brcmf_fil_iovar_int_get (ifp,"nmode" , &nmode);if (err) {brcmf_err ("nmode error (%d)\n" , err); }else {brcmf_get_bwcap (ifp, bw_cap); } -brcmf_dbg (INFO ,"nmode=%d, bw_cap=(%d, %d)\n" , nmode, - bw_cap[IEEE80211_BAND_2GHZ ], bw_cap[IEEE80211_BAND_5GHZ ]); +brcmf_dbg (INFO ,"nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n" , + nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ ], + bw_cap[IEEE80211_BAND_5GHZ ]); err =brcmf_fil_iovar_int_get (ifp,"rxchain" , &rxchain);if (err) {
@@ -5388,17 +5440,10 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)else continue ; -if (bw_cap[band->band] &WLC_BW_40MHZ_BIT ) { - band->ht_cap.cap |=IEEE80211_HT_CAP_SGI_40 ; - band->ht_cap.cap |=IEEE80211_HT_CAP_SUP_WIDTH_20_40 ; - } - band->ht_cap.cap |=IEEE80211_HT_CAP_SGI_20 ; - band->ht_cap.cap |=IEEE80211_HT_CAP_DSSSCCK40 ; - band->ht_cap.ht_supported = true; - band->ht_cap.ampdu_factor =IEEE80211_HT_MAX_AMPDU_64K ; - band->ht_cap.ampdu_density =IEEE80211_HT_MPDU_DENSITY_16 ; -memset (band->ht_cap.mcs.rx_mask,0xff , nchain); - band->ht_cap.mcs.tx_params =IEEE80211_HT_MCS_TX_DEFINED ; +if (nmode) +brcmf_update_ht_cap (band, bw_cap, nchain); +if (vhtmode) +brcmf_update_vht_cap (band, bw_cap, nchain); bands[band->band] = band; }
Signature · 1 line
1.7.9.5
PATCH 11/14 brcmfmac: enable 80Mhz in 5G custom regulatory rules
In reply to Arend van SprielBy default allow 80Mhz in custom regulatory rules of the 5G band so the channels will not be flagged with N0_80MHZ.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +2 -2
@@ -221,9 +221,9 @@ static const struct ieee80211_regdomain brcmf_regdom = {*/ REG_RULE (2484 -10 ,2484 +10 ,20 ,6 ,20 ,0 ),/* IEEE 802.11a, channel 36..64 */ -REG_RULE (5150 -10 ,5350 +10 ,40 ,6 ,20 ,0 ), +REG_RULE (5150 -10 ,5350 +10 ,80 ,6 ,20 ,0 ),/* IEEE 802.11a, channel 100..165 */ - REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } + REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), } }; static const u32 __wl_cipher_suites[] = {
Signature · 1 line
1.7.9.5
PATCH 12/14 brcmfmac: get rid of brcmf_cfg80211_set_channel() function
In reply to Arend van SprielThe function does not provide any additional functionality and is used only once so just get rid of it.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 28 +++++--------------- 1 file changed, 7 insertions(+), 21 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +7 -21
@@ -3734,23 +3734,6 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, }static s32 -brcmf_cfg80211_set_channel (struct brcmf_cfg80211_info *cfg, -struct brcmf_if *ifp, -struct ieee80211_channel *channel) -{ -u16 chanspec; -s32 err; - -brcmf_dbg (TRACE ,"band=%d, center_freq=%d\n" , channel->band, - channel->center_freq); - - chanspec =channel_to_chanspec (&cfg->d11inf, channel); - err =brcmf_fil_iovar_int_set (ifp,"chanspec" , chanspec); - -return err; -} - -static s32 brcmf_cfg80211_start_ap (struct wiphy *wiphy,struct net_device *ndev,struct cfg80211_ap_settings *settings) {
@@ -3765,9 +3748,11 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,struct brcmf_join_params join_params;enum nl80211_iftype dev_role;struct brcmf_fil_bss_enable_le bss_enable; +u16 chanspec; -brcmf_dbg (TRACE ,"channel=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n" , - settings->chandef.chan->hw_value, settings->chandef.width, +brcmf_dbg (TRACE ,"ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n" , + settings->chandef.chan->hw_value, + settings->chandef.center_freq1, settings->chandef.width, settings->beacon_interval, settings->dtim_period); brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n", settings->ssid, settings->ssid_len, settings->auth_type,
@@ -3825,9 +3810,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,brcmf_config_ap_mgmt_ie (ifp->vif, &settings->beacon); - err =brcmf_cfg80211_set_channel (cfg, ifp, settings->chandef.chan); + chanspec =channel_to_chanspec (&cfg->d11inf, settings->chandef.chan); + err =brcmf_fil_iovar_int_set (ifp,"chanspec" , chanspec);if (err <0 ) { -brcmf_err ("Set Channel failed, %d\n" , err); +brcmf_err ("Set Channel failed: chspec=%d, %d\n" , chanspec, err); goto exit; }
Signature · 1 line
1.7.9.5
PATCH 13/14 brcmfmac: handle 80MHz chanspecs in construct_reg_info() function
In reply to Arend van SprielThe device is queried about the usability of channels, but it did not take 80MHz channels into consideration. This patch adds processing those chanspecs and clear the NO_80MHZ flag for those control/primary channels.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 21 +++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +16 -5
@@ -5191,6 +5191,9 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,if (!(bw_cap[band] &WLC_BW_40MHZ_BIT ) && ch.bw ==BRCMU_CHAN_BW_40 )continue ; +if (!(bw_cap[band] &WLC_BW_80MHZ_BIT ) && + ch.bw ==BRCMU_CHAN_BW_80 ) +continue ; update = false;for (j =0 ; (j < *n_cnt && (*n_cnt < array_size)); j++) {if (band_chan_arr[j].hw_value == ch.chnum) {
@@ -5207,10 +5210,13 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,ieee80211_channel_to_frequency (ch.chnum, band); band_chan_arr[index].hw_value = ch.chnum; -if (ch.bw ==BRCMU_CHAN_BW_40 ) { -/* assuming the order is HT20, HT40 Upper, -* HT40 lower from chanspecs -*/ +/* assuming the chanspecs order is HT20, +* HT40 upper, HT40 lower, and VHT80. +*/ +if (ch.bw ==BRCMU_CHAN_BW_80 ) { + band_chan_arr[index].flags &= + ~IEEE80211_CHAN_NO_80MHZ ; + }else if (ch.bw ==BRCMU_CHAN_BW_40 ) { ht40_flag = band_chan_arr[index].flags &IEEE80211_CHAN_NO_HT40 ;if (ch.sb ==BRCMU_CHAN_SB_U ) {
@@ -5231,8 +5237,13 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,IEEE80211_CHAN_NO_HT40MINUS ; } }else { +/* disable other bandwidths for now as mentioned +* order assure they are enabled for subsequent +* chanspecs. +*/ band_chan_arr[index].flags = -IEEE80211_CHAN_NO_HT40 ; +IEEE80211_CHAN_NO_HT40 | +IEEE80211_CHAN_NO_80MHZ ; ch.bw =BRCMU_CHAN_BW_20 ; cfg->d11inf.encchspec (&ch); channel = ch.chspec;
Signature · 1 line
1.7.9.5
PATCH 14/14 brcmfmac: determine chanspec from struct cfg80211_chan_def info
In reply to Arend van SprielThe struct cfg80211_chan_def contains additional info to derive the bandwidth and side-band information of the chanspec. This patch adds chandef_to_chanspec() function used in IBSS join and starting AP operation.
--- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 60 +++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-)
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +57 -3
@@ -341,6 +341,60 @@ static u8 brcmf_mw_to_qdbm(u16 mw)return qdbm; } +u16 chandef_to_chanspec (struct brcmu_d11inf *d11inf, +struct cfg80211_chan_def *ch) +{ +struct brcmu_chan ch_inf; +s32 primary_offset; + +brcmf_dbg (TRACE ,"chandef: control %d center %d width %d\n" , + ch->chan->center_freq, ch->center_freq1, ch->width); + ch_inf.chnum =ieee80211_frequency_to_channel (ch->center_freq1); + primary_offset = ch->center_freq1 - ch->chan->center_freq; +switch (ch->width) { +case NL80211_CHAN_WIDTH_20 : + ch_inf.bw =BRCMU_CHAN_BW_20 ; +WARN_ON (primary_offset !=0 ); +break ; +case NL80211_CHAN_WIDTH_40 : + ch_inf.bw =BRCMU_CHAN_BW_40 ; +if (primary_offset <0 ) + ch_inf.sb =BRCMU_CHAN_SB_U ; +else + ch_inf.sb =BRCMU_CHAN_SB_L ; +break ; +case NL80211_CHAN_WIDTH_80 : + ch_inf.bw =BRCMU_CHAN_BW_80 ; +if (primary_offset <0 ) { +if (primary_offset < -CH_10MHZ_APART ) + ch_inf.sb =BRCMU_CHAN_SB_UU ; +else + ch_inf.sb =BRCMU_CHAN_SB_UL ; + }else { +if (primary_offset >CH_10MHZ_APART ) + ch_inf.sb =BRCMU_CHAN_SB_LL ; +else + ch_inf.sb =BRCMU_CHAN_SB_LU ; + } +break ; +default : +WARN_ON_ONCE (1 ); + } +switch (ch->chan->band) { +case IEEE80211_BAND_2GHZ : + ch_inf.band =BRCMU_CHAN_BAND_2G ; +break ; +case IEEE80211_BAND_5GHZ : + ch_inf.band =BRCMU_CHAN_BAND_5G ; +break ; +default : +WARN_ON_ONCE (1 ); + } + d11inf->encchspec (&ch_inf); + +return ch_inf.chspec; +} +u16 channel_to_chanspec (struct brcmu_d11inf *d11inf,struct ieee80211_channel *ch) {
@@ -1236,8 +1290,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, params->chandef.chan->center_freq);if (params->channel_fixed) {/* adding chanspec */ - chanspec =channel_to_chanspec (&cfg->d11inf, - params->chandef.chan); + chanspec =chandef_to_chanspec (&cfg->d11inf, + ¶ms->chandef); join_params.params_le.chanspec_list[0 ] =cpu_to_le16 (chanspec); join_params.params_le.chanspec_num =cpu_to_le32 (1 );
@@ -3810,7 +3864,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,brcmf_config_ap_mgmt_ie (ifp->vif, &settings->beacon); - chanspec =channel_to_chanspec (&cfg->d11inf, settings->chandef.chan); + chanspec =chandef_to_chanspec (&cfg->d11inf, &settings->chandef); err =brcmf_fil_iovar_int_set (ifp,"chanspec" , chanspec);if (err <0 ) {brcmf_err ("Set Channel failed: chspec=%d, %d\n" , chanspec, err);
Signature · 1 line
1.7.9.5