Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/otus/if_otus.c
Show First 20 Lines • Show All 2,080 Lines • ▼ Show 20 Lines | default: /* Error */ | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Map net80211 rate to hw rate for otus MAC/PHY. | * Map net80211 rate to hw rate for otus MAC/PHY. | ||||
*/ | */ | ||||
static uint8_t | static uint8_t | ||||
otus_rate_to_hw_rate(struct otus_softc *sc, uint8_t rate) | otus_rate_to_hw_rate(struct otus_softc *sc, | ||||
const struct ieee80211_rate_t *rate) | |||||
{ | { | ||||
int is_2ghz; | int is_2ghz; | ||||
is_2ghz = !! (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)); | switch (rate->type) { | ||||
case IEEE80211_T_HT: | |||||
switch (rate) { | /* TODO */ | ||||
/* CCK */ | break; | ||||
case 2: | case IEEE80211_T_OFDM: | ||||
return (0x0); | switch (rate->value) { | ||||
case 4: | case 12: return (0xb); | ||||
return (0x1); | case 18: return (0xf); | ||||
case 11: | case 24: return (0xa); | ||||
return (0x2); | case 36: return (0xe); | ||||
case 22: | case 48: return (0x9); | ||||
return (0x3); | case 72: return (0xd); | ||||
/* OFDM */ | case 96: return (0x8); | ||||
case 12: | case 108: return (0xc); | ||||
return (0xb); | |||||
case 18: | |||||
return (0xf); | |||||
case 24: | |||||
return (0xa); | |||||
case 36: | |||||
return (0xe); | |||||
case 48: | |||||
return (0x9); | |||||
case 72: | |||||
return (0xd); | |||||
case 96: | |||||
return (0x8); | |||||
case 108: | |||||
return (0xc); | |||||
default: | default: | ||||
device_printf(sc->sc_dev, "%s: unknown rate '%d'\n", | break; | ||||
__func__, (int) rate); | |||||
case 0: | |||||
if (is_2ghz) | |||||
return (0x0); /* 1MB CCK */ | |||||
else | |||||
return (0xb); /* 6MB OFDM */ | |||||
/* XXX TODO: HT */ | |||||
} | } | ||||
case IEEE80211_T_CCK: | |||||
switch (rate->value) { | |||||
case 2: return (0x0); | |||||
case 4: return (0x1); | |||||
case 11: return (0x2); | |||||
case 22: return (0x3); | |||||
default: | |||||
break; | |||||
} | } | ||||
static int | |||||
otus_hw_rate_is_ofdm(struct otus_softc *sc, uint8_t hw_rate) | |||||
{ | |||||
switch (hw_rate) { | |||||
case 0x0: | |||||
case 0x1: | |||||
case 0x2: | |||||
case 0x3: | |||||
return (0); | |||||
default: | default: | ||||
return (1); | break; | ||||
} | } | ||||
} | |||||
device_printf(sc->sc_dev, "%s: unknown rate '%u/%u'\n", | |||||
__func__, rate->type, rate->value); | |||||
is_2ghz = !! (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)); | |||||
if (is_2ghz) | |||||
return (0x0); /* 1MB CCK */ | |||||
else | |||||
return (0xb); /* 6MB OFDM */ | |||||
} | |||||
static void | static void | ||||
otus_tx_update_ratectl(struct otus_softc *sc, struct ieee80211_node *ni) | otus_tx_update_ratectl(struct otus_softc *sc, struct ieee80211_node *ni) | ||||
{ | { | ||||
struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs; | struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs; | ||||
struct otus_node *on = OTUS_NODE(ni); | struct otus_node *on = OTUS_NODE(ni); | ||||
txs->flags = IEEE80211_RATECTL_TX_STATS_NODE | | txs->flags = IEEE80211_RATECTL_TX_STATS_NODE | | ||||
IEEE80211_RATECTL_TX_STATS_RETRIES; | IEEE80211_RATECTL_TX_STATS_RETRIES; | ||||
Show All 18 Lines | |||||
* params->ibp_flags & IEEE80211_BPF_CTS | * params->ibp_flags & IEEE80211_BPF_CTS | ||||
* tx->rts_ntries = params->ibp_try1; | * tx->rts_ntries = params->ibp_try1; | ||||
* tx->data_ntries = params->ibp_try0; | * tx->data_ntries = params->ibp_try0; | ||||
*/ | */ | ||||
static int | static int | ||||
otus_tx(struct otus_softc *sc, struct ieee80211_node *ni, struct mbuf *m, | otus_tx(struct otus_softc *sc, struct ieee80211_node *ni, struct mbuf *m, | ||||
struct otus_data *data, const struct ieee80211_bpf_params *params) | struct otus_data *data, const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
const struct ieee80211_txparam *tp = ni->ni_txparms; | const struct ieee80211_txparam_vht *tp = ni->ni_txparms; | ||||
const struct ieee80211_rate_t *rate; | |||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
struct ar_tx_head *head; | struct ar_tx_head *head; | ||||
uint32_t phyctl; | uint32_t phyctl; | ||||
uint16_t macctl, qos; | uint16_t macctl, qos, rate_idx; | ||||
uint8_t qid, rate; | uint8_t qid, hw_rate; | ||||
int hasqos, xferlen, type, ismcast; | int hasqos, xferlen, type, ismcast; | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | ||||
k = ieee80211_crypto_encap(ni, m); | k = ieee80211_crypto_encap(ni, m); | ||||
if (k == NULL) { | if (k == NULL) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: m=%p: ieee80211_crypto_encap returns NULL\n", | "%s: m=%p: ieee80211_crypto_encap returns NULL\n", | ||||
Show All 27 Lines | if (hasqos) { | ||||
qid = WME_AC_BE; | qid = WME_AC_BE; | ||||
} | } | ||||
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | ||||
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); | ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); | ||||
/* Pickup a rate index. */ | /* Pickup a rate index. */ | ||||
if (params != NULL) | if (params != NULL) | ||||
rate = otus_rate_to_hw_rate(sc, params->ibp_rate0); | rate_idx = params->ibp_rate0; | ||||
else if (!!(m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA) | else if (!!(m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA) | ||||
rate = otus_rate_to_hw_rate(sc, tp->mgmtrate); | rate_idx = tp->mgmtrate; | ||||
else if (ismcast) | else if (ismcast) | ||||
rate = otus_rate_to_hw_rate(sc, tp->mcastrate); | rate_idx = tp->mcastrate; | ||||
else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) | else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) | ||||
rate = otus_rate_to_hw_rate(sc, tp->ucastrate); | rate_idx = tp->ucastrate; | ||||
else { | else { | ||||
(void) ieee80211_ratectl_rate(ni, NULL, 0); | (void) ieee80211_ratectl_rate(ni, NULL, 0); | ||||
rate = otus_rate_to_hw_rate(sc, ni->ni_txrate); | rate_idx = ni->ni_txrate; | ||||
} | } | ||||
rate = ieee80211_get_rate(rate_idx); | |||||
hw_rate = otus_rate_to_hw_rate(sc, rate); | |||||
phyctl = 0; | phyctl = 0; | ||||
macctl = AR_TX_MAC_BACKOFF | AR_TX_MAC_HW_DUR | AR_TX_MAC_QID(qid); | macctl = AR_TX_MAC_BACKOFF | AR_TX_MAC_HW_DUR | AR_TX_MAC_QID(qid); | ||||
/* | /* | ||||
* XXX TODO: params for NOACK, ACK, RTS, CTS, etc | * XXX TODO: params for NOACK, ACK, RTS, CTS, etc | ||||
*/ | */ | ||||
if (ismcast || | if (ismcast || | ||||
(hasqos && ((qos & IEEE80211_QOS_ACKPOLICY) == | (hasqos && ((qos & IEEE80211_QOS_ACKPOLICY) == | ||||
IEEE80211_QOS_ACKPOLICY_NOACK))) | IEEE80211_QOS_ACKPOLICY_NOACK))) | ||||
macctl |= AR_TX_MAC_NOACK; | macctl |= AR_TX_MAC_NOACK; | ||||
if (!ismcast) { | if (!ismcast) { | ||||
if (m->m_pkthdr.len + IEEE80211_CRC_LEN >= vap->iv_rtsthreshold) | if (m->m_pkthdr.len + IEEE80211_CRC_LEN >= vap->iv_rtsthreshold) | ||||
macctl |= AR_TX_MAC_RTS; | macctl |= AR_TX_MAC_RTS; | ||||
else if (ic->ic_flags & IEEE80211_F_USEPROT) { | else if (ic->ic_flags & IEEE80211_F_USEPROT) { | ||||
if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) | ||||
macctl |= AR_TX_MAC_CTS; | macctl |= AR_TX_MAC_CTS; | ||||
else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) | else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) | ||||
macctl |= AR_TX_MAC_RTS; | macctl |= AR_TX_MAC_RTS; | ||||
} | } | ||||
} | } | ||||
phyctl |= AR_TX_PHY_MCS(rate); | phyctl |= AR_TX_PHY_MCS(hw_rate); | ||||
if (otus_hw_rate_is_ofdm(sc, rate)) { | if (rate->type == IEEE80211_T_OFDM) { | ||||
phyctl |= AR_TX_PHY_MT_OFDM; | phyctl |= AR_TX_PHY_MT_OFDM; | ||||
/* Always use all tx antennas for now, just to be safe */ | /* Always use all tx antennas for now, just to be safe */ | ||||
phyctl |= AR_TX_PHY_ANTMSK(sc->txmask); | phyctl |= AR_TX_PHY_ANTMSK(sc->txmask); | ||||
} else { /* CCK */ | } else { /* CCK */ | ||||
phyctl |= AR_TX_PHY_MT_CCK; | phyctl |= AR_TX_PHY_MT_CCK; | ||||
phyctl |= AR_TX_PHY_ANTMSK(sc->txmask); | phyctl |= AR_TX_PHY_ANTMSK(sc->txmask); | ||||
} | } | ||||
Show All 13 Lines | otus_tx(struct otus_softc *sc, struct ieee80211_node *ni, struct mbuf *m, | ||||
m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&head[1]); | m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&head[1]); | ||||
data->buflen = xferlen; | data->buflen = xferlen; | ||||
data->ni = ni; | data->ni = ni; | ||||
data->m = m; | data->m = m; | ||||
OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, | OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, | ||||
"%s: tx: m=%p; data=%p; len=%d mac=0x%04x phy=0x%08x rate=0x%02x, ni_txrate=%d\n", | "%s: tx: m=%p; data=%p; len=%d mac=0x%04x phy=0x%08x " | ||||
__func__, m, data, le16toh(head->len), macctl, phyctl, | "rate=%u/0x%02x\n", __func__, m, data, le16toh(head->len), | ||||
(int) rate, (int) ni->ni_txrate); | macctl, phyctl, rate->type, rate->value); | ||||
/* Submit transfer */ | /* Submit transfer */ | ||||
STAILQ_INSERT_TAIL(&sc->sc_tx_pending[OTUS_BULK_TX], data, next); | STAILQ_INSERT_TAIL(&sc->sc_tx_pending[OTUS_BULK_TX], data, next); | ||||
usbd_transfer_start(sc->sc_xfer[OTUS_BULK_TX]); | usbd_transfer_start(sc->sc_xfer[OTUS_BULK_TX]); | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 931 Lines • Show Last 20 Lines |