[bwn] add initial 5xx firmware API support

* Add the new TX/RX frame formats;
* Use the right TX/RX format based on the frame info;
* Disable the 5xx firmware check, since now it should
  somewhat work (but note, we don't yet use it unless
  you manually add ucode11/initvals11 from the 5.x driver
  to bwn-kmod-firmware;

* Misc: update some comments/debugging now I know what's
  actually going on.

Tested:

* BCM4321MC, STA mode, both 4xx and 666 firmware, DMA mode

TODO:

* The newer firmware ends up logging "warn: firmware state (0)";
  not sure yet what's going on there.  But, yes, it still works.
  I'm committing this via a BCM4321MC, 11a station, firmware
  rev 666.

Obtained from:	Linux b43 (TX/RX descriptor format for 5xx)
This commit is contained in:
adrian 2016-05-18 05:56:25 +00:00
parent 596f2a146d
commit 4b1c046953
2 changed files with 189 additions and 39 deletions

View File

@ -1216,14 +1216,12 @@ bwn_attach_core(struct bwn_mac *mac)
}
/*
* XXX turns off PHY A because it's not supported.
* Implement PHY-A support so we can use it for PHY-G
* dual-band support.
* XXX The PHY-G support doesn't do 5GHz operation.
*/
if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
mac->mac_phy.type != BWN_PHYTYPE_N) {
device_printf(sc->sc_dev,
"%s: forcing 2GHz only; missing PHY-A support\n",
"%s: forcing 2GHz only; no dual-band support for PHY\n",
__func__);
have_a = 0;
have_bg = 1;
@ -3791,6 +3789,8 @@ bwn_psctl(struct bwn_mac *mac, uint32_t flags)
DELAY(10);
}
}
DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: ucstat=%d\n", __func__,
ucstat);
}
static int
@ -4186,12 +4186,14 @@ bwn_fw_loaducode(struct bwn_mac *mac)
* So, complain this is the case and exit out, rather
* than attaching and then failing.
*/
#if 0
if (mac->mac_fw.fw_hdr_format == BWN_FW_HDR_598) {
device_printf(sc->sc_dev,
"firmware is too new (>=598); not supported\n");
error = EOPNOTSUPP;
goto error;
}
#endif
mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
BWN_SHARED_UCODE_PATCH);
@ -5351,7 +5353,17 @@ bwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
len, dr->dr_rx_bufsize, cnt);
return;
}
macstat = le32toh(rxhdr->mac_status);
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
case BWN_FW_HDR_410:
macstat = le32toh(rxhdr->ps4.r351.mac_status);
break;
case BWN_FW_HDR_598:
macstat = le32toh(rxhdr->ps4.r598.mac_status);
break;
}
if (macstat & BWN_RX_MAC_FCSERR) {
if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
device_printf(sc->sc_dev, "RX drop\n");
@ -5452,7 +5464,16 @@ bwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
goto error;
}
macstat = le32toh(rxhdr.mac_status);
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
case BWN_FW_HDR_410:
macstat = le32toh(rxhdr.ps4.r351.mac_status);
break;
case BWN_FW_HDR_598:
macstat = le32toh(rxhdr.ps4.r598.mac_status);
break;
}
if (macstat & BWN_RX_MAC_FCSERR) {
if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
device_printf(sc->sc_dev, "%s: FCS error", __func__);
@ -5706,11 +5727,25 @@ bwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
BWN_ASSERT_LOCKED(sc);
phystat0 = le16toh(rxhdr->phy_status0);
phystat3 = le16toh(rxhdr->phy_status3);
/* XXX Note: mactime, macstat, chanstat need fixing for fw 598 */
macstat = le32toh(rxhdr->mac_status);
chanstat = le16toh(rxhdr->channel);
/*
* XXX Note: phy_status3 doesn't exist for HT-PHY; it's only
* used for LP-PHY.
*/
phystat3 = le16toh(rxhdr->ps3.lp.phy_status3);
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
case BWN_FW_HDR_410:
macstat = le32toh(rxhdr->ps4.r351.mac_status);
chanstat = le16toh(rxhdr->ps4.r351.channel);
break;
case BWN_FW_HDR_598:
macstat = le32toh(rxhdr->ps4.r598.mac_status);
chanstat = le16toh(rxhdr->ps4.r598.channel);
break;
}
phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
@ -6181,10 +6216,22 @@ bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
m->m_pkthdr.len, rate, isshort);
/* XXX TX encryption */
bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
(struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
(struct bwn_plcp4 *)(&txhdr->body.new.plcp),
m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->body.r351.plcp),
m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
break;
case BWN_FW_HDR_410:
bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->body.r410.plcp),
m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
break;
case BWN_FW_HDR_598:
bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->body.r598.plcp),
m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
break;
}
bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
@ -6243,9 +6290,22 @@ bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
+ ieee80211_ack_duration(ic->ic_rt, rate, isshort);
if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
(txhdr->body.old.rts_frame) :
(txhdr->body.new.rts_frame));
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
cts = (struct ieee80211_frame_cts *)
txhdr->body.r351.rts_frame;
break;
case BWN_FW_HDR_410:
cts = (struct ieee80211_frame_cts *)
txhdr->body.r410.rts_frame;
break;
case BWN_FW_HDR_598:
cts = (struct ieee80211_frame_cts *)
txhdr->body.r598.rts_frame;
break;
}
mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
protdur);
KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
@ -6255,9 +6315,21 @@ bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
len = sizeof(struct ieee80211_frame_cts);
} else {
rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
(txhdr->body.old.rts_frame) :
(txhdr->body.new.rts_frame));
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
rts = (struct ieee80211_frame_rts *)
txhdr->body.r351.rts_frame;
break;
case BWN_FW_HDR_410:
rts = (struct ieee80211_frame_rts *)
txhdr->body.r410.rts_frame;
break;
case BWN_FW_HDR_598:
rts = (struct ieee80211_frame_rts *)
txhdr->body.r598.rts_frame;
break;
}
/* XXX rate/rate_fb is the hardware rate */
protdur += ieee80211_ack_duration(ic->ic_rt, rate,
isshort);
@ -6271,15 +6343,40 @@ bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
len = sizeof(struct ieee80211_frame_rts);
}
len += IEEE80211_CRC_LEN;
bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
&txhdr->body.old.rts_plcp :
&txhdr->body.new.rts_plcp), len, rts_rate);
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
bwn_plcp_genhdr((struct bwn_plcp4 *)
&txhdr->body.r351.rts_plcp, len, rts_rate);
break;
case BWN_FW_HDR_410:
bwn_plcp_genhdr((struct bwn_plcp4 *)
&txhdr->body.r410.rts_plcp, len, rts_rate);
break;
case BWN_FW_HDR_598:
bwn_plcp_genhdr((struct bwn_plcp4 *)
&txhdr->body.r598.rts_plcp, len, rts_rate);
break;
}
bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
rts_rate_fb);
protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
(&txhdr->body.old.rts_frame) :
(&txhdr->body.new.rts_frame));
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
protwh = (struct ieee80211_frame *)
&txhdr->body.r351.rts_frame;
break;
case BWN_FW_HDR_410:
protwh = (struct ieee80211_frame *)
&txhdr->body.r410.rts_frame;
break;
case BWN_FW_HDR_598:
protwh = (struct ieee80211_frame *)
&txhdr->body.r598.rts_frame;
break;
}
txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
if (BWN_ISOFDMRATE(rts_rate)) {
@ -6303,10 +6400,17 @@ bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
txhdr->phyctl_1fb = htole16(bwn_set_txhdr_phyctl1(mac, rate_fb));
}
if (BWN_ISOLDFMT(mac))
txhdr->body.old.cookie = htole16(cookie);
else
txhdr->body.new.cookie = htole16(cookie);
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
txhdr->body.r351.cookie = htole16(cookie);
break;
case BWN_FW_HDR_410:
txhdr->body.r410.cookie = htole16(cookie);
break;
case BWN_FW_HDR_598:
txhdr->body.r598.cookie = htole16(cookie);
break;
}
txhdr->macctl = htole32(macctl);
txhdr->phyctl = htole16(phyctl);
@ -6739,6 +6843,7 @@ bwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
const struct ieee80211_frame_min *wh;
uint64_t tsf;
uint16_t low_mactime_now;
uint16_t mt;
if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
@ -6750,8 +6855,19 @@ bwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
bwn_tsf_read(mac, &tsf);
low_mactime_now = tsf;
tsf = tsf & ~0xffffULL;
tsf += le16toh(rxhdr->mac_time);
if (low_mactime_now < le16toh(rxhdr->mac_time))
switch (mac->mac_fw.fw_hdr_format) {
case BWN_FW_HDR_351:
case BWN_FW_HDR_410:
mt = le16toh(rxhdr->ps4.r351.mac_time);
break;
case BWN_FW_HDR_598:
mt = le16toh(rxhdr->ps4.r598.mac_time);
break;
}
tsf += mt;
if (low_mactime_now < mt)
tsf -= 0x10000;
sc->sc_rx_th.wr_tsf = tsf;

