Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ral/rt2560.c
Show First 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | |||||
static void rt2560_beacon_expire(struct rt2560_softc *); | static void rt2560_beacon_expire(struct rt2560_softc *); | ||||
static void rt2560_wakeup_expire(struct rt2560_softc *); | static void rt2560_wakeup_expire(struct rt2560_softc *); | ||||
static void rt2560_scan_start(struct ieee80211com *); | static void rt2560_scan_start(struct ieee80211com *); | ||||
static void rt2560_scan_end(struct ieee80211com *); | static void rt2560_scan_end(struct ieee80211com *); | ||||
static void rt2560_getradiocaps(struct ieee80211com *, int, int *, | static void rt2560_getradiocaps(struct ieee80211com *, int, int *, | ||||
struct ieee80211_channel[]); | struct ieee80211_channel[]); | ||||
static void rt2560_set_channel(struct ieee80211com *); | static void rt2560_set_channel(struct ieee80211com *); | ||||
static void rt2560_setup_tx_desc(struct rt2560_softc *, | static void rt2560_setup_tx_desc(struct rt2560_softc *, | ||||
struct rt2560_tx_desc *, uint32_t, int, int, int, | struct rt2560_tx_desc *, uint32_t, int, | ||||
bus_addr_t); | const struct ieee80211_rate_t *, int, bus_addr_t); | ||||
static int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, | static int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, | static int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, | static int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int rt2560_transmit(struct ieee80211com *, struct mbuf *); | static int rt2560_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void rt2560_start(struct rt2560_softc *); | static void rt2560_start(struct rt2560_softc *); | ||||
▲ Show 20 Lines • Show All 803 Lines • ▼ Show 20 Lines | for (;;) { | ||||
ni = data->ni; | ni = data->ni; | ||||
switch (flags & RT2560_TX_RESULT_MASK) { | switch (flags & RT2560_TX_RESULT_MASK) { | ||||
case RT2560_TX_SUCCESS: | case RT2560_TX_SUCCESS: | ||||
txs->status = IEEE80211_RATECTL_TX_SUCCESS; | txs->status = IEEE80211_RATECTL_TX_SUCCESS; | ||||
txs->long_retries = 0; | txs->long_retries = 0; | ||||
DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); | DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); | ||||
if (data->rix != IEEE80211_FIXED_RATE_NONE) | if (data->submit_to_ratectl) | ||||
ieee80211_ratectl_tx_complete(ni, txs); | ieee80211_ratectl_tx_complete(ni, txs); | ||||
status = 0; | status = 0; | ||||
break; | break; | ||||
case RT2560_TX_SUCCESS_RETRY: | case RT2560_TX_SUCCESS_RETRY: | ||||
txs->status = IEEE80211_RATECTL_TX_SUCCESS; | txs->status = IEEE80211_RATECTL_TX_SUCCESS; | ||||
txs->long_retries = RT2560_TX_RETRYCNT(flags); | txs->long_retries = RT2560_TX_RETRYCNT(flags); | ||||
DPRINTFN(sc, 9, "data frame sent after %u retries\n", | DPRINTFN(sc, 9, "data frame sent after %u retries\n", | ||||
txs->long_retries); | 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); | ||||
status = 0; | status = 0; | ||||
break; | break; | ||||
case RT2560_TX_FAIL_RETRY: | case RT2560_TX_FAIL_RETRY: | ||||
txs->status = IEEE80211_RATECTL_TX_FAIL_LONG; | txs->status = IEEE80211_RATECTL_TX_FAIL_LONG; | ||||
txs->long_retries = RT2560_TX_RETRYCNT(flags); | txs->long_retries = RT2560_TX_RETRYCNT(flags); | ||||
DPRINTFN(sc, 9, "data frame failed after %d retries\n", | DPRINTFN(sc, 9, "data frame failed after %d retries\n", | ||||
txs->long_retries); | 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); | ||||
status = 1; | status = 1; | ||||
break; | break; | ||||
case RT2560_TX_FAIL_INVALID: | case RT2560_TX_FAIL_INVALID: | ||||
case RT2560_TX_FAIL_OTHER: | case RT2560_TX_FAIL_OTHER: | ||||
default: | default: | ||||
device_printf(sc->sc_dev, "sending data frame failed " | device_printf(sc->sc_dev, "sending data frame failed " | ||||
▲ Show 20 Lines • Show All 420 Lines • ▼ Show 20 Lines | rt2560_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 | ||||
rt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, | rt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, | ||||
uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) | uint32_t flags, int len, const struct ieee80211_rate_t *rate, int encrypt, | ||||
bus_addr_t physaddr) | |||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
uint16_t plcp_length; | uint16_t plcp_length; | ||||
int remainder; | int remainder; | ||||
desc->flags = htole32(flags); | desc->flags = htole32(flags); | ||||
desc->flags |= htole32(len << 16); | desc->flags |= htole32(len << 16); | ||||
desc->physaddr = htole32(physaddr); | desc->physaddr = htole32(physaddr); | ||||
desc->wme = htole16( | desc->wme = htole16( | ||||
RT2560_AIFSN(2) | | RT2560_AIFSN(2) | | ||||
RT2560_LOGCWMIN(3) | | RT2560_LOGCWMIN(3) | | ||||
RT2560_LOGCWMAX(8)); | RT2560_LOGCWMAX(8)); | ||||
/* setup PLCP fields */ | /* setup PLCP fields */ | ||||
desc->plcp_signal = rt2560_plcp_signal(rate); | desc->plcp_signal = rt2560_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(RT2560_TX_OFDM); | desc->flags |= htole32(RT2560_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 |= RT2560_PLCP_LENGEXT; | desc->plcp_service |= RT2560_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; | ||||
} | } | ||||
if (!encrypt) | if (!encrypt) | ||||
desc->flags |= htole32(RT2560_TX_VALID); | desc->flags |= htole32(RT2560_TX_VALID); | ||||
desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) | desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) | ||||
: htole32(RT2560_TX_BUSY); | : htole32(RT2560_TX_BUSY); | ||||
} | } | ||||
static int | static int | ||||
rt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, | rt2560_tx_bcn(struct rt2560_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 rt2560_tx_desc *desc; | struct rt2560_tx_desc *desc; | ||||
struct rt2560_tx_data *data; | struct rt2560_tx_data *data; | ||||
bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | ||||
int nsegs, rate, error; | int nsegs, error; | ||||
desc = &sc->bcnq.desc[sc->bcnq.cur]; | desc = &sc->bcnq.desc[sc->bcnq.cur]; | ||||
data = &sc->bcnq.data[sc->bcnq.cur]; | data = &sc->bcnq.data[sc->bcnq.cur]; | ||||
/* XXX maybe a separate beacon rate? */ | /* XXX maybe a separate beacon rate? */ | ||||
rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; | rate = ieee80211_get_rate(ni->ni_txparms->mgmtrate); | ||||
error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, | error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, | ||||
segs, &nsegs, BUS_DMA_NOWAIT); | segs, &nsegs, BUS_DMA_NOWAIT); | ||||
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 rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
tap->wt_antenna = sc->tx_ant; | tap->wt_antenna = sc->tx_ant; | ||||
ieee80211_radiotap_tx(vap, m0); | ieee80211_radiotap_tx(vap, m0); | ||||
} | } | ||||
data->m = m0; | data->m = m0; | ||||
data->ni = ni; | data->ni = ni; | ||||
rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | | rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | | ||||
RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); | RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); | ||||
DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", | DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u/%u\n", | ||||
m0->m_pkthdr.len, sc->bcnq.cur, rate); | m0->m_pkthdr.len, sc->bcnq.cur, rate->type, rate->value); | ||||
bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | ||||
bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, | bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; | sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, | rt2560_tx_mgt(struct rt2560_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 rt2560_tx_desc *desc; | struct rt2560_tx_desc *desc; | ||||
struct rt2560_tx_data *data; | struct rt2560_tx_data *data; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | ||||
uint16_t dur; | uint16_t dur; | ||||
uint32_t flags = 0; | uint32_t flags = 0; | ||||
int nsegs, rate, error; | int nsegs, error; | ||||
desc = &sc->prioq.desc[sc->prioq.cur]; | desc = &sc->prioq.desc[sc->prioq.cur]; | ||||
data = &sc->prioq.data[sc->prioq.cur]; | data = &sc->prioq.data[sc->prioq.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->prioq.data_dmat, data->map, m0, | error = bus_dmamap_load_mbuf_sg(sc->prioq.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 rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
tap->wt_antenna = sc->tx_ant; | tap->wt_antenna = sc->tx_ant; | ||||
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 |= RT2560_TX_ACK; | flags |= RT2560_TX_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 for probe responses */ | /* tell hardware to add timestamp for probe responses */ | ||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == | if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == | ||||
IEEE80211_FC0_TYPE_MGT && | IEEE80211_FC0_TYPE_MGT && | ||||
(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == | (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == | ||||
IEEE80211_FC0_SUBTYPE_PROBE_RESP) | IEEE80211_FC0_SUBTYPE_PROBE_RESP) | ||||
flags |= RT2560_TX_TIMESTAMP; | flags |= RT2560_TX_TIMESTAMP; | ||||
} | } | ||||
rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, | rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, | ||||
segs->ds_addr); | segs->ds_addr); | ||||
bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | ||||
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, | bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.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->prioq.cur, rate); | m0->m_pkthdr.len, sc->prioq.cur, rate->type, rate->value); | ||||
/* kick prio */ | /* kick prio */ | ||||
sc->prioq.queued++; | sc->prioq.queued++; | ||||
sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; | sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; | ||||
RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); | RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
rt2560_sendprot(struct rt2560_softc *sc, | rt2560_sendprot(struct rt2560_softc *sc, const struct mbuf *m, | ||||
const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) | 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 rt2560_tx_desc *desc; | struct rt2560_tx_desc *desc; | ||||
struct rt2560_tx_data *data; | struct rt2560_tx_data *data; | ||||
struct mbuf *mprot; | struct mbuf *mprot; | ||||
int protrate, flags, error; | int flags, error; | ||||
bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | bus_dma_segment_t segs[RT2560_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; | ||||
} | } | ||||
desc = &sc->txq.desc[sc->txq.cur_encrypt]; | desc = &sc->txq.desc[sc->txq.cur_encrypt]; | ||||
data = &sc->txq.data[sc->txq.cur_encrypt]; | data = &sc->txq.data[sc->txq.cur_encrypt]; | ||||
error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, | error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, | ||||
mprot, segs, &nsegs, 0); | mprot, segs, &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 = RT2560_TX_MORE_FRAG; | flags = RT2560_TX_MORE_FRAG; | ||||
if (prot == IEEE80211_PROT_RTSCTS) | if (prot == IEEE80211_PROT_RTSCTS) | ||||
flags |= RT2560_TX_ACK; | flags |= RT2560_TX_ACK; | ||||
rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, | rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, | ||||
segs->ds_addr); | segs->ds_addr); | ||||
bus_dmamap_sync(sc->txq.data_dmat, data->map, | bus_dmamap_sync(sc->txq.data_dmat, data->map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
sc->txq.queued++; | sc->txq.queued++; | ||||
sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; | sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
rt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, | rt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, | ||||
struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
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 rt2560_tx_desc *desc; | struct rt2560_tx_desc *desc; | ||||
struct rt2560_tx_data *data; | struct rt2560_tx_data *data; | ||||
bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | ||||
uint32_t flags; | uint32_t flags; | ||||
int nsegs, rate, error; | int nsegs, error; | ||||
desc = &sc->prioq.desc[sc->prioq.cur]; | desc = &sc->prioq.desc[sc->prioq.cur]; | ||||
data = &sc->prioq.data[sc->prioq.cur]; | data = &sc->prioq.data[sc->prioq.cur]; | ||||
rate = params->ibp_rate0; | rate = ieee80211_get_rate(params->ibp_rate0); | ||||
if (!ieee80211_isratevalid(ic->ic_rt, rate)) { | if (!ieee80211_isratevalid(ic->ic_rt, rate)) { | ||||
/* XXX fall back to mcast/mgmt rate? */ | /* XXX fall back to mcast/mgmt rate? */ | ||||
m_freem(m0); | m_freem(m0); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
flags = 0; | flags = 0; | ||||
if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) | if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) | ||||
flags |= RT2560_TX_ACK; | flags |= RT2560_TX_ACK; | ||||
if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { | if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { | ||||
error = rt2560_sendprot(sc, m0, ni, | error = rt2560_sendprot(sc, m0, ni, | ||||
params->ibp_flags & IEEE80211_BPF_RTS ? | params->ibp_flags & IEEE80211_BPF_RTS ? | ||||
IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, | IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, | ||||
rate); | params->ibp_rate0); | ||||
if (error) { | if (error) { | ||||
m_freem(m0); | m_freem(m0); | ||||
return error; | return error; | ||||
} | } | ||||
flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; | flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; | ||||
} | } | ||||
error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, | error = bus_dmamap_load_mbuf_sg(sc->prioq.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 rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
tap->wt_antenna = sc->tx_ant; | tap->wt_antenna = sc->tx_ant; | ||||
ieee80211_radiotap_tx(ni->ni_vap, m0); | ieee80211_radiotap_tx(ni->ni_vap, m0); | ||||
} | } | ||||
data->m = m0; | data->m = m0; | ||||
data->ni = ni; | data->ni = ni; | ||||
/* XXX need to setup descriptor ourself */ | /* XXX need to setup descriptor ourself */ | ||||
rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, | rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, | ||||
rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, | rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, | ||||
segs->ds_addr); | segs->ds_addr); | ||||
bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | ||||
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, | bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", | DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u/%u\n", | ||||
m0->m_pkthdr.len, sc->prioq.cur, rate); | m0->m_pkthdr.len, sc->prioq.cur, rate->type, rate->value); | ||||
/* kick prio */ | /* kick prio */ | ||||
sc->prioq.queued++; | sc->prioq.queued++; | ||||
sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; | sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; | ||||
RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); | RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, | rt2560_tx_data(struct rt2560_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 rt2560_tx_desc *desc; | struct rt2560_tx_desc *desc; | ||||
struct rt2560_tx_data *data; | struct rt2560_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[RT2560_MAX_SCATTER]; | bus_dma_segment_t segs[RT2560_MAX_SCATTER]; | ||||
uint16_t dur; | uint16_t dur, rate_idx; | ||||
uint32_t flags; | uint32_t flags; | ||||
int nsegs, rate, error; | int nsegs, error; | ||||
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_get_rate(rate_idx); | |||||
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 = rt2560_sendprot(sc, m0, ni, prot, rate); | error = rt2560_sendprot(sc, m0, ni, prot, rate_idx); | ||||
if (error) { | if (error) { | ||||
m_freem(m0); | m_freem(m0); | ||||
return error; | return error; | ||||
} | } | ||||
flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; | flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; | ||||
} | } | ||||
} | } | ||||
Show All 30 Lines | if (error != 0) { | ||||
/* 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 *); | ||||
} | } | ||||
if (ieee80211_radiotap_active_vap(vap)) { | if (ieee80211_radiotap_active_vap(vap)) { | ||||
struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; | ||||
tap->wt_flags = 0; | tap->wt_flags = 0; | ||||
tap->wt_rate = rate; | tap->wt_rate = rate->value; | ||||
tap->wt_antenna = sc->tx_ant; | tap->wt_antenna = sc->tx_ant; | ||||
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 (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { | ||||
flags |= RT2560_TX_ACK; | flags |= RT2560_TX_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); | ||||
} | } | ||||
rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, | rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, | ||||
segs->ds_addr); | segs->ds_addr); | ||||
bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); | ||||
bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, | bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, | ||||
BUS_DMASYNC_PREWRITE); | 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, sc->txq.cur_encrypt, rate); | m0->m_pkthdr.len, sc->txq.cur_encrypt, rate->type, rate->value); | ||||
/* kick encrypt */ | /* kick encrypt */ | ||||
sc->txq.queued++; | sc->txq.queued++; | ||||
sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; | sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; | ||||
RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); | RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 438 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
rt2560_set_basicrates(struct rt2560_softc *sc, | rt2560_set_basicrates(struct rt2560_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, RT2560_ARSP_PLCP_1, mask); | RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask); | ||||
DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); | DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 424 Lines • Show Last 20 Lines |