Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ral/rt2661.c
Show First 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | |||||
static void rt2661_mcu_cmd_intr(struct rt2661_softc *); | static void rt2661_mcu_cmd_intr(struct rt2661_softc *); | ||||
static void rt2661_scan_start(struct ieee80211com *); | static void rt2661_scan_start(struct ieee80211com *); | ||||
static void rt2661_scan_end(struct ieee80211com *); | static void rt2661_scan_end(struct ieee80211com *); | ||||
static void rt2661_getradiocaps(struct ieee80211com *, int, int *, | static void rt2661_getradiocaps(struct ieee80211com *, int, int *, | ||||
struct ieee80211_channel[]); | struct ieee80211_channel[]); | ||||
static void rt2661_set_channel(struct ieee80211com *); | static void rt2661_set_channel(struct ieee80211com *); | ||||
static void rt2661_setup_tx_desc(struct rt2661_softc *, | static void rt2661_setup_tx_desc(struct rt2661_softc *, | ||||
struct rt2661_tx_desc *, uint32_t, uint16_t, int, | struct rt2661_tx_desc *, uint32_t, uint16_t, int, | ||||
int, const bus_dma_segment_t *, int, int); | const struct ieee80211_rate_t *, | ||||
const bus_dma_segment_t *, int, int); | |||||
static int rt2661_tx_data(struct rt2661_softc *, struct mbuf *, | static int rt2661_tx_data(struct rt2661_softc *, struct mbuf *, | ||||
struct ieee80211_node *, int); | struct ieee80211_node *, int); | ||||
static int rt2661_tx_mgt(struct rt2661_softc *, struct mbuf *, | static int rt2661_tx_mgt(struct rt2661_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int rt2661_transmit(struct ieee80211com *, struct mbuf *); | static int rt2661_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void rt2661_start(struct rt2661_softc *); | static void rt2661_start(struct rt2661_softc *); | ||||
static int rt2661_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int rt2661_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
▲ Show 20 Lines • Show All 753 Lines • ▼ Show 20 Lines | for (;;) { | ||||
switch (RT2661_TX_RESULT(val)) { | switch (RT2661_TX_RESULT(val)) { | ||||
case RT2661_TX_SUCCESS: | case RT2661_TX_SUCCESS: | ||||
txs->status = IEEE80211_RATECTL_TX_SUCCESS; | txs->status = IEEE80211_RATECTL_TX_SUCCESS; | ||||
txs->long_retries = RT2661_TX_RETRYCNT(val); | txs->long_retries = RT2661_TX_RETRYCNT(val); | ||||
DPRINTFN(sc, 10, "data frame sent successfully after " | DPRINTFN(sc, 10, "data frame sent successfully after " | ||||
"%d retries\n", txs->long_retries); | "%d retries\n", txs->long_retries); | ||||
if (data->rix != IEEE80211_FIXED_RATE_NONE) | if (data->submit_to_ratectl) | ||||
ieee80211_ratectl_tx_complete(ni, txs); | ieee80211_ratectl_tx_complete(ni, txs); | ||||
error = 0; | error = 0; | ||||
break; | break; | ||||
case RT2661_TX_RETRY_FAIL: | case RT2661_TX_RETRY_FAIL: | ||||
txs->status = IEEE80211_RATECTL_TX_FAIL_LONG; | txs->status = IEEE80211_RATECTL_TX_FAIL_LONG; | ||||
txs->long_retries = RT2661_TX_RETRYCNT(val); | txs->long_retries = RT2661_TX_RETRYCNT(val); | ||||
DPRINTFN(sc, 9, "%s\n", | DPRINTFN(sc, 9, "%s\n", | ||||
"sending data frame failed (too much retries)"); | "sending data frame failed (too much retries)"); | ||||
if (data->rix != IEEE80211_FIXED_RATE_NONE) | if (data->submit_to_ratectl) | ||||
ieee80211_ratectl_tx_complete(ni, txs); | ieee80211_ratectl_tx_complete(ni, txs); | ||||
error = 1; | error = 1; | ||||
break; | break; | ||||
default: | default: | ||||
/* other failure */ | /* other failure */ | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"sending data frame failed 0x%08x\n", val); | "sending data frame failed 0x%08x\n", val); | ||||
▲ Show 20 Lines • Show All 293 Lines • ▼ Show 20 Lines | rt2661_plcp_signal(int rate) | ||||
case 11: return 0x2; | case 11: return 0x2; | ||||
case 22: return 0x3; | case 22: return 0x3; | ||||
} | } | ||||
return 0xff; /* XXX unsupported/unknown rate */ | return 0xff; /* XXX unsupported/unknown rate */ | ||||
} | } | ||||
static void | static void | ||||
rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc, | rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc, | ||||
uint32_t flags, uint16_t xflags, int len, int rate, | uint32_t flags, uint16_t xflags, int len, | ||||
const bus_dma_segment_t *segs, int nsegs, int ac) | const struct ieee80211_rate_t *rate, const bus_dma_segment_t *segs, | ||||
int nsegs, int ac) | |||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
uint16_t plcp_length; | uint16_t plcp_length; | ||||
int i, remainder; | int i, remainder; | ||||
desc->flags = htole32(flags); | desc->flags = htole32(flags); | ||||
desc->flags |= htole32(len << 16); | desc->flags |= htole32(len << 16); | ||||
desc->flags |= htole32(RT2661_TX_BUSY | RT2661_TX_VALID); | desc->flags |= htole32(RT2661_TX_BUSY | RT2661_TX_VALID); | ||||
Show All 10 Lines | rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc, | ||||
/* | /* | ||||
* Remember in which queue this frame was sent. This field is driver | * Remember in which queue this frame was sent. This field is driver | ||||
* private data only. It will be made available by the NIC in STA_CSR4 | * private data only. It will be made available by the NIC in STA_CSR4 | ||||
* on Tx interrupts. | * on Tx interrupts. | ||||
*/ | */ | ||||
desc->qid = ac; | desc->qid = ac; | ||||
/* setup PLCP fields */ | /* setup PLCP fields */ | ||||
desc->plcp_signal = rt2661_plcp_signal(rate); | desc->plcp_signal = rt2661_plcp_signal(rate->value); | ||||
desc->plcp_service = 4; | desc->plcp_service = 4; | ||||
len += IEEE80211_CRC_LEN; | len += IEEE80211_CRC_LEN; | ||||
if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { | if (rate->type == IEEE80211_T_OFDM) { | ||||
desc->flags |= htole32(RT2661_TX_OFDM); | desc->flags |= htole32(RT2661_TX_OFDM); | ||||
plcp_length = len & 0xfff; | plcp_length = len & 0xfff; | ||||
desc->plcp_length_hi = plcp_length >> 6; | desc->plcp_length_hi = plcp_length >> 6; | ||||
desc->plcp_length_lo = plcp_length & 0x3f; | desc->plcp_length_lo = plcp_length & 0x3f; | ||||
} else { | } else { | ||||
plcp_length = howmany(16 * len, rate); | plcp_length = howmany(16 * len, rate->value); | ||||
if (rate == 22) { | if (rate->value == 22) { | ||||
remainder = (16 * len) % 22; | remainder = (16 * len) % 22; | ||||
if (remainder != 0 && remainder < 7) | if (remainder != 0 && remainder < 7) | ||||
desc->plcp_service |= RT2661_PLCP_LENGEXT; | desc->plcp_service |= RT2661_PLCP_LENGEXT; | ||||
} | } | ||||
desc->plcp_length_hi = plcp_length >> 8; | desc->plcp_length_hi = plcp_length >> 8; | ||||
desc->plcp_length_lo = plcp_length & 0xff; | desc->plcp_length_lo = plcp_length & 0xff; | ||||
if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) | if (rate->props.cck.short_preamble && | ||||
(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) | |||||
desc->plcp_signal |= 0x08; | desc->plcp_signal |= 0x08; | ||||
} | } | ||||
/* RT2x61 supports scatter with up to 5 segments */ | /* RT2x61 supports scatter with up to 5 segments */ | ||||
for (i = 0; i < nsegs; i++) { | for (i = 0; i < nsegs; i++) { | ||||
desc->addr[i] = htole32(segs[i].ds_addr); | desc->addr[i] = htole32(segs[i].ds_addr); | ||||
desc->len [i] = htole16(segs[i].ds_len); | desc->len [i] = htole16(segs[i].ds_len); | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0, | rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0, | ||||
struct ieee80211_node *ni) | struct ieee80211_node *ni) | ||||
{ | { | ||||
const struct ieee80211_rate_t *rate; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct rt2661_tx_desc *desc; | struct rt2661_tx_desc *desc; | ||||
struct rt2661_tx_data *data; | struct rt2661_tx_data *data; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
bus_dma_segment_t segs[RT2661_MAX_SCATTER]; | bus_dma_segment_t segs[RT2661_MAX_SCATTER]; | ||||
uint16_t dur; | uint16_t dur; | ||||
uint32_t flags = 0; /* XXX HWSEQ */ | uint32_t flags = 0; /* XXX HWSEQ */ | ||||
int nsegs, rate, error; | int nsegs, error; | ||||
desc = &sc->mgtq.desc[sc->mgtq.cur]; | desc = &sc->mgtq.desc[sc->mgtq.cur]; | ||||
data = &sc->mgtq.data[sc->mgtq.cur]; | data = &sc->mgtq.data[sc->mgtq.cur]; | ||||
rate = ni->ni_txparms->mgmtrate; | rate = ieee80211_get_rate(ni->ni_txparms->mgmtrate); | ||||
wh = mtod(m0, struct ieee80211_frame *); | wh = mtod(m0, struct ieee80211_frame *); | ||||
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | ||||
k = ieee80211_crypto_encap(ni, m0); | k = ieee80211_crypto_encap(ni, m0); | ||||
if (k == NULL) { | if (k == NULL) { | ||||
m_freem(m0); | m_freem(m0); | ||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
} | } | ||||
error = bus_dmamap_load_mbuf_sg(sc->mgtq.data_dmat, data->map, m0, | error = bus_dmamap_load_mbuf_sg(sc->mgtq.data_dmat, data->map, m0, | ||||
segs, &nsegs, 0); | segs, &nsegs, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", | device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", | ||||
error); | error); | ||||
m_freem(m0); | m_freem(m0); | ||||
return error; | return error; | ||||
} | } | ||||
if (ieee80211_radiotap_active_vap(vap)) { | if (ieee80211_radiotap_active_vap(vap)) { | ||||
struct rt2661_tx_radiotap_header *tap = &sc->sc_txtap; | struct rt2661_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
ieee80211_radiotap_tx(vap, m0); | ieee80211_radiotap_tx(vap, m0); | ||||
} | } | ||||
data->m = m0; | data->m = m0; | ||||
data->ni = ni; | data->ni = ni; | ||||
/* management frames are not taken into account for amrr */ | /* management frames are not taken into account for amrr */ | ||||
data->rix = IEEE80211_FIXED_RATE_NONE; | data->submit_to_ratectl = 0; | ||||
wh = mtod(m0, struct ieee80211_frame *); | wh = mtod(m0, struct ieee80211_frame *); | ||||
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { | ||||
flags |= RT2661_TX_NEED_ACK; | flags |= RT2661_TX_NEED_ACK; | ||||
dur = ieee80211_ack_duration(ic->ic_rt, | dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, | ||||
rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); | ni->ni_txparms->mgmtrate, | ||||
ic->ic_flags & IEEE80211_F_SHPREAMBLE); | |||||
*(uint16_t *)wh->i_dur = htole16(dur); | *(uint16_t *)wh->i_dur = htole16(dur); | ||||
/* tell hardware to add timestamp in probe responses */ | /* tell hardware to add timestamp in probe responses */ | ||||
if ((wh->i_fc[0] & | if ((wh->i_fc[0] & | ||||
(IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == | (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == | ||||
(IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) | (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) | ||||
flags |= RT2661_TX_TIMESTAMP; | flags |= RT2661_TX_TIMESTAMP; | ||||
} | } | ||||
rt2661_setup_tx_desc(sc, desc, flags, 0 /* XXX HWSEQ */, | rt2661_setup_tx_desc(sc, desc, flags, 0 /* XXX HWSEQ */, | ||||
m0->m_pkthdr.len, rate, segs, nsegs, RT2661_QID_MGT); | m0->m_pkthdr.len, rate, segs, nsegs, RT2661_QID_MGT); | ||||
bus_dmamap_sync(sc->mgtq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(sc->mgtq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | ||||
bus_dmamap_sync(sc->mgtq.desc_dmat, sc->mgtq.desc_map, | bus_dmamap_sync(sc->mgtq.desc_dmat, sc->mgtq.desc_map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", | DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u/%u\n", | ||||
m0->m_pkthdr.len, sc->mgtq.cur, rate); | m0->m_pkthdr.len, sc->mgtq.cur, rate->type, rate->value); | ||||
/* kick mgt */ | /* kick mgt */ | ||||
sc->mgtq.queued++; | sc->mgtq.queued++; | ||||
sc->mgtq.cur = (sc->mgtq.cur + 1) % RT2661_MGT_RING_COUNT; | sc->mgtq.cur = (sc->mgtq.cur + 1) % RT2661_MGT_RING_COUNT; | ||||
RAL_WRITE(sc, RT2661_TX_CNTL_CSR, RT2661_KICK_MGT); | RAL_WRITE(sc, RT2661_TX_CNTL_CSR, RT2661_KICK_MGT); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
rt2661_sendprot(struct rt2661_softc *sc, int ac, | rt2661_sendprot(struct rt2661_softc *sc, int ac, | ||||
const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) | const struct mbuf *m, struct ieee80211_node *ni, int prot, | ||||
uint16_t rate_idx) | |||||
{ | { | ||||
const struct ieee80211_rate_t *protrate; | |||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct rt2661_tx_ring *txq = &sc->txq[ac]; | struct rt2661_tx_ring *txq = &sc->txq[ac]; | ||||
struct rt2661_tx_desc *desc; | struct rt2661_tx_desc *desc; | ||||
struct rt2661_tx_data *data; | struct rt2661_tx_data *data; | ||||
struct mbuf *mprot; | struct mbuf *mprot; | ||||
int protrate, flags, error; | int flags, error; | ||||
bus_dma_segment_t segs[RT2661_MAX_SCATTER]; | bus_dma_segment_t segs[RT2661_MAX_SCATTER]; | ||||
int nsegs; | int nsegs; | ||||
mprot = ieee80211_alloc_prot(ni, m, rate, prot); | mprot = ieee80211_alloc_prot(ni, m, rate_idx, prot); | ||||
if (mprot == NULL) { | if (mprot == NULL) { | ||||
if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"could not allocate mbuf for protection mode %d\n", prot); | "could not allocate mbuf for protection mode %d\n", prot); | ||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
data = &txq->data[txq->cur]; | data = &txq->data[txq->cur]; | ||||
desc = &txq->desc[txq->cur]; | desc = &txq->desc[txq->cur]; | ||||
error = bus_dmamap_load_mbuf_sg(txq->data_dmat, data->map, mprot, segs, | error = bus_dmamap_load_mbuf_sg(txq->data_dmat, data->map, mprot, segs, | ||||
&nsegs, 0); | &nsegs, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"could not map mbuf (error %d)\n", error); | "could not map mbuf (error %d)\n", error); | ||||
m_freem(mprot); | m_freem(mprot); | ||||
return error; | return error; | ||||
} | } | ||||
data->m = mprot; | data->m = mprot; | ||||
data->ni = ieee80211_ref_node(ni); | data->ni = ieee80211_ref_node(ni); | ||||
/* ctl frames are not taken into account for amrr */ | /* ctl frames are not taken into account for amrr */ | ||||
data->rix = IEEE80211_FIXED_RATE_NONE; | data->submit_to_ratectl = 0; | ||||
protrate = ieee80211_ctl_rate(ic->ic_rt, rate); | protrate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); | ||||
flags = RT2661_TX_MORE_FRAG; | flags = RT2661_TX_MORE_FRAG; | ||||
if (prot == IEEE80211_PROT_RTSCTS) | if (prot == IEEE80211_PROT_RTSCTS) | ||||
flags |= RT2661_TX_NEED_ACK; | flags |= RT2661_TX_NEED_ACK; | ||||
rt2661_setup_tx_desc(sc, desc, flags, 0, mprot->m_pkthdr.len, | rt2661_setup_tx_desc(sc, desc, flags, 0, mprot->m_pkthdr.len, | ||||
protrate, segs, 1, ac); | protrate, segs, 1, ac); | ||||
bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE); | ||||
bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE); | ||||
txq->queued++; | txq->queued++; | ||||
txq->cur = (txq->cur + 1) % RT2661_TX_RING_COUNT; | txq->cur = (txq->cur + 1) % RT2661_TX_RING_COUNT; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0, | rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0, | ||||
struct ieee80211_node *ni, int ac) | struct ieee80211_node *ni, int ac) | ||||
{ | { | ||||
const struct ieee80211_rate_t *rate; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct rt2661_tx_ring *txq = &sc->txq[ac]; | struct rt2661_tx_ring *txq = &sc->txq[ac]; | ||||
struct rt2661_tx_desc *desc; | struct rt2661_tx_desc *desc; | ||||
struct rt2661_tx_data *data; | struct rt2661_tx_data *data; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
const struct ieee80211_txparam *tp = ni->ni_txparms; | const struct ieee80211_txparam_vht *tp = ni->ni_txparms; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
struct mbuf *mnew; | struct mbuf *mnew; | ||||
bus_dma_segment_t segs[RT2661_MAX_SCATTER]; | bus_dma_segment_t segs[RT2661_MAX_SCATTER]; | ||||
uint16_t dur; | uint16_t dur, rate_idx; | ||||
uint32_t flags; | uint32_t flags; | ||||
int error, nsegs, rate, noack = 0; | int error, nsegs, noack = 0; | ||||
wh = mtod(m0, struct ieee80211_frame *); | wh = mtod(m0, struct ieee80211_frame *); | ||||
if (m0->m_flags & M_EAPOL) { | if (m0->m_flags & M_EAPOL) { | ||||
rate = tp->mgmtrate; | rate_idx = tp->mgmtrate; | ||||
} else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { | } else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { | ||||
rate = tp->mcastrate; | rate_idx = tp->mcastrate; | ||||
} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { | } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { | ||||
rate = tp->ucastrate; | rate_idx = tp->ucastrate; | ||||
} else { | } else { | ||||
(void) ieee80211_ratectl_rate(ni, NULL, 0); | (void) ieee80211_ratectl_rate(ni, NULL, 0); | ||||
rate = ni->ni_txrate; | rate_idx = ni->ni_txrate; | ||||
} | } | ||||
rate &= IEEE80211_RATE_VAL; | rate = ieee80211_get_rate(rate_idx); | ||||
if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) | if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) | ||||
noack = !! ieee80211_wme_vap_ac_is_noack(vap, ac); | noack = !! ieee80211_wme_vap_ac_is_noack(vap, ac); | ||||
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | ||||
k = ieee80211_crypto_encap(ni, m0); | k = ieee80211_crypto_encap(ni, m0); | ||||
if (k == NULL) { | if (k == NULL) { | ||||
m_freem(m0); | m_freem(m0); | ||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
/* packet header may have moved, reset our local pointer */ | /* packet header may have moved, reset our local pointer */ | ||||
wh = mtod(m0, struct ieee80211_frame *); | wh = mtod(m0, struct ieee80211_frame *); | ||||
} | } | ||||
flags = 0; | flags = 0; | ||||
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { | ||||
int prot = IEEE80211_PROT_NONE; | int prot = IEEE80211_PROT_NONE; | ||||
if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) | if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > | ||||
vap->iv_rtsthreshold) | |||||
prot = IEEE80211_PROT_RTSCTS; | prot = IEEE80211_PROT_RTSCTS; | ||||
else if ((ic->ic_flags & IEEE80211_F_USEPROT) && | else if ((ic->ic_flags & IEEE80211_F_USEPROT) && | ||||
ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) | rate->type == IEEE80211_T_OFDM) | ||||
prot = ic->ic_protmode; | prot = ic->ic_protmode; | ||||
if (prot != IEEE80211_PROT_NONE) { | if (prot != IEEE80211_PROT_NONE) { | ||||
error = rt2661_sendprot(sc, ac, m0, ni, prot, rate); | error = rt2661_sendprot(sc, ac, m0, ni, prot, | ||||
rate_idx); | |||||
if (error) { | if (error) { | ||||
m_freem(m0); | m_freem(m0); | ||||
return error; | return error; | ||||
} | } | ||||
flags |= RT2661_TX_LONG_RETRY | RT2661_TX_IFS; | flags |= RT2661_TX_LONG_RETRY | RT2661_TX_IFS; | ||||
} | } | ||||
} | } | ||||
Show All 30 Lines | if (error != 0) { | ||||
/* packet header have moved, reset our local pointer */ | /* packet header have moved, reset our local pointer */ | ||||
wh = mtod(m0, struct ieee80211_frame *); | wh = mtod(m0, struct ieee80211_frame *); | ||||
} | } | ||||
if (ieee80211_radiotap_active_vap(vap)) { | if (ieee80211_radiotap_active_vap(vap)) { | ||||
struct rt2661_tx_radiotap_header *tap = &sc->sc_txtap; | struct rt2661_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
ieee80211_radiotap_tx(vap, m0); | ieee80211_radiotap_tx(vap, m0); | ||||
} | } | ||||
data->m = m0; | data->m = m0; | ||||
data->ni = ni; | data->ni = ni; | ||||
/* remember link conditions for rate adaptation algorithm */ | /* remember link conditions for rate adaptation algorithm */ | ||||
if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { | if (tp->ucastrate == IEEE80211_RATE_NONEXISTENT) { | ||||
data->rix = ni->ni_txrate; | data->submit_to_ratectl = 1; | ||||
/* XXX probably need last rssi value and not avg */ | /* XXX probably need last rssi value and not avg */ | ||||
data->rssi = ic->ic_node_getrssi(ni); | data->rssi = ic->ic_node_getrssi(ni); | ||||
} else | } else | ||||
data->rix = IEEE80211_FIXED_RATE_NONE; | data->submit_to_ratectl = 0; | ||||
if (!noack && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { | if (!noack && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { | ||||
flags |= RT2661_TX_NEED_ACK; | flags |= RT2661_TX_NEED_ACK; | ||||
dur = ieee80211_ack_duration(ic->ic_rt, | dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, | ||||
rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); | rate_idx, ic->ic_flags & IEEE80211_F_SHPREAMBLE); | ||||
*(uint16_t *)wh->i_dur = htole16(dur); | *(uint16_t *)wh->i_dur = htole16(dur); | ||||
} | } | ||||
rt2661_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate, segs, | rt2661_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate, segs, | ||||
nsegs, ac); | nsegs, ac); | ||||
bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE); | ||||
bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE); | ||||
DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", | DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u/%u\n", | ||||
m0->m_pkthdr.len, txq->cur, rate); | m0->m_pkthdr.len, txq->cur, rate->type, rate->value); | ||||
/* kick Tx */ | /* kick Tx */ | ||||
txq->queued++; | txq->queued++; | ||||
txq->cur = (txq->cur + 1) % RT2661_TX_RING_COUNT; | txq->cur = (txq->cur + 1) % RT2661_TX_RING_COUNT; | ||||
RAL_WRITE(sc, RT2661_TX_CNTL_CSR, 1 << ac); | RAL_WRITE(sc, RT2661_TX_CNTL_CSR, 1 << ac); | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 281 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
rt2661_set_basicrates(struct rt2661_softc *sc, | rt2661_set_basicrates(struct rt2661_softc *sc, | ||||
const struct ieee80211_rateset *rs) | const struct ieee80211_rateset *rs) | ||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
uint32_t mask = 0; | uint32_t mask = 0; | ||||
uint8_t rate; | |||||
int i; | int i; | ||||
for (i = 0; i < rs->rs_nrates; i++) { | for (i = 0; i < rs->rs_nrates; i++) { | ||||
rate = rs->rs_rates[i]; | if (!rs->rates[i].rs_basic) | ||||
if (!(rate & IEEE80211_RATE_BASIC)) | |||||
continue; | continue; | ||||
mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, | mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt->ctl_rates, | ||||
IEEE80211_RV(rate)); | rs->rates[i].rs_index); | ||||
} | } | ||||
RAL_WRITE(sc, RT2661_TXRX_CSR5, mask); | RAL_WRITE(sc, RT2661_TXRX_CSR5, mask); | ||||
DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); | DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 740 Lines • ▼ Show 20 Lines | rt2661_radar_stop(struct rt2661_softc *sc) | ||||
return bbp66 == 1; | return bbp66 == 1; | ||||
} | } | ||||
#endif | #endif | ||||
static int | static int | ||||
rt2661_prepare_beacon(struct rt2661_softc *sc, struct ieee80211vap *vap) | rt2661_prepare_beacon(struct rt2661_softc *sc, struct ieee80211vap *vap) | ||||
{ | { | ||||
const struct ieee80211_rate_t *rate; | |||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct rt2661_tx_desc desc; | struct rt2661_tx_desc desc; | ||||
struct mbuf *m0; | struct mbuf *m0; | ||||
int rate; | |||||
if ((m0 = ieee80211_beacon_alloc(vap->iv_bss))== NULL) { | if ((m0 = ieee80211_beacon_alloc(vap->iv_bss))== NULL) { | ||||
device_printf(sc->sc_dev, "could not allocate beacon frame\n"); | device_printf(sc->sc_dev, "could not allocate beacon frame\n"); | ||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
/* send beacons at the lowest available rate */ | /* send beacons at the lowest available rate */ | ||||
rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan) ? 12 : 2; | if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) | ||||
rate = ieee80211_get_rate(IEEE80211_RATE_INDEX_OFDM6); | |||||
else | |||||
rate = ieee80211_get_rate(IEEE80211_RATE_INDEX_CCK1); | |||||
rt2661_setup_tx_desc(sc, &desc, RT2661_TX_TIMESTAMP, RT2661_TX_HWSEQ, | rt2661_setup_tx_desc(sc, &desc, RT2661_TX_TIMESTAMP, RT2661_TX_HWSEQ, | ||||
m0->m_pkthdr.len, rate, NULL, 0, RT2661_QID_MGT); | m0->m_pkthdr.len, rate, NULL, 0, RT2661_QID_MGT); | ||||
/* copy the first 24 bytes of Tx descriptor into NIC memory */ | /* copy the first 24 bytes of Tx descriptor into NIC memory */ | ||||
RAL_WRITE_REGION_1(sc, RT2661_HW_BEACON_BASE0, (uint8_t *)&desc, 24); | RAL_WRITE_REGION_1(sc, RT2661_HW_BEACON_BASE0, (uint8_t *)&desc, 24); | ||||
/* copy beacon header and payload into NIC memory */ | /* copy beacon header and payload into NIC memory */ | ||||
▲ Show 20 Lines • Show All 149 Lines • Show Last 20 Lines |