View File

@ -271,10 +271,29 @@ struct bwn_rxhdr4 {
} __packed ht;
uint16_t phy_status2;
} __packed ps2;
uint16_t phy_status3;
uint32_t mac_status;
uint16_t mac_time;
uint16_t channel;
union {
struct {
uint16_t phy_status3;
} __packed lp;
struct {
int8_t phy_ht_power1;
int8_t phy_ht_power2;
} __packed ht;
} __packed ps3;
union {
struct {
uint32_t mac_status;
uint16_t mac_time;
uint16_t channel;
} __packed r351;
struct {
uint16_t phy_status4;
uint16_t phy_status5;
uint32_t mac_status;
uint16_t mac_time;
uint16_t channel;
} __packed r598;
} __packed ps4;
} __packed;
struct bwn_txstatus {
@ -765,8 +784,8 @@ struct bwn_txhdr {
uint8_t rts_frame[16];
uint8_t pad1[2];
struct bwn_plcp6 plcp;
} __packed old;
/* format > r410 */
} __packed r351;
/* format > r410 < r598 */
struct {
uint16_t mimo_antenna;
uint16_t preload_size;
@ -777,7 +796,22 @@ struct bwn_txhdr {
uint8_t rts_frame[16];
uint8_t pad1[2];
struct bwn_plcp6 plcp;
} __packed new;
} __packed r410;
struct {
uint16_t mimo_antenna;
uint16_t preload_size;
uint8_t pad0[2];
uint16_t cookie;
uint16_t tx_status;
uint16_t max_n_mpdus;
uint16_t max_a_bytes_mrt;
uint16_t max_a_bytes_fbr;
uint16_t min_m_bytes;
struct bwn_plcp6 rts_plcp;
uint8_t rts_frame[16];
uint8_t pad1[2];
struct bwn_plcp6 plcp;
} __packed r598;
} __packed body;
} __packed;