PERFORCE change 129271 for review
Kevin Lo
kevlo at FreeBSD.org
Mon Nov 19 22:42:44 PST 2007
http://perforce.freebsd.org/chv.cgi?CH=129271
Change 129271 by kevlo at kevlo_rtsl on 2007/11/20 06:42:32
Rework LED support
Obtained from: DragonFlyBSD
Affected files ...
.. //depot/projects/wifi/sys/dev/bwi/if_bwi.c#9 edit
.. //depot/projects/wifi/sys/dev/bwi/if_bwireg.h#4 edit
.. //depot/projects/wifi/sys/dev/bwi/if_bwivar.h#5 edit
Differences ...
==== //depot/projects/wifi/sys/dev/bwi/if_bwi.c#9 (text+ko) ====
@@ -111,8 +111,8 @@
static int bwi_calc_rssi(struct bwi_softc *, const struct bwi_rxbuf_hdr *);
static __inline uint8_t bwi_ofdm_plcp2rate(const uint32_t *);
static __inline uint8_t bwi_ds_plcp2rate(const struct ieee80211_ds_plcp_hdr *);
-static void bwi_rx_radiotap(struct bwi_softc *, struct mbuf *,
- struct bwi_rxbuf_hdr *, const void *, int);
+static void bwi_rx_radiotap(struct bwi_softc *, struct mbuf *,
+ struct bwi_rxbuf_hdr *, const void *, int, int);
static void bwi_stop(struct bwi_softc *);
static int bwi_newbuf(struct bwi_softc *, int, int);
@@ -132,7 +132,7 @@
static void bwi_setup_rx_desc32(struct bwi_softc *, int, bus_addr_t, int);
static void bwi_setup_tx_desc32(struct bwi_softc *, struct bwi_ring_data *,
int, bus_addr_t, int);
-static void bwi_rxeof32(struct bwi_softc *);
+static int bwi_rxeof32(struct bwi_softc *);
static void bwi_start_tx32(struct bwi_softc *, uint32_t, int);
static void bwi_txeof_status32(struct bwi_softc *);
@@ -145,11 +145,11 @@
static void bwi_setup_rx_desc64(struct bwi_softc *, int, bus_addr_t, int);
static void bwi_setup_tx_desc64(struct bwi_softc *, struct bwi_ring_data *,
int, bus_addr_t, int);
-static void bwi_rxeof64(struct bwi_softc *);
+static int bwi_rxeof64(struct bwi_softc *);
static void bwi_start_tx64(struct bwi_softc *, uint32_t, int);
static void bwi_txeof_status64(struct bwi_softc *);
-static void bwi_rxeof(struct bwi_softc *, int);
+static int bwi_rxeof(struct bwi_softc *, int);
static void _bwi_txeof(struct bwi_softc *, uint16_t, int, int);
static void bwi_txeof(struct bwi_softc *);
static void bwi_txeof_status(struct bwi_softc *, int);
@@ -195,6 +195,10 @@
static void bwi_led_attach(struct bwi_softc *);
static void bwi_led_newstate(struct bwi_softc *, enum ieee80211_state);
+static void bwi_led_event(struct bwi_softc *, int);
+static void bwi_led_blink_start(struct bwi_softc *, int, int);
+static void bwi_led_blink_next(void *);
+static void bwi_led_blink_end(void *);
static const struct {
uint16_t did_min;
@@ -242,6 +246,48 @@
#undef CLKSRC
+#define VENDOR_LED_ACT(vendor) \
+{ \
+ .vid = PCI_VENDOR_##vendor, \
+ .led_act = { BWI_VENDOR_LED_ACT_##vendor } \
+}
+
+static const struct {
+#define PCI_VENDOR_COMPAQ 0x0e11
+#define PCI_VENDOR_LINKSYS 0x1737
+ uint16_t vid;
+ uint8_t led_act[BWI_LED_MAX];
+} bwi_vendor_led_act[] = {
+ VENDOR_LED_ACT(COMPAQ),
+ VENDOR_LED_ACT(LINKSYS)
+#undef PCI_VENDOR_LINKSYS
+#undef PCI_VENDOR_COMPAQ
+};
+
+static const uint8_t bwi_default_led_act[BWI_LED_MAX] =
+ { BWI_VENDOR_LED_ACT_DEFAULT };
+
+#undef VENDOR_LED_ACT
+
+static const struct {
+ int on_dur;
+ int off_dur;
+} bwi_led_duration[109] = {
+ [0] = { 400, 100 },
+ [2] = { 150, 75 },
+ [4] = { 90, 45 },
+ [11] = { 66, 34 },
+ [12] = { 53, 26 },
+ [18] = { 42, 21 },
+ [22] = { 35, 17 },
+ [24] = { 32, 16 },
+ [36] = { 21, 10 },
+ [48] = { 16, 8 },
+ [72] = { 11, 5 },
+ [96] = { 9, 4 },
+ [108] = { 7, 3 }
+};
+
static const uint8_t bwi_zero_addr[IEEE80211_ADDR_LEN];
uint16_t
@@ -417,6 +463,10 @@
sc->sc_fw_version = BWI_FW_VERSION3;
+ /* Initialize LED vars */
+ sc->sc_led_idle = (2350 * hz) / 1000;
+ sc->sc_led_blink = 1;
+
ic->ic_ifp = ifp;
ic->ic_caps = IEEE80211_C_SHSLOT |
IEEE80211_C_SHPREAMBLE |
@@ -1385,7 +1435,7 @@
struct ifnet *ifp = sc->sc_ic.ic_ifp;
uint32_t intr_status;
uint32_t txrx_intr_status[BWI_TXRX_NRING];
- int i, txrx_error;
+ int i, txrx_error, tx = 0, rx_data = -1;
BWI_LOCK(sc);
@@ -1480,18 +1530,41 @@
if_printf(ifp, "intr noise\n");
if (txrx_intr_status[0] & BWI_TXRX_INTR_RX)
- sc->sc_rxeof(sc);
+ rx_data = sc->sc_rxeof(sc);
- if (txrx_intr_status[3] & BWI_TXRX_INTR_RX)
+ if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) {
sc->sc_txeof_status(sc);
+ tx = 1;
+ }
- if (intr_status & BWI_INTR_TX_DONE)
+ if (intr_status & BWI_INTR_TX_DONE) {
bwi_txeof(sc);
+ tx = 1;
+ }
- /* TODO:LED */
-
/* Re-enable interrupts */
bwi_enable_intrs(sc, BWI_INIT_INTRS);
+
+ if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
+ int evt = BWI_LED_EVENT_NONE;
+
+ if (tx && rx_data > 0) {
+ if (sc->sc_rx_rate > sc->sc_tx_rate)
+ evt = BWI_LED_EVENT_RX;
+ else
+ evt = BWI_LED_EVENT_TX;
+ } else if (tx) {
+ evt = BWI_LED_EVENT_TX;
+ } else if (rx_data > 0) {
+ evt = BWI_LED_EVENT_RX;
+ } else if (rx_data == 0) {
+ evt = BWI_LED_EVENT_POLL;
+ }
+
+ if (evt != BWI_LED_EVENT_NONE)
+ bwi_led_event(sc, evt);
+ }
+
BWI_UNLOCK(sc);
}
@@ -2454,14 +2527,14 @@
return 0;
}
-static void
+static int
bwi_rxeof(struct bwi_softc *sc, int end_idx)
{
struct bwi_ring_data *rd = &sc->sc_rx_rdata;
struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
- int idx;
+ int idx, rx_data = 0;
idx = rbd->rbd_idx;
while (idx != end_idx) {
@@ -2470,9 +2543,9 @@
struct ieee80211_frame_min *wh;
struct ieee80211_node *ni;
struct mbuf *m;
- const uint8_t *plcp;
+ const void *plcp;
uint16_t flags2;
- int buflen, wh_ofs, hdr_extra, rssi;
+ int buflen, wh_ofs, hdr_extra, rssi, type, rate;
m = rb->rb_mbuf;
bus_dmamap_sync(sc->sc_buf_dtag, rb->rb_dmap,
@@ -2507,18 +2580,27 @@
m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr);
m_adj(m, sizeof(*hdr) + wh_ofs);
+ if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM)
+ rate = bwi_ofdm_plcp2rate(plcp);
+ else
+ rate = bwi_ds_plcp2rate(plcp);
+
/* RX radio tap */
if (sc->sc_drvbpf != NULL)
- bwi_rx_radiotap(sc, m, hdr, plcp, rssi);
+ bwi_rx_radiotap(sc, m, hdr, plcp, rate, rssi);
m_adj(m, -IEEE80211_CRC_LEN);
wh = mtod(m, struct ieee80211_frame_min *);
ni = ieee80211_find_rxnode(ic, wh);
- ieee80211_input(ic, m, ni, rssi - BWI_NOISE_FLOOR,
+ type = ieee80211_input(ic, m, ni, rssi - BWI_NOISE_FLOOR,
BWI_NOISE_FLOOR, le16toh(hdr->rxh_tsf));
ieee80211_free_node(ni);
+ if (type == IEEE80211_FC0_TYPE_DATA) {
+ rx_data = 1;
+ sc->sc_rx_rate = rate;
+ }
next:
idx = (idx + 1) % BWI_RX_NDESC;
}
@@ -2526,13 +2608,15 @@
rbd->rbd_idx = idx;
bus_dmamap_sync(sc->sc_rxring_dtag, rd->rdata_dmap,
BUS_DMASYNC_PREWRITE);
+
+ return rx_data;
}
-static void
+static int
bwi_rxeof32(struct bwi_softc *sc)
{
uint32_t val, rx_ctrl;
- int end_idx;
+ int end_idx, rx_data;
rx_ctrl = sc->sc_rx_rdata.rdata_txrx_ctrl;
@@ -2540,16 +2624,19 @@
end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) /
sizeof(struct bwi_desc32);
- bwi_rxeof(sc, end_idx);
+ rx_data = bwi_rxeof(sc, end_idx);
CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_INDEX,
end_idx * sizeof(struct bwi_desc32));
+
+ return rx_data;
}
-static void
+static int
bwi_rxeof64(struct bwi_softc *sc)
{
/* TODO:64 */
+ return 0;
}
static void
@@ -2816,12 +2903,16 @@
if (IEEE80211_IS_MULTICAST(wh->i_addr1))
rate = rate_fb = ic->ic_mcast_rate;
else if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
- rate = ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL;
+ rate = ni->ni_rates.rs_rates[ni->ni_txrate] &
+ IEEE80211_RATE_VAL;
rate_fb = (ni->ni_txrate > 0) ?
- ni->ni_rates.rs_rates[ni->ni_txrate-1] & IEEE80211_RATE_VAL : rate;
+ ni->ni_rates.rs_rates[ni->ni_txrate-1] &
+ IEEE80211_RATE_VAL : rate;
} else
rate = rate_fb = ic->ic_fixed_rate;
+ sc->sc_tx_rate = rate;
+
/*
* TX radio tap
*/
@@ -3460,20 +3551,12 @@
static void
bwi_rx_radiotap(struct bwi_softc *sc, struct mbuf *m,
- struct bwi_rxbuf_hdr *hdr, const void *plcp, int rssi)
+ struct bwi_rxbuf_hdr *hdr, const void *plcp, int rate, int rssi)
{
const struct ieee80211_frame_min *wh;
- uint16_t flags1;
- uint8_t rate;
- flags1 = htole16(hdr->rxh_flags1);
- if (flags1 & BWI_RXH_F1_OFDM)
- rate = bwi_ofdm_plcp2rate(plcp);
- else
- rate = bwi_ds_plcp2rate(plcp);
-
sc->sc_rx_th.wr_flags = IEEE80211_RADIOTAP_F_FCS;
- if (flags1 & BWI_RXH_F1_SHPREAMBLE)
+ if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_SHPREAMBLE)
sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
wh = mtod(m, const struct ieee80211_frame_min *);
@@ -3491,17 +3574,23 @@
static void
bwi_led_attach(struct bwi_softc *sc)
{
-#define PCI_VENDOR_COMPAQ 0x0e11
- const static uint8_t led_default_act[BWI_LED_MAX] = {
- BWI_LED_ACT_ACTIVE,
- BWI_LED_ACT_2GHZ,
- BWI_LED_ACT_5GHZ,
- BWI_LED_ACT_OFF
- };
-
+ const uint8_t *led_act = NULL;
uint16_t gpio, val[BWI_LED_MAX];
int i;
+#define N(arr) (int)(sizeof(arr) / sizeof(arr[0]))
+
+ for (i = 0; i < N(bwi_vendor_led_act); ++i) {
+ if (sc->sc_pci_subvid == bwi_vendor_led_act[i].vid) {
+ led_act = bwi_vendor_led_act[i].led_act;
+ break;
+ }
+ }
+ if (led_act == NULL)
+ led_act = bwi_default_led_act;
+
+#undef N
+
gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO01);
val[0] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_0);
val[1] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_1);
@@ -3514,19 +3603,46 @@
struct bwi_led *led = &sc->sc_leds[i];
if (val[i] == 0xff) {
- led->l_act = led_default_act[i];
- if (i == 0 && sc->sc_pci_subvid == PCI_VENDOR_COMPAQ)
- led->l_act = BWI_LED_ACT_RFEN;
+ led->l_act = led_act[i];
} else {
if (val[i] & BWI_LED_ACT_LOW)
led->l_flags |= BWI_LED_F_ACTLOW;
led->l_act = __SHIFTOUT(val[i], BWI_LED_ACT_MASK);
}
+ led->l_mask = (1 << i);
+
+ if (led->l_act == BWI_LED_ACT_BLINK_SLOW ||
+ led->l_act == BWI_LED_ACT_BLINK_POLL ||
+ led->l_act == BWI_LED_ACT_BLINK) {
+ led->l_flags |= BWI_LED_F_BLINK;
+ if (led->l_act == BWI_LED_ACT_BLINK_POLL)
+ led->l_flags |= BWI_LED_F_POLLABLE;
+ else if (led->l_act == BWI_LED_ACT_BLINK_SLOW)
+ led->l_flags |= BWI_LED_F_SLOW;
+
+ if (sc->sc_blink_led == NULL) {
+ sc->sc_blink_led = led;
+ if (led->l_flags & BWI_LED_F_SLOW)
+ BWI_LED_SLOWDOWN(sc->sc_led_idle);
+ }
+ }
DPRINTF(sc, "%dth led, act %d, lowact %d\n",
i, led->l_act, led->l_flags & BWI_LED_F_ACTLOW);
}
-#undef PCI_VENDOR_COMPAQ
+ callout_init(&sc->sc_led_blink_ch, CALLOUT_MPSAFE);
+}
+
+static __inline uint16_t
+bwi_led_onoff(const struct bwi_led *led, uint16_t val, int on)
+{
+ if (led->l_flags & BWI_LED_F_ACTLOW)
+ on = !on;
+ if (on)
+ val |= led->l_mask;
+ else
+ val &= ~led->l_mask;
+ return val;
}
static void
@@ -3536,6 +3652,11 @@
uint16_t val;
int i;
+ if (nstate == IEEE80211_S_INIT) {
+ callout_stop(&sc->sc_led_blink_ch);
+ sc->sc_led_blinking = 0;
+ }
+
if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
@@ -3545,10 +3666,12 @@
int on;
if (led->l_act == BWI_LED_ACT_UNKN ||
- led->l_act == BWI_LED_ACT_NULL) {
- /* Don't touch it */
+ led->l_act == BWI_LED_ACT_NULL)
continue;
- }
+
+ if ((led->l_flags & BWI_LED_F_BLINK) &&
+ nstate != IEEE80211_S_INIT)
+ continue;
switch (led->l_act) {
case BWI_LED_ACT_ON: /* Always on */
@@ -3556,8 +3679,6 @@
break;
case BWI_LED_ACT_OFF: /* Always off */
case BWI_LED_ACT_5GHZ: /* TODO: 11A */
- case BWI_LED_ACT_MID: /* Blinking ones */
- case BWI_LED_ACT_FAST:
on = 0;
break;
default:
@@ -3572,23 +3693,92 @@
on = 0;
break;
default:
- if (led->l_act == BWI_LED_ACT_RUN ||
- led->l_act == BWI_LED_ACT_ACTIVE)
+ if (led->l_act == BWI_LED_ACT_ASSOC)
on = 0;
break;
}
break;
}
- if (led->l_flags & BWI_LED_F_ACTLOW)
- on = !on;
+ val = bwi_led_onoff(led, val, on);
+ }
+ CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val);
+}
+static void
+bwi_led_event(struct bwi_softc *sc, int event)
+{
+ struct bwi_led *led = sc->sc_blink_led;
+ int rate;
+
+ if (event == BWI_LED_EVENT_POLL) {
+ if ((led->l_flags & BWI_LED_F_POLLABLE) == 0)
+ return;
+ if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
+ return;
+ }
+
+ sc->sc_led_ticks = ticks;
+ if (sc->sc_led_blinking)
+ return;
+
+ switch (event) {
+ case BWI_LED_EVENT_RX:
+ rate = sc->sc_rx_rate;
+ break;
+ case BWI_LED_EVENT_TX:
+ rate = sc->sc_tx_rate;
+ break;
+ case BWI_LED_EVENT_POLL:
+ rate = 0;
+ break;
+ default:
+ panic("unknown LED event %d\n", event);
+ break;
+ }
+ bwi_led_blink_start(sc, bwi_led_duration[rate].on_dur,
+ bwi_led_duration[rate].off_dur);
+}
+
+static void
+bwi_led_blink_start(struct bwi_softc *sc, int on_dur, int off_dur)
+{
+ struct bwi_led *led = sc->sc_blink_led;
+ uint16_t val;
+
+ val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL);
+ val = bwi_led_onoff(led, val, 1);
+ CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val);
- if (on)
- val |= (1 << i);
- else
- val &= ~(1 << i);
+ if (led->l_flags & BWI_LED_F_SLOW) {
+ BWI_LED_SLOWDOWN(on_dur);
+ BWI_LED_SLOWDOWN(off_dur);
}
+
+ sc->sc_led_blinking = 1;
+ sc->sc_led_blink_offdur = off_dur;
+
+ callout_reset(&sc->sc_led_blink_ch, on_dur, bwi_led_blink_next, sc);
+}
+
+static void
+bwi_led_blink_next(void *xsc)
+{
+ struct bwi_softc *sc = xsc;
+ uint16_t val;
+
+ val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL);
+ val = bwi_led_onoff(sc->sc_blink_led, val, 0);
CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val);
+
+ callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
+ bwi_led_blink_end, sc);
+}
+
+static void
+bwi_led_blink_end(void *xsc)
+{
+ struct bwi_softc *sc = xsc;
+ sc->sc_led_blinking = 0;
}
/*
==== //depot/projects/wifi/sys/dev/bwi/if_bwireg.h#4 (text+ko) ====
@@ -412,17 +412,35 @@
#define BWI_LED_ACT_MASK __BITS(6, 0)
#define BWI_LED_ACT_OFF 0
#define BWI_LED_ACT_ON 1
-#define BWI_LED_ACT_ACTIVE 2
-#define BWI_LED_ACT_RFEN 3
+#define BWI_LED_ACT_BLINK 2
+#define BWI_LED_ACT_RF_ENABLED 3
#define BWI_LED_ACT_5GHZ 4
#define BWI_LED_ACT_2GHZ 5
#define BWI_LED_ACT_11G 6
-#define BWI_LED_ACT_MID 7
-#define BWI_LED_ACT_FAST 8
+#define BWI_LED_ACT_BLINK_SLOW 7
+#define BWI_LED_ACT_BLINK_POLL 8
#define BWI_LED_ACT_UNKN 9
-#define BWI_LED_ACT_RUN 10
+#define BWI_LED_ACT_ASSOC 10
#define BWI_LED_ACT_NULL 11
+#define BWI_VENDOR_LED_ACT_COMPAQ \
+ BWI_LED_ACT_RF_ENABLED, \
+ BWI_LED_ACT_2GHZ, \
+ BWI_LED_ACT_5GHZ, \
+ BWI_LED_ACT_OFF
+
+#define BWI_VENDOR_LED_ACT_LINKSYS \
+ BWI_LED_ACT_ASSOC, \
+ BWI_LED_ACT_2GHZ, \
+ BWI_LED_ACT_5GHZ, \
+ BWI_LED_ACT_OFF
+
+#define BWI_VENDOR_LED_ACT_DEFAULT \
+ BWI_LED_ACT_BLINK, \
+ BWI_LED_ACT_2GHZ, \
+ BWI_LED_ACT_5GHZ, \
+ BWI_LED_ACT_OFF
+
/*
* BBP IDs
*/
==== //depot/projects/wifi/sys/dev/bwi/if_bwivar.h#5 (text+ko) ====
@@ -55,6 +55,12 @@
#define BWI_SHRETRY_FB 3
#define BWI_LGRETRY_FB 2
+#define BWI_LED_EVENT_NONE -1
+#define BWI_LED_EVENT_POLL 0
+#define BWI_LED_EVENT_TX 1
+#define BWI_LED_EVENT_RX 2
+#define BWI_LED_SLOWDOWN(dur) (dur) = (((dur) * 3) / 2)
+
#define BWI_NOISE_FLOOR -95 /* TODO: noise floor calc */
#define BWI_FRAME_MIN_LEN(hdr) \
((hdr) + sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
@@ -284,9 +290,13 @@
struct bwi_led {
uint8_t l_flags; /* BWI_LED_F_ */
uint8_t l_act; /* BWI_LED_ACT_ */
+ uint8_t l_mask;
};
#define BWI_LED_F_ACTLOW 0x1
+#define BWI_LED_F_BLINK 0x2
+#define BWI_LED_F_POLLABLE 0x4
+#define BWI_LED_F_SLOW 0x8
enum bwi_clock_mode {
BWI_CLOCK_MODE_SLOW,
@@ -543,6 +553,14 @@
int sc_nmac;
struct bwi_mac sc_mac[BWI_MAC_MAX];
+ int sc_rx_rate;
+ int sc_tx_rate;
+
+ int sc_led_blinking;
+ int sc_led_ticks;
+ struct bwi_led *sc_blink_led;
+ struct callout sc_led_blink_ch;
+ int sc_led_blink_offdur;
struct bwi_led sc_leds[BWI_LED_MAX];
enum bwi_bus_space sc_bus_space;
@@ -582,7 +600,7 @@
void (*sc_setup_rxdesc)
(struct bwi_softc *, int, bus_addr_t, int);
- void (*sc_rxeof)(struct bwi_softc *);
+ int (*sc_rxeof)(struct bwi_softc *);
void (*sc_setup_txdesc)
(struct bwi_softc *, struct bwi_ring_data *,
@@ -595,6 +613,8 @@
/* Sysctl variables */
int sc_fw_version; /* BWI_FW_VERSION[34] */
int sc_dwell_time; /* milliseconds */
+ int sc_led_idle;
+ int sc_led_blink;
};
#define BWI_F_BUS_INITED 0x1
More information about the p4-projects
mailing list