Module Name: src
Committed By: martin
Date: Sun Feb 2 14:30:00 UTC 2025
Modified Files:
src/share/man/man4 [netbsd-10]: bwi.4
src/sys/arch/evbppc/conf [netbsd-10]: WII
src/sys/dev/ic [netbsd-10]: bwi.c bwireg.h bwivar.h
src/sys/dev/sdmmc [netbsd-10]: files.sdmmc sdmmc_cis.c sdmmcvar.h
Added Files:
src/sys/dev/sdmmc [netbsd-10]: if_bwi_sdio.c
Log Message:
Pull up following revision(s) (requested by jmcneill in ticket #1041):
sys/dev/ic/bwi.c: revision 1.40
share/man/man4/bwi.4: revision 1.15
sys/dev/sdmmc/if_bwi_sdio.c: revision 1.1
sys/dev/ic/bwi.c: revision 1.41
sys/dev/sdmmc/sdmmcvar.h: revision 1.38
sys/dev/ic/bwireg.h: revision 1.5
sys/dev/ic/bwi.c: revision 1.39
sys/dev/ic/bwivar.h: revision 1.11
sys/dev/sdmmc/sdmmc_cis.c: revision 1.10
sys/dev/sdmmc/files.sdmmc: revision 1.6
sys/arch/evbppc/conf/WII: revision 1.7
bwi: Remove unnecessary pcivar.h include
sdmmc: Capture lan_nid and expose sdmmc_cisptr
LAN NID contains the MAC address for networking adapters.
Device drivers may want to processor vendor specific tuple codes, so
expose sdmmc_cisptr to help this.
bwi(4): Add support for Nintendo Wii WLAN.
Adapt the bwi(4) driver to support SDIO attachment and driving TX/RX using
PIO instead of DMA since the latter is not supported on SDIO busses.
fix uninitialized
To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.13.36.1 src/share/man/man4/bwi.4
cvs rdiff -u -r1.4.2.4 -r1.4.2.5 src/sys/arch/evbppc/conf/WII
cvs rdiff -u -r1.38 -r1.38.10.1 src/sys/dev/ic/bwi.c
cvs rdiff -u -r1.4 -r1.4.20.1 src/sys/dev/ic/bwireg.h
cvs rdiff -u -r1.10 -r1.10.46.1 src/sys/dev/ic/bwivar.h
cvs rdiff -u -r1.5 -r1.5.36.1 src/sys/dev/sdmmc/files.sdmmc
cvs rdiff -u -r0 -r1.1.2.2 src/sys/dev/sdmmc/if_bwi_sdio.c
cvs rdiff -u -r1.8.26.1 -r1.8.26.2 src/sys/dev/sdmmc/sdmmc_cis.c
cvs rdiff -u -r1.36.18.1 -r1.36.18.2 src/sys/dev/sdmmc/sdmmcvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/share/man/man4/bwi.4
diff -u src/share/man/man4/bwi.4:1.13 src/share/man/man4/bwi.4:1.13.36.1
--- src/share/man/man4/bwi.4:1.13 Tue Mar 18 18:20:39 2014
+++ src/share/man/man4/bwi.4 Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-.\" $NetBSD: bwi.4,v 1.13 2014/03/18 18:20:39 riastradh Exp $
+.\" $NetBSD: bwi.4,v 1.13.36.1 2025/02/02 14:29:59 martin Exp $
.\"
.\" Copyright (c) 2007 The DragonFly Project. All rights reserved.
.\"
@@ -31,7 +31,7 @@
.\"
.\" $DragonFly: src/share/man/man4/bwi.4,v 1.10 2008/07/26 16:25:40 swildner Exp $
.\"
-.Dd April 25, 2012
+.Dd January 18, 2025
.Dt BWI 4
.Os
.Sh NAME
@@ -40,6 +40,7 @@
.Sh SYNOPSIS
.Cd "bwi* at pci? dev ? function ?"
.Cd "bwi* at cardbus? function ?"
+.Cd "bwi* at sdmmc?"
.Sh DESCRIPTION
The
.Nm
@@ -73,6 +74,7 @@ driver:
.Pp
.Bl -column -offset 6n -compact "Apple AirPort Extreme" "BCM4318" "Mini PCI" "b/g"
.It Em "Card Chip Bus Standard"
+.It Apple AirPort Extreme b/g
.It Buffalo WLI-CB-G54 BCM4306 CardBus b/g
.It Buffalo WLI3-CB-G54L BCM4318 CardBus b/g
.It Buffalo WLI-PCI-G54S BCM4306 PCI b/g
@@ -80,7 +82,7 @@ driver:
.It Dell Wireless 1470 BCM4318 Mini PCI b/g
.It Dell Truemobile 1400 BCM4309 Mini PCI b/g
.It Dell Latitude D505 BCM4306 PCI b/g
-.It Apple AirPort Extreme b/g
+.It Nintendo Wii WLAN BCM4318 SDIO b/g
.El
.Sh FILES
The firmware for the adapter is not shipped with
Index: src/sys/arch/evbppc/conf/WII
diff -u src/sys/arch/evbppc/conf/WII:1.4.2.4 src/sys/arch/evbppc/conf/WII:1.4.2.5
--- src/sys/arch/evbppc/conf/WII:1.4.2.4 Wed Oct 2 12:28:15 2024
+++ src/sys/arch/evbppc/conf/WII Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-# $NetBSD: WII,v 1.4.2.4 2024/10/02 12:28:15 martin Exp $
+# $NetBSD: WII,v 1.4.2.5 2025/02/02 14:29:59 martin Exp $
#
# Nintendo Wii
#
@@ -155,6 +155,7 @@ sdhc0 at hollywood0 addr 0x0d070000 irq
sdhc1 at hollywood0 addr 0x0d080000 irq 8 # SDIO/BT
sdmmc* at sdmmcbus?
ld* at sdmmc?
+bwi* at sdmmc? # WLAN
include "dev/usb/usbdevices.config"
include "dev/bluetooth/bluetoothdevices.config"
Index: src/sys/dev/ic/bwi.c
diff -u src/sys/dev/ic/bwi.c:1.38 src/sys/dev/ic/bwi.c:1.38.10.1
--- src/sys/dev/ic/bwi.c:1.38 Wed Jun 16 00:21:18 2021
+++ src/sys/dev/ic/bwi.c Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: bwi.c,v 1.38 2021/06/16 00:21:18 riastradh Exp $ */
+/* $NetBSD: bwi.c,v 1.38.10.1 2025/02/02 14:29:59 martin Exp $ */
/* $OpenBSD: bwi.c,v 1.74 2008/02/25 21:13:30 mglocker Exp $ */
/*
@@ -48,7 +48,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.38 2021/06/16 00:21:18 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.38.10.1 2025/02/02 14:29:59 martin Exp $");
#include <sys/param.h>
#include <sys/callout.h>
@@ -62,6 +62,10 @@ __KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.38
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/intr.h>
+#include <sys/pool.h>
+#include <sys/workqueue.h>
+#include <sys/mutex.h>
+#include <sys/kmem.h>
#include <machine/endian.h>
@@ -88,7 +92,7 @@ int bwi_debug = 0;
#define DPRINTF(sc, dbg, fmt, ...) \
do { \
if ((sc)->sc_debug & (dbg)) \
- aprint_debug_dev((sc)->sc_dev, fmt, ##__VA_ARGS__); \
+ device_printf((sc)->sc_dev, fmt, ##__VA_ARGS__); \
} while (0)
#else /* !BWI_DEBUG */
@@ -99,7 +103,6 @@ do { \
/* XXX temporary porting goop */
#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
/* XXX does not belong here */
@@ -310,13 +313,18 @@ static void bwi_watchdog(struct ifnet *
static void bwi_stop(struct ifnet *, int);
static void bwi_newstate_begin(struct bwi_softc *, enum ieee80211_state);
static int bwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static int bwi_newstate_sdio(struct ieee80211com *, enum ieee80211_state,
+ int);
static int bwi_media_change(struct ifnet *);
+static void bwi_task(struct work *, void *);
/* [TRC: XXX amrr] */
static void bwi_iter_func(void *, struct ieee80211_node *);
static void bwi_amrr_timeout(void *);
static void bwi_newassoc(struct ieee80211_node *, int);
static struct ieee80211_node *
bwi_node_alloc(struct ieee80211_node_table *);
+static int bwi_pio_alloc(struct bwi_softc *);
+static void bwi_pio_free(struct bwi_softc *);
static int bwi_dma_alloc(struct bwi_softc *);
static void bwi_dma_free(struct bwi_softc *);
static void bwi_ring_data_free(struct bwi_ring_data *, struct bwi_softc *);
@@ -329,6 +337,13 @@ static int bwi_dma_mbuf_create(struct b
static void bwi_dma_mbuf_destroy(struct bwi_softc *, int, int);
static void bwi_enable_intrs(struct bwi_softc *, uint32_t);
static void bwi_disable_intrs(struct bwi_softc *, uint32_t);
+static int bwi_init_tx_ring_pio(struct bwi_softc *, int);
+static int bwi_init_rx_ring_pio(struct bwi_softc *);
+static int bwi_init_txstats_pio(struct bwi_softc *);
+static void bwi_setup_rx_desc_pio(struct bwi_softc *, int, bus_addr_t,
+ int);
+static void bwi_setup_tx_desc_pio(struct bwi_softc *,
+ struct bwi_ring_data *, int, bus_addr_t, int);
static int bwi_init_tx_ring32(struct bwi_softc *, int);
static void bwi_init_rxdesc_ring32(struct bwi_softc *, uint32_t,
bus_addr_t, int, int);
@@ -349,8 +364,12 @@ static void bwi_set_addr_filter(struct
static int bwi_set_chan(struct bwi_softc *, struct ieee80211_channel *);
static void bwi_next_scan(void *);
static int bwi_rxeof(struct bwi_softc *, int);
+static int bwi_rxeof_pio(struct bwi_softc *);
static int bwi_rxeof32(struct bwi_softc *);
static int bwi_rxeof64(struct bwi_softc *);
+static void bwi_free_txstats_pio(struct bwi_softc *);
+static void bwi_free_rx_ring_pio(struct bwi_softc *);
+static void bwi_free_tx_ring_pio(struct bwi_softc *, int);
static void bwi_reset_rx_ring32(struct bwi_softc *, uint32_t);
static void bwi_free_txstats32(struct bwi_softc *);
static void bwi_free_rx_ring32(struct bwi_softc *);
@@ -370,8 +389,10 @@ static void bwi_ds_plcp_header(struct i
static void bwi_plcp_header(void *, int, uint8_t);
static int bwi_encap(struct bwi_softc *, int, struct mbuf *,
struct ieee80211_node **, int);
+static void bwi_start_tx_pio(struct bwi_softc *, uint32_t, int);
static void bwi_start_tx32(struct bwi_softc *, uint32_t, int);
static void bwi_start_tx64(struct bwi_softc *, uint32_t, int);
+static void bwi_txeof_status_pio(struct bwi_softc *);
static void bwi_txeof_status32(struct bwi_softc *);
static void bwi_txeof_status64(struct bwi_softc *);
static void _bwi_txeof(struct bwi_softc *, uint16_t);
@@ -391,6 +412,8 @@ static void bwi_regwin_disable(struct b
uint32_t);
static void bwi_set_bssid(struct bwi_softc *, const uint8_t *);
static void bwi_updateslot(struct ifnet *);
+static void bwi_updateslot_sdio(struct ifnet *);
+static void bwi_do_calibrate(struct bwi_softc *);
static void bwi_calibrate(void *);
static int bwi_calc_rssi(struct bwi_softc *,
const struct bwi_rxbuf_hdr *);
@@ -690,30 +713,13 @@ err:
/* CODE */
-int
-bwi_intr(void *arg)
-{
- struct bwi_softc *sc = arg;
- struct ifnet *ifp = &sc->sc_if;
-
- if (!device_is_active(sc->sc_dev) ||
- (ifp->if_flags & IFF_RUNNING) == 0)
- return (0);
-
- /* Disable all interrupts */
- bwi_disable_intrs(sc, BWI_ALL_INTRS);
-
- softint_schedule(sc->sc_soft_ih);
- return (1);
-}
-
static void
bwi_softintr(void *arg)
{
struct bwi_softc *sc = arg;
struct bwi_mac *mac;
struct ifnet *ifp = &sc->sc_if;
- uint32_t intr_status;
+ uint32_t intr_status, intr_mask;
uint32_t txrx_intr_status[BWI_TXRX_NRING];
int i, s, txrx_error, tx = 0, rx_data = -1;
@@ -729,11 +735,19 @@ bwi_softintr(void *arg)
if (intr_status == 0xffffffff) /* Not for us */
goto out;
- intr_status &= CSR_READ_4(sc, BWI_MAC_INTR_MASK);
- if (intr_status == 0) /* Nothing is interesting */
+ if (BWI_IS_SDIO(sc)) {
+ intr_mask = 0xffffffff;
+ } else {
+ /* XXX FIXME */
+ intr_mask = CSR_READ_4(sc, BWI_MAC_INTR_MASK);
+ }
+ DPRINTF(sc, BWI_DBG_INTR,
+ "intr status 0x%08x mask 0x%08x -> 0x%08x\n",
+ intr_status, intr_mask, intr_status & intr_mask);
+ intr_status &= intr_mask;
+ if (intr_status == 0) { /* Nothing is interesting */
goto out;
-
- DPRINTF(sc, BWI_DBG_INTR, "intr status 0x%08x\n", intr_status);
+ }
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC);
mac = (struct bwi_mac *)sc->sc_cur_regwin;
@@ -802,8 +816,9 @@ bwi_softintr(void *arg)
if (intr_status & BWI_INTR_NOISE)
aprint_normal_dev(sc->sc_dev, "intr noise\n");
- if (txrx_intr_status[0] & BWI_TXRX_INTR_RX)
+ if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) {
rx_data = (sc->sc_rxeof)(sc);
+ }
if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) {
(sc->sc_txeof_status)(sc);
@@ -815,7 +830,8 @@ bwi_softintr(void *arg)
tx = 1;
}
- if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
+ if (sc->sc_blink_led != NULL && sc->sc_led_blink &&
+ !BWI_IS_SDIO(sc)) {
int evt = BWI_LED_EVENT_NONE;
if (tx && rx_data > 0) {
@@ -842,6 +858,28 @@ out:
}
int
+bwi_intr(void *arg)
+{
+ struct bwi_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_if;
+
+ if (!device_is_active(sc->sc_dev) ||
+ (ifp->if_flags & IFF_RUNNING) == 0)
+ return (0);
+
+ /* Disable all interrupts */
+ bwi_disable_intrs(sc, BWI_ALL_INTRS);
+
+ if (BWI_IS_SDIO(sc)) {
+ bwi_softintr(sc);
+ } else {
+ softint_schedule(sc->sc_soft_ih);
+ }
+
+ return (1);
+}
+
+int
bwi_attach(struct bwi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
@@ -853,10 +891,25 @@ bwi_attach(struct bwi_softc *sc)
/* [TRC: XXX Is this necessary?] */
s = splnet();
- sc->sc_soft_ih = softint_establish(SOFTINT_NET, bwi_softintr, sc);
- if (sc->sc_soft_ih == NULL) {
- error = ENXIO;
- goto fail;
+ if (BWI_IS_SDIO(sc)) {
+ error = workqueue_create(&sc->sc_taskq,
+ device_xname(sc->sc_dev), bwi_task, sc, PRI_NONE,
+ IPL_NET, 0);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "failed to create workqueue\n");
+ goto fail;
+ }
+ sc->sc_freetask = pool_cache_init(sizeof(struct bwi_task),
+ 0, 0, 0, "bwitask", NULL, IPL_NET, NULL, NULL, NULL);
+ pool_cache_prime(sc->sc_freetask, BWI_TASK_COUNT);
+ } else {
+ sc->sc_soft_ih = softint_establish(SOFTINT_NET, bwi_softintr,
+ sc);
+ if (sc->sc_soft_ih == NULL) {
+ error = ENXIO;
+ goto fail;
+ }
}
/*
@@ -945,7 +998,11 @@ bwi_attach(struct bwi_softc *sc)
bwi_bbp_power_off(sc);
- error = bwi_dma_alloc(sc);
+ if (BWI_IS_PIO(sc)) {
+ error = bwi_pio_alloc(sc);
+ } else {
+ error = bwi_dma_alloc(sc);
+ }
if (error)
goto fail;
@@ -1019,7 +1076,8 @@ bwi_attach(struct bwi_softc *sc)
ic->ic_state = IEEE80211_S_INIT;
ic->ic_opmode = IEEE80211_M_STA;
- ic->ic_updateslot = bwi_updateslot;
+ ic->ic_updateslot = BWI_IS_SDIO(sc) ?
+ bwi_updateslot_sdio : bwi_updateslot;
if_initialize(ifp);
ieee80211_ifattach(ic);
@@ -1030,7 +1088,7 @@ bwi_attach(struct bwi_softc *sc)
/* ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; */
sc->sc_newstate = ic->ic_newstate;
- ic->ic_newstate = bwi_newstate;
+ ic->ic_newstate = BWI_IS_SDIO(sc) ? bwi_newstate_sdio : bwi_newstate;
/* [TRC: XXX amrr] */
ic->ic_newassoc = bwi_newassoc;
ic->ic_node_alloc = bwi_node_alloc;
@@ -1085,7 +1143,17 @@ bwi_detach(struct bwi_softc *sc)
splx(s);
- bwi_dma_free(sc);
+ if (BWI_IS_PIO(sc)) {
+ bwi_pio_free(sc);
+ if (sc->sc_taskq != NULL) {
+ workqueue_destroy(sc->sc_taskq);
+ }
+ if (sc->sc_freetask != NULL) {
+ pool_cache_destroy(sc->sc_freetask);
+ }
+ } else {
+ bwi_dma_free(sc);
+ }
}
/* MAC */
@@ -1251,6 +1319,12 @@ bwi_mac_lateattach(struct bwi_mac *mac)
bwi_rf_off(mac);
CSR_WRITE_2(mac->mac_sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC);
+
+ if (BWI_IS_PIO(mac->mac_sc)) {
+ /* Initialize RX padding data offset */
+ MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_RXPADOFF, 0);
+ }
+
bwi_regwin_disable(mac->mac_sc, &mac->mac_regwin, 0);
return (0);
@@ -1527,7 +1601,7 @@ bwi_mac_test(struct bwi_mac *mac)
MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL1);
val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
if (val != TEST_VAL1) {
- aprint_error_dev(sc->sc_dev, "TEST1 failed\n");
+ aprint_error_dev(sc->sc_dev, "TEST1 failed [0x%08x]\n", val);
return (ENXIO);
}
@@ -1535,7 +1609,7 @@ bwi_mac_test(struct bwi_mac *mac)
MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL2);
val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0);
if (val != TEST_VAL2) {
- aprint_error_dev(sc->sc_dev, "TEST2 failed\n");
+ aprint_error_dev(sc->sc_dev, "TEST2 failed [0x%08x]\n", val);
return (ENXIO);
}
@@ -2552,6 +2626,12 @@ bwi_mac_get_property(struct bwi_mac *mac
* Byte swap
*/
val = CSR_READ_4(sc, BWI_MAC_STATUS);
+ if (BWI_IS_PIO(sc) && (val & BWI_MAC_STATUS_BSWAP)) {
+ DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "disable byte swap\n");
+ val &= ~BWI_MAC_STATUS_BSWAP;
+ CSR_WRITE_4(sc, BWI_MAC_STATUS, val);
+ val = CSR_READ_4(sc, BWI_MAC_STATUS);
+ }
if (val & BWI_MAC_STATUS_BSWAP) {
DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "need byte swap\n");
mac->mac_flags |= BWI_MAC_F_BSWAP;
@@ -6419,6 +6499,10 @@ bwi_power_on(struct bwi_softc *sc, int w
DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__);
+ if (BWI_IS_SDIO(sc)) {
+ return;
+ }
+
gpio_in = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_IN);
if (gpio_in & BWI_PCIM_GPIO_PWR_ON)
goto back;
@@ -6460,6 +6544,10 @@ bwi_power_off(struct bwi_softc *sc, int
DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__);
+ if (BWI_IS_SDIO(sc)) {
+ return (0);
+ }
+
(sc->sc_conf_read)(sc, BWI_PCIR_GPIO_IN); /* dummy read */
gpio_out = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT);
gpio_en = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_ENABLE);
@@ -6901,8 +6989,13 @@ bwi_bus_init(struct bwi_softc *sc, struc
bus = &sc->sc_bus_regwin;
KASSERT(sc->sc_cur_regwin == &mac->mac_regwin);
+ if (BWI_IS_SDIO(sc)) {
+ sc->sc_flags |= BWI_F_BUS_INITED;
+ return (0);
+ }
+
/*
- * Tell bus to generate requested interrupts
+ * Tell bus to generate requested interrupts (PCI and Cardbus only).
*/
if (bus->rw_rev < 6 && bus->rw_type == BWI_REGWIN_T_BUSPCI) {
/*
@@ -7038,7 +7131,8 @@ bwi_get_clock_freq(struct bwi_softc *sc,
src = -1;
div = 0;
if (com->rw_rev < 6) {
- val = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT);
+ val = BWI_IS_SDIO(sc) ?
+ 0 : (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT);
if (val & BWI_PCIM_GPIO_OUT_CLKSRC) {
src = BWI_CLKSRC_PCI;
div = 64;
@@ -7250,12 +7344,12 @@ bwi_init_statechg(struct bwi_softc *sc,
if (error)
goto back;
- /* Enable intrs */
- bwi_enable_intrs(sc, BWI_INIT_INTRS);
-
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
+ /* Enable intrs */
+ bwi_enable_intrs(sc, BWI_INIT_INTRS);
+
if (statechg) {
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
/* [TRC: XXX OpenBSD omits this conditional.] */
@@ -7274,6 +7368,8 @@ back:
else
/* [TRC: XXX DragonFlyBD uses ifp->if_start(ifp).] */
bwi_start(ifp);
+
+ DPRINTF(sc, BWI_DBG_MISC, "%s done\n", __func__);
}
static int
@@ -7503,6 +7599,24 @@ bwi_start(struct ifnet *ifp)
if (trans)
sc->sc_tx_timer = 5;
ifp->if_timer = 1;
+
+ if (BWI_IS_PIO(sc)) {
+ mutex_enter(&sc->sc_pio_txlock);
+ if (!STAILQ_EMPTY(&sc->sc_pio_txpend)) {
+ struct bwi_task *t;
+
+ t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
+ if (t == NULL) {
+ device_printf(sc->sc_dev, "no free tasks\n");
+ } else {
+ t->t_ic = &sc->sc_ic;
+ t->t_cmd = BWI_TASK_TX;
+ workqueue_enqueue(sc->sc_taskq, &t->t_work,
+ NULL);
+ }
+ }
+ mutex_exit(&sc->sc_pio_txlock);
+ }
}
static void
@@ -7549,6 +7663,8 @@ bwi_stop(struct ifnet *ifp, int state_ch
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC);
mac = (struct bwi_mac *)sc->sc_cur_regwin;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
bwi_disable_intrs(sc, BWI_ALL_INTRS);
CSR_READ_4(sc, BWI_MAC_INTR_MASK);
bwi_mac_stop(mac);
@@ -7668,16 +7784,178 @@ back:
}
static int
+bwi_newstate_sdio(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+{
+ struct bwi_softc *sc = ic->ic_ifp->if_softc;
+ struct bwi_task *t;
+
+ t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
+ if (t == NULL) {
+ device_printf(sc->sc_dev, "no free tasks\n");
+ return EIO;
+ }
+
+ t->t_ic = ic;
+ t->t_cmd = BWI_TASK_NEWSTATE;
+ t->t_newstate.state = nstate;
+ t->t_newstate.arg = arg;
+ workqueue_enqueue(sc->sc_taskq, &t->t_work, NULL);
+
+ return 0;
+}
+
+static inline bool
+bwi_tx_fifo_pkt_valid(struct bwi_softc *sc, u_int len)
+{
+ return len >= sizeof(uint32_t) && len <= sc->sc_pio_fifolen;
+}
+
+static inline bool
+bwi_tx_fifo_avail(struct bwi_softc *sc, u_int len)
+{
+ return len <= sc->sc_pio_fifoavail;
+}
+
+static void
+bwi_tx_frame_data_pio(struct bwi_softc *sc, u_int idx, uint32_t *ctl,
+ uint8_t *buf, u_int buflen)
+{
+ size_t count;
+
+ *ctl |= BWI_PIO_TXCTL_VALID_BYTES(4);
+ CSR_WRITE_4(sc, BWI_PIO_TXCTL(idx), *ctl);
+
+ count = buflen / sizeof(uint32_t);
+ CSR_WRITE_MULTI_4(sc, BWI_PIO_TXDATA(idx), (uint32_t *)buf, count);
+ buf += count * sizeof(uint32_t);
+ buflen -= count * sizeof(uint32_t);
+ if (buflen != 0) {
+ uint32_t data = 0;
+
+ *ctl &= ~BWI_PIO_TXCTL_VALID;
+ *ctl |= BWI_PIO_TXCTL_VALID_BYTES(buflen);
+ CSR_WRITE_4(sc, BWI_PIO_TXCTL(idx), *ctl);
+
+ memcpy(&data, buf, buflen);
+ CSR_WRITE_MULTI_4(sc, BWI_PIO_TXDATA(idx), &data, 1);
+ }
+}
+
+static void
+bwi_tx_frame_pio(struct bwi_softc *sc, struct bwi_txbuf *tb)
+{
+ struct mbuf *m = tb->tb_mbuf;
+ const u_int idx = BWI_TX_DATA_RING;
+ uint32_t ctl;
+ uint8_t *txbuf = sc->sc_pio_databuf;
+ u_int pktlen = m_length(m);
+
+ m_copydata(m, 0, pktlen, txbuf);
+
+ ctl = CSR_READ_4(sc, BWI_PIO_TXCTL(idx));
+ ctl |= BWI_PIO_TXCTL_FREADY;
+ ctl &= ~BWI_PIO_TXCTL_EOF;
+
+ bwi_tx_frame_data_pio(sc, idx, &ctl, txbuf, pktlen);
+
+ ctl |= BWI_PIO_TXCTL_EOF;
+ CSR_WRITE_4(sc, BWI_PIO_TXCTL(idx), ctl);
+}
+
+static void
+bwi_tx_pending(struct bwi_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_if;
+ struct bwi_txbuf *tb;
+
+ mutex_enter(&sc->sc_pio_txlock);
+ while ((tb = STAILQ_FIRST(&sc->sc_pio_txpend)) != NULL) {
+ const u_int pktlen = m_length(tb->tb_mbuf);
+
+ if (!bwi_tx_fifo_pkt_valid(sc, pktlen)) {
+ device_printf(sc->sc_dev,
+ "dropping large packet (%u bytes)\n", pktlen);
+
+ STAILQ_REMOVE_HEAD(&sc->sc_pio_txpend, tb_entry);
+ if_statinc(ifp, if_oerrors);
+ m_freem(tb->tb_mbuf);
+ tb->tb_mbuf = NULL;
+ continue;
+ }
+
+ if (!bwi_tx_fifo_avail(sc, pktlen)) {
+ break;
+ }
+
+ STAILQ_REMOVE_HEAD(&sc->sc_pio_txpend, tb_entry);
+
+ sc->sc_pio_fifoavail -= roundup(pktlen, 4);
+ mutex_exit(&sc->sc_pio_txlock);
+
+ bwi_tx_frame_pio(sc, tb);
+
+ mutex_enter(&sc->sc_pio_txlock);
+ }
+ mutex_exit(&sc->sc_pio_txlock);
+}
+
+static void
+bwi_task(struct work *wk, void *arg)
+{
+ struct bwi_task *t = (struct bwi_task *)wk;
+ struct ieee80211com *ic = t->t_ic;
+ struct bwi_softc *sc = ic->ic_ifp->if_softc;
+
+ switch (t->t_cmd) {
+ case BWI_TASK_NEWSTATE:
+ bwi_newstate(ic, t->t_newstate.state, t->t_newstate.arg);
+ break;
+ case BWI_TASK_UPDATESLOT:
+ bwi_updateslot(ic->ic_ifp);
+ break;
+ case BWI_TASK_TX:
+ bwi_tx_pending(sc);
+ break;
+ case BWI_TASK_INIT:
+ bwi_init(ic->ic_ifp);
+ break;
+ case BWI_TASK_CALIBRATE:
+ bwi_do_calibrate(sc);
+ break;
+ default:
+ panic("bwi: unknown task command %d", t->t_cmd);
+ }
+
+ pool_cache_put(sc->sc_freetask, t);
+}
+
+static int
bwi_media_change(struct ifnet *ifp)
{
+ struct bwi_softc *sc = ifp->if_softc;
int error;
error = ieee80211_media_change(ifp);
if (error != ENETRESET)
return (error);
- if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
- bwi_init(ifp);
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) {
+ if (BWI_IS_SDIO(sc)) {
+ struct bwi_task *t;
+
+ t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
+ if (t == NULL) {
+ device_printf(sc->sc_dev, "no free tasks\n");
+ return (ENOBUFS);
+ }
+
+ t->t_ic = &sc->sc_ic;
+ t->t_cmd = BWI_TASK_INIT;
+ workqueue_enqueue(sc->sc_taskq, &t->t_work, NULL);
+ } else {
+ bwi_init(ifp);
+ }
+ }
return (0);
}
@@ -7742,6 +8020,64 @@ bwi_node_alloc(struct ieee80211_node_tab
/* [TRC: XXX amrr end] */
static int
+bwi_pio_alloc(struct bwi_softc *sc)
+{
+ struct bwi_mac *mac = &sc->sc_mac[0];
+ int i, j, has_txstats;
+
+ KASSERT(BWI_IS_PIO(sc));
+
+ if (mac->mac_rev < 8) {
+ aprint_error_dev(sc->sc_dev,
+ "driver does not support MAC rev %u in PIO mode\n",
+ mac->mac_rev);
+ return EINVAL;
+ }
+
+ has_txstats = (mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) != 0;
+
+ sc->sc_init_tx_ring = bwi_init_tx_ring_pio;
+ sc->sc_free_tx_ring = bwi_free_tx_ring_pio;
+ sc->sc_init_rx_ring = bwi_init_rx_ring_pio;
+ sc->sc_free_rx_ring = bwi_free_rx_ring_pio;
+ sc->sc_setup_rxdesc = bwi_setup_rx_desc_pio;
+ sc->sc_setup_txdesc = bwi_setup_tx_desc_pio;
+ sc->sc_rxeof = bwi_rxeof_pio;
+ sc->sc_start_tx = bwi_start_tx_pio;
+ if (has_txstats) {
+ sc->sc_init_txstats = bwi_init_txstats_pio;
+ sc->sc_free_txstats = bwi_free_txstats_pio;
+ sc->sc_txeof_status = bwi_txeof_status_pio;
+ }
+
+ mutex_init(&sc->sc_pio_txlock, MUTEX_DEFAULT, IPL_NET);
+ STAILQ_INIT(&sc->sc_pio_txpend);
+
+ sc->sc_pio_fifolen = 2000 - 80;
+ sc->sc_pio_fifoavail = sc->sc_pio_fifolen;
+
+ sc->sc_pio_databuf = kmem_alloc(sc->sc_pio_fifolen, KM_SLEEP);
+
+ for (i = 0; i < BWI_TX_NRING; ++i) {
+ struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i];
+ for (j = 0; j < BWI_TX_NDESC; ++j) {
+ tbd->tbd_buf[j].tb_data = tbd;
+ }
+ }
+
+ return 0;
+}
+
+static void
+bwi_pio_free(struct bwi_softc *sc)
+{
+ KASSERT(BWI_IS_PIO(sc));
+
+ kmem_free(sc->sc_pio_databuf, sc->sc_pio_fifolen);
+ mutex_destroy(&sc->sc_pio_txlock);
+}
+
+static int
bwi_dma_alloc(struct bwi_softc *sc)
{
int error, i, has_txstats;
@@ -7750,6 +8086,8 @@ bwi_dma_alloc(struct bwi_softc *sc)
bus_size_t tx_ring_sz, rx_ring_sz, desc_sz = 0;
uint32_t txrx_ctrl_step = 0;
+ KASSERT(!BWI_IS_PIO(sc));
+
has_txstats = 0;
for (i = 0; i < sc->sc_nmac; ++i) {
if (sc->sc_mac[i].mac_flags & BWI_MAC_F_HAS_TXSTATS) {
@@ -7865,6 +8203,8 @@ bwi_dma_free(struct bwi_softc *sc)
{
int i;
+ KASSERT(!BWI_IS_PIO(sc));
+
for (i = 0; i < BWI_TX_NRING; ++i)
bwi_ring_data_free(&sc->sc_tx_rdata[i], sc);
@@ -8140,16 +8480,64 @@ bwi_dma_mbuf_destroy(struct bwi_softc *s
static void
bwi_enable_intrs(struct bwi_softc *sc, uint32_t enable_intrs)
{
+ DPRINTF(sc, BWI_DBG_INTR, "enable_intrs 0x%08x\n", enable_intrs);
CSR_SETBITS_4(sc, BWI_MAC_INTR_MASK, enable_intrs);
}
static void
bwi_disable_intrs(struct bwi_softc *sc, uint32_t disable_intrs)
{
+ DPRINTF(sc, BWI_DBG_INTR, "disable_intrs 0x%08x\n", disable_intrs);
CSR_CLRBITS_4(sc, BWI_MAC_INTR_MASK, disable_intrs);
}
static int
+bwi_init_tx_ring_pio(struct bwi_softc *sc, int ring_idx)
+{
+ return (0);
+}
+
+static int
+bwi_init_rx_ring_pio(struct bwi_softc *sc)
+{
+ uint32_t ctrl_base = BWI_TXRX_CTRL_BASE;
+ uint32_t val;
+ int error;
+
+ val = CSR_READ_4(sc, ctrl_base + BWI_RX32_CTRL);
+ val |= BWI_TXRX32_CTRL_ENABLE |
+ BWI_RX32_CTRL_DIRECT_FIFO;
+ CSR_WRITE_4(sc, ctrl_base + BWI_RX32_CTRL, val);
+
+ error = bwi_newbuf(sc, 0, 1);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "can't allocate RX buffer\n");
+ return (error);
+ }
+
+ return (0);
+}
+
+static int
+bwi_init_txstats_pio(struct bwi_softc *sc)
+{
+ return (0);
+}
+
+static void
+bwi_setup_rx_desc_pio(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr,
+ int buf_len)
+{
+}
+
+static void
+bwi_setup_tx_desc_pio(struct bwi_softc *sc, struct bwi_ring_data *rd,
+ int buf_idx, bus_addr_t paddr, int buf_len)
+{
+}
+
+static int
bwi_init_tx_ring32(struct bwi_softc *sc, int ring_idx)
{
struct bwi_ring_data *rd;
@@ -8320,7 +8708,7 @@ bwi_newbuf(struct bwi_softc *sc, int buf
bus_dmamap_t map;
bus_addr_t paddr;
struct mbuf *m;
- int error;
+ int error = 0;
KASSERT(buf_idx < BWI_RX_NDESC);
@@ -8343,35 +8731,39 @@ bwi_newbuf(struct bwi_softc *sc, int buf
}
m->m_len = m->m_pkthdr.len = MCLBYTES;
- /*
- * Try to load RX buf into temporary DMA map
- */
- error = bus_dmamap_load_mbuf(sc->sc_dmat, rbd->rbd_tmp_dmap, m,
- init ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT);
- if (error) {
- m_freem(m);
-
+ if (!BWI_IS_PIO(sc)) {
/*
- * See the comment above
+ * Try to load RX buf into temporary DMA map
*/
- if (init)
- return error;
- else
- goto back;
- }
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, rbd->rbd_tmp_dmap, m,
+ init ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT);
+ if (error) {
+ m_freem(m);
- if (!init)
- bus_dmamap_unload(sc->sc_dmat, rxbuf->rb_dmap);
+ /*
+ * See the comment above
+ */
+ if (init)
+ return error;
+ else
+ goto back;
+ }
+
+ if (!init)
+ bus_dmamap_unload(sc->sc_dmat, rxbuf->rb_dmap);
+ }
rxbuf->rb_mbuf = m;
- /*
- * Swap RX buf's DMA map with the loaded temporary one
- */
- map = rxbuf->rb_dmap;
- rxbuf->rb_dmap = rbd->rbd_tmp_dmap;
- rbd->rbd_tmp_dmap = map;
- paddr = rxbuf->rb_dmap->dm_segs[0].ds_addr;
- rxbuf->rb_paddr = paddr;
+ if (!BWI_IS_PIO(sc)) {
+ /*
+ * Swap RX buf's DMA map with the loaded temporary one
+ */
+ map = rxbuf->rb_dmap;
+ rxbuf->rb_dmap = rbd->rbd_tmp_dmap;
+ rbd->rbd_tmp_dmap = map;
+ paddr = rxbuf->rb_dmap->dm_segs[0].ds_addr;
+ rxbuf->rb_paddr = paddr;
+ }
back:
/*
@@ -8379,8 +8771,10 @@ back:
*/
hdr = mtod(rxbuf->rb_mbuf, struct bwi_rxbuf_hdr *);
memset(hdr, 0, sizeof(*hdr));
- bus_dmamap_sync(sc->sc_dmat, rxbuf->rb_dmap, 0,
- rxbuf->rb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE);
+ if (!BWI_IS_PIO(sc)) {
+ bus_dmamap_sync(sc->sc_dmat, rxbuf->rb_dmap, 0,
+ rxbuf->rb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE);
+ }
/*
* Setup RX buf descriptor
@@ -8558,6 +8952,184 @@ next:
return (rx_data);
}
+static void
+bwi_rx_frame_data_pio(struct bwi_softc *sc, struct bwi_rxbuf_hdr *hdr, int qid)
+{
+ struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
+ struct bwi_rxbuf *rb = &rbd->rbd_buf[0];
+ struct ieee80211_frame_min *wh;
+ struct ieee80211_node *ni;
+ struct ifnet *ifp = &sc->sc_if;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct mbuf *m;
+ const void *plcp;
+ uint16_t flags2;
+ int buflen, hdr_extra, rssi, type, rate;
+ int s;
+
+ m = rb->rb_mbuf;
+
+ if (bwi_newbuf(sc, 0, 0)) {
+ device_printf(sc->sc_dev, "couldn't create mbuf\n");
+ if_statinc(ifp, if_ierrors);
+ return;
+ }
+
+ flags2 = le16toh(hdr->rxh_flags2);
+
+ hdr_extra = 0;
+ if (flags2 & BWI_RXH_F2_TYPE2FRAME)
+ hdr_extra = 2;
+
+ buflen = le16toh(hdr->rxh_buflen);
+
+ /* Read the packet data into the mbuf */
+ CSR_READ_MULTI_4(sc, BWI_PIO_RXDATA(qid), mtod(m, uint32_t *),
+ buflen / sizeof(uint32_t));
+ if (buflen & 0x3) {
+ uint8_t data[4];
+ uint8_t *ppkt;
+ u_int resid;
+ u_int n;
+
+ resid = buflen & 0x3;
+ ppkt = mtod(m, uint8_t *) + (buflen & ~0x3);
+ CSR_READ_MULTI_4(sc, BWI_PIO_RXDATA(qid), (uint32_t *)&data, 1);
+ for (n = 0; n < resid; n++, ppkt++) {
+ *ppkt = data[n];
+ }
+ }
+
+ plcp = mtod(m, uint8_t *) + hdr_extra;
+ rssi = bwi_calc_rssi(sc, hdr);
+
+ m_set_rcvif(m, ifp);
+ m->m_len = m->m_pkthdr.len = buflen + hdr_extra;
+ m_adj(m, hdr_extra + 6);
+
+ if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM)
+ rate = bwi_ofdm_plcp2rate(plcp);
+ else
+ rate = bwi_ds_plcp2rate(plcp);
+
+ s = splnet();
+
+ /* RX radio tap */
+ if (sc->sc_drvbpf != NULL) {
+ struct mbuf mb;
+ struct bwi_rx_radiotap_hdr *tap = &sc->sc_rxtap;
+
+ tap->wr_tsf = hdr->rxh_tsf;
+ tap->wr_flags = 0;
+ tap->wr_rate = rate;
+ tap->wr_chan_freq =
+ htole16(ic->ic_bss->ni_chan->ic_freq);
+ tap->wr_chan_flags =
+ htole16(ic->ic_bss->ni_chan->ic_flags);
+ tap->wr_antsignal = rssi;
+ tap->wr_antnoise = BWI_NOISE_FLOOR;
+
+ mb.m_data = (void *)tap;
+ mb.m_len = sc->sc_rxtap_len;
+ mb.m_next = m;
+ mb.m_nextpkt = NULL;
+ mb.m_owner = NULL;
+ mb.m_type = 0;
+ mb.m_flags = 0;
+ bpf_mtap3(sc->sc_drvbpf, &mb, BPF_D_IN);
+ }
+
+ m_adj(m, -IEEE80211_CRC_LEN);
+
+ wh = mtod(m, struct ieee80211_frame_min *);
+ ni = ieee80211_find_rxnode(ic, wh);
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+ ieee80211_input(ic, m, ni, hdr->rxh_rssi,
+ le16toh(hdr->rxh_tsf));
+
+ ieee80211_free_node(ni);
+
+ if (type == IEEE80211_FC0_TYPE_DATA) {
+ sc->sc_rx_rate = rate;
+ }
+
+ splx(s);
+}
+
+static int
+bwi_rx_frame_pio(struct bwi_softc *sc)
+{
+ struct bwi_rxbuf_hdr rxh;
+ struct ifnet *ifp = &sc->sc_if;
+ const u_int qid = 0;
+ const size_t pio_hdrlen = 20;
+ uint32_t val;
+ uint16_t pktlen;
+ uint16_t flags2;
+ u_int n;
+
+ /* Check for frame ready bit and acknowledge it */
+ val = CSR_READ_4(sc, BWI_PIO_RXCTL(qid));
+ if ((val & BWI_PIO_RXCTL_FRAMERDY) == 0) {
+ return 0;
+ }
+ CSR_WRITE_4(sc, BWI_PIO_RXCTL(qid), BWI_PIO_RXCTL_FRAMERDY);
+
+ /* Wait for up to 100us for data ready */
+ for (n = 10; n > 0; n--) {
+ val = CSR_READ_4(sc, BWI_PIO_RXCTL(qid));
+ if ((val & BWI_PIO_RXCTL_DATARDY) != 0) {
+ break;
+ }
+ delay(10);
+ }
+ if (n == 0) {
+ device_printf(sc->sc_dev, "RX timeout\n");
+ if_statinc(ifp, if_ierrors);
+ goto ack;
+ }
+
+ /* Read 20 bytes of the packet RX header from the FIFO... */
+ CSR_READ_MULTI_4(sc, BWI_PIO_RXDATA(qid), (uint32_t *)&rxh,
+ pio_hdrlen / sizeof(uint32_t));
+ /* ... and zero the rest of it. */
+ memset(((uint8_t *)&rxh) + pio_hdrlen, 0, sizeof(rxh) - pio_hdrlen);
+
+ /* Validate packet */
+ pktlen = le16toh(rxh.rxh_buflen);
+ if (pktlen > 0x700 || pktlen == 0) {
+ device_printf(sc->sc_dev, "RX error (length %#x)\n", pktlen);
+ if_statinc(ifp, if_ierrors);
+ goto ack;
+ }
+ flags2 = le16toh(rxh.rxh_flags2);
+ if ((flags2 & BWI_RXH_F2_INVALID) != 0) {
+ device_printf(sc->sc_dev, "RX frame invalid\n");
+ if_statinc(ifp, if_ierrors);
+ goto ack;
+ }
+
+ /* Process frame data */
+ bwi_rx_frame_data_pio(sc, &rxh, qid);
+
+ack:
+ CSR_WRITE_4(sc, BWI_PIO_RXCTL(qid), BWI_PIO_RXCTL_DATARDY);
+ return 1;
+}
+
+static int
+bwi_rxeof_pio(struct bwi_softc *sc)
+{
+ unsigned npkt = 0;
+
+ while (bwi_rx_frame_pio(sc) && npkt++ < 1000) {
+ preempt_point();
+ }
+
+ return (npkt != 0);
+}
+
static int
bwi_rxeof32(struct bwi_softc *sc)
{
@@ -8611,12 +9183,28 @@ bwi_reset_rx_ring32(struct bwi_softc *sc
}
static void
+bwi_free_txstats_pio(struct bwi_softc *sc)
+{
+}
+
+static void
bwi_free_txstats32(struct bwi_softc *sc)
{
bwi_reset_rx_ring32(sc, sc->sc_txstats->stats_ctrl_base);
}
static void
+bwi_free_rx_ring_pio(struct bwi_softc *sc)
+{
+}
+
+static void
+bwi_free_tx_ring_pio(struct bwi_softc *sc, int ring_idx)
+{
+ bwi_free_tx_ring32(sc, ring_idx);
+}
+
+static void
bwi_free_rx_ring32(struct bwi_softc *sc)
{
struct bwi_ring_data *rd = &sc->sc_rx_rdata;
@@ -8685,7 +9273,9 @@ bwi_free_tx_ring32(struct bwi_softc *sc,
struct bwi_txbuf *tb = &tbd->tbd_buf[i];
if (tb->tb_mbuf != NULL) {
- bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap);
+ if (!BWI_IS_PIO(sc)) {
+ bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap);
+ }
m_freem(tb->tb_mbuf);
tb->tb_mbuf = NULL;
}
@@ -9165,18 +9755,24 @@ bwi_encap(struct bwi_softc *sc, int idx,
hdr = NULL;
wh = NULL;
- /* DMA load */
- error = bus_dmamap_load_mbuf(sc->sc_dmat, tb->tb_dmap, m,
- BUS_DMA_NOWAIT);
- if (error && error != EFBIG) {
- aprint_error_dev(sc->sc_dev, "can't load TX buffer (1) %d\n",
- error);
- goto back;
+ if (BWI_IS_PIO(sc)) {
+ error = 0;
+ } else {
+ /* DMA load */
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, tb->tb_dmap, m,
+ BUS_DMA_NOWAIT);
+ if (error && error != EFBIG) {
+ aprint_error_dev(sc->sc_dev,
+ "can't load TX buffer (1) %d\n", error);
+ goto back;
+ }
}
if (error) { /* error == EFBIG */
struct mbuf *m_new;
+ KASSERT(!BWI_IS_PIO(sc));
+
error = 0;
MGETHDR(m_new, M_DONTWAIT, MT_DATA);
@@ -9217,8 +9813,10 @@ bwi_encap(struct bwi_softc *sc, int idx,
}
error = 0;
- bus_dmamap_sync(sc->sc_dmat, tb->tb_dmap, 0,
- tb->tb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE);
+ if (!BWI_IS_PIO(sc)) {
+ bus_dmamap_sync(sc->sc_dmat, tb->tb_dmap, 0,
+ tb->tb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE);
+ }
if (mgt_pkt || mcast_pkt) {
/* Don't involve mcast/mgt packets into TX rate control */
@@ -9245,11 +9843,13 @@ bwi_encap(struct bwi_softc *sc, int idx,
DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n",
idx, pkt_len, m->m_pkthdr.len);
- /* Setup TX descriptor */
- paddr = tb->tb_dmap->dm_segs[0].ds_addr;
- (sc->sc_setup_txdesc)(sc, rd, idx, paddr, m->m_pkthdr.len);
- bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
- rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE);
+ if (!BWI_IS_PIO(sc)) {
+ /* Setup TX descriptor */
+ paddr = tb->tb_dmap->dm_segs[0].ds_addr;
+ (sc->sc_setup_txdesc)(sc, rd, idx, paddr, m->m_pkthdr.len);
+ bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
+ rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE);
+ }
/* Kick start */
(sc->sc_start_tx)(sc, rd->rdata_txrx_ctrl, idx);
@@ -9261,6 +9861,17 @@ back:
}
static void
+bwi_start_tx_pio(struct bwi_softc *sc, uint32_t tx_ctrl, int idx)
+{
+ struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING];
+ struct bwi_txbuf *tb = &tbd->tbd_buf[idx];
+
+ mutex_enter(&sc->sc_pio_txlock);
+ STAILQ_INSERT_TAIL(&sc->sc_pio_txpend, tb, tb_entry);
+ mutex_exit(&sc->sc_pio_txlock);
+}
+
+static void
bwi_start_tx32(struct bwi_softc *sc, uint32_t tx_ctrl, int idx)
{
idx = (idx + 1) % BWI_TX_NDESC;
@@ -9275,6 +9886,12 @@ bwi_start_tx64(struct bwi_softc *sc, uin
}
static void
+bwi_txeof_status_pio(struct bwi_softc *sc)
+{
+ /* TODO: PIO */
+}
+
+static void
bwi_txeof_status32(struct bwi_softc *sc)
{
struct ifnet *ifp = &sc->sc_if;
@@ -9331,7 +9948,15 @@ _bwi_txeof(struct bwi_softc *sc, uint16_
tb = &tbd->tbd_buf[buf_idx];
- bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap);
+ if (BWI_IS_PIO(sc)) {
+ mutex_enter(&sc->sc_pio_txlock);
+ const u_int pktlen = m_length(tb->tb_mbuf);
+ sc->sc_pio_fifoavail += roundup(pktlen, sizeof(uint32_t));
+ KASSERT(sc->sc_pio_fifoavail <= sc->sc_pio_fifolen);
+ mutex_exit(&sc->sc_pio_txlock);
+ } else {
+ bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap);
+ }
m_freem(tb->tb_mbuf);
tb->tb_mbuf = NULL;
@@ -9352,8 +9977,10 @@ bwi_txeof_status(struct bwi_softc *sc, i
struct bwi_txstats_data *st = sc->sc_txstats;
int idx;
- bus_dmamap_sync(sc->sc_dmat, st->stats_dmap, 0,
- st->stats_dmap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+ if (!BWI_IS_PIO(sc)) {
+ bus_dmamap_sync(sc->sc_dmat, st->stats_dmap, 0,
+ st->stats_dmap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+ }
idx = st->stats_idx;
while (idx != end_idx) {
@@ -9693,6 +10320,41 @@ bwi_updateslot(struct ifnet *ifp)
}
static void
+bwi_updateslot_sdio(struct ifnet *ifp)
+{
+ struct bwi_softc *sc = ifp->if_softc;
+ struct bwi_task *t;
+
+ t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
+ if (t == NULL) {
+ device_printf(sc->sc_dev, "no free tasks\n");
+ return;
+ }
+
+ t->t_ic = &sc->sc_ic;
+ t->t_cmd = BWI_TASK_UPDATESLOT;
+ workqueue_enqueue(sc->sc_taskq, &t->t_work, NULL);
+}
+
+static void
+bwi_do_calibrate(struct bwi_softc *sc)
+{
+ struct bwi_mac *mac;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC);
+ mac = (struct bwi_mac *)sc->sc_cur_regwin;
+
+ if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+ bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type);
+ sc->sc_txpwrcb_type = BWI_TXPWR_CALIB;
+ }
+
+ /* XXX 15 seconds */
+ callout_schedule(&sc->sc_calib_ch, hz * 15);
+}
+
+static void
bwi_calibrate(void *xsc)
{
struct bwi_softc *sc = xsc;
@@ -9702,18 +10364,22 @@ bwi_calibrate(void *xsc)
s = splnet();
if (ic->ic_state == IEEE80211_S_RUN) {
- struct bwi_mac *mac;
-
- KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC);
- mac = (struct bwi_mac *)sc->sc_cur_regwin;
+ if (BWI_IS_SDIO(sc)) {
+ struct bwi_task *t;
- if (ic->ic_opmode != IEEE80211_M_MONITOR) {
- bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type);
- sc->sc_txpwrcb_type = BWI_TXPWR_CALIB;
+ t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
+ if (t == NULL) {
+ device_printf(sc->sc_dev, "no free tasks\n");
+ callout_schedule(&sc->sc_calib_ch, hz * 15);
+ } else {
+ t->t_ic = &sc->sc_ic;
+ t->t_cmd = BWI_TASK_CALIBRATE;
+ workqueue_enqueue(sc->sc_taskq, &t->t_work,
+ NULL);
+ }
+ } else {
+ bwi_do_calibrate(sc);
}
-
- /* XXX 15 seconds */
- callout_schedule(&sc->sc_calib_ch, hz * 15);
}
splx(s);
Index: src/sys/dev/ic/bwireg.h
diff -u src/sys/dev/ic/bwireg.h:1.4 src/sys/dev/ic/bwireg.h:1.4.20.1
--- src/sys/dev/ic/bwireg.h:1.4 Mon May 18 05:47:54 2020
+++ src/sys/dev/ic/bwireg.h Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: bwireg.h,v 1.4 2020/05/18 05:47:54 msaitoh Exp $ */
+/* $NetBSD: bwireg.h,v 1.4.20.1 2025/02/02 14:29:59 martin Exp $ */
/* $OpenBSD: bwireg.h,v 1.7 2007/11/17 16:50:02 mglocker Exp $ */
/*
@@ -150,6 +150,18 @@
#define BWI_TXRX_INTR_STATUS(i) (BWI_TXRX_INTR_STATUS_BASE + ((i) * 8))
#define BWI_TXRX_INTR_MASK(i) (BWI_TXRX_INTR_MASK_BASE + ((i) * 8))
+#define BWI_PIO_TXCTL(qid) (0x0000300 + (qid) * 0x10 + 0x0)
+#define BWI_PIO_TXCTL_VALID (0xf << 0)
+#define BWI_PIO_TXCTL_VALID_BYTES(n) ((1 << (n)) - 1)
+#define BWI_PIO_TXCTL_EOF (1 << 4)
+#define BWI_PIO_TXCTL_FREADY (1 << 7)
+#define BWI_PIO_TXDATA(qid) (0x0000300 + (qid) * 0x10 + 0x4)
+
+#define BWI_PIO_RXCTL(qid) (0x0000300 + (qid) * 0x10 + 0x8)
+#define BWI_PIO_RXCTL_FRAMERDY (1 << 0)
+#define BWI_PIO_RXCTL_DATARDY (1 << 1)
+#define BWI_PIO_RXDATA(qid) (0x0000300 + (qid) * 0x10 + 0xc)
+
#define BWI_MAC_STATUS 0x00000120
#define BWI_MAC_STATUS_ENABLE (1 << 0)
#define BWI_MAC_STATUS_UCODE_START (1 << 1)
@@ -196,6 +208,7 @@
#define BWI_COMM_MOBJ_SLOTTIME 0x10
#define BWI_COMM_MOBJ_MACREV 0x16
#define BWI_COMM_MOBJ_TX_ACK 0x22
+#define BWI_COMM_MOBJ_RXPADOFF 0x34
#define BWI_COMM_MOBJ_UCODE_STATE 0x40
#define BWI_COMM_MOBJ_SHRETRY_FB 0x44
#define BWI_COMM_MOBJ_LGRETEY_FB 0x46
@@ -252,6 +265,7 @@
#define BWI_TX32_STATUS_STATE_STOPPED 3
#define BWI_RX32_CTRL 0x10
#define BWI_RX32_CTRL_HDRSZ_MASK 0x00fe
+#define BWI_RX32_CTRL_DIRECT_FIFO 0x0100
#define BWI_RX32_RINGINFO 0x14
#define BWI_RX32_INDEX 0x18
#define BWI_RX32_STATUS 0x1c
Index: src/sys/dev/ic/bwivar.h
diff -u src/sys/dev/ic/bwivar.h:1.10 src/sys/dev/ic/bwivar.h:1.10.46.1
--- src/sys/dev/ic/bwivar.h:1.10 Thu Feb 2 10:05:35 2017
+++ src/sys/dev/ic/bwivar.h Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: bwivar.h,v 1.10 2017/02/02 10:05:35 nonaka Exp $ */
+/* $NetBSD: bwivar.h,v 1.10.46.1 2025/02/02 14:29:59 martin Exp $ */
/* $OpenBSD: bwivar.h,v 1.23 2008/02/25 20:36:54 mglocker Exp $ */
/*
@@ -78,14 +78,18 @@ enum bwi_txpwrcb_type {
((hdr) + sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
#define CSR_READ_4(sc, reg) \
- bus_space_read_4((sc)->sc_mem_bt, (sc)->sc_mem_bh, (reg))
+ _bwi_read_4(sc, reg)
#define CSR_READ_2(sc, reg) \
- bus_space_read_2((sc)->sc_mem_bt, (sc)->sc_mem_bh, (reg))
+ _bwi_read_2(sc, reg)
+#define CSR_READ_MULTI_4(sc, reg, datap, count) \
+ _bwi_read_multi_4(sc, reg, datap, count)
#define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4((sc)->sc_mem_bt, (sc)->sc_mem_bh, (reg), (val))
+ _bwi_write_4(sc, reg, val)
#define CSR_WRITE_2(sc, reg, val) \
- bus_space_write_2((sc)->sc_mem_bt, (sc)->sc_mem_bh, (reg), (val))
+ _bwi_write_2(sc, reg, val)
+#define CSR_WRITE_MULTI_4(sc, reg, datap, count) \
+ _bwi_write_multi_4(sc, reg, datap, count)
#define CSR_SETBITS_4(sc, reg, bits) \
CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) | (bits))
@@ -102,6 +106,9 @@ enum bwi_txpwrcb_type {
#define CSR_CLRBITS_2(sc, reg, bits) \
CSR_WRITE_2((sc), (reg), CSR_READ_2((sc), (reg)) & ~(bits))
+struct pool_cache;
+struct workqueue;
+
struct bwi_desc32 {
/* Little endian */
uint32_t ctrl;
@@ -145,6 +152,7 @@ struct bwi_rxbuf_hdr {
#define BWI_RXH_F1_OFDM (1 << 0)
#define BWI_RXH_F2_TYPE2FRAME (1 << 2)
+#define BWI_RXH_F2_INVALID (1 << 0)
#define BWI_RXH_F3_BCM2050_RSSI (1 << 10)
@@ -207,12 +215,17 @@ struct bwi_ring_data {
void *rdata_desc;
};
+struct bwi_txbuf_data;
+
struct bwi_txbuf {
struct mbuf *tb_mbuf;
bus_dmamap_t tb_dmap;
struct ieee80211_node *tb_ni;
int tb_rate_idx[2];
+
+ struct bwi_txbuf_data *tb_data;
+ STAILQ_ENTRY(bwi_txbuf) tb_entry;
};
struct bwi_txbuf_data {
@@ -522,6 +535,28 @@ struct bwi_node {
struct ieee80211_amrr_node amn;
};
+enum bwi_task_cmd {
+ BWI_TASK_NEWSTATE,
+ BWI_TASK_UPDATESLOT,
+ BWI_TASK_TX,
+ BWI_TASK_INIT,
+ BWI_TASK_CALIBRATE,
+};
+
+#define BWI_TASK_COUNT 64
+
+struct bwi_task {
+ struct work t_work;
+ struct ieee80211com *t_ic;
+ enum bwi_task_cmd t_cmd;
+ union {
+ struct {
+ enum ieee80211_state state;
+ int arg;
+ } t_newstate;
+ };
+};
+
struct bwi_softc {
device_t sc_dev;
struct ethercom sc_ec;
@@ -627,6 +662,24 @@ struct bwi_softc {
void (*sc_conf_write)(void *, uint32_t, uint32_t);
uint32_t (*sc_conf_read)(void *, uint32_t);
+ void (*sc_reg_write_2)(void *, uint32_t, uint16_t);
+ uint16_t (*sc_reg_read_2)(void *, uint32_t);
+ void (*sc_reg_write_4)(void *, uint32_t, uint32_t);
+ uint32_t (*sc_reg_read_4)(void *, uint32_t);
+
+ void (*sc_reg_write_multi_4)(void *, uint32_t,
+ const uint32_t *, size_t);
+ void (*sc_reg_read_multi_4)(void *, uint32_t,
+ uint32_t *, size_t);
+
+ struct pool_cache *sc_freetask;
+ struct workqueue *sc_taskq;
+ uint8_t *sc_pio_databuf;
+ kmutex_t sc_pio_txlock;
+ STAILQ_HEAD(, bwi_txbuf) sc_pio_txpend;
+ size_t sc_pio_fifolen;
+ size_t sc_pio_fifoavail;
+
struct sysctllog *sc_sysctllog;
/* Sysctl variables */
@@ -654,8 +707,77 @@ struct bwi_softc {
int sc_txtap_len;
};
+static inline void
+_bwi_read_multi_4(struct bwi_softc *sc, bus_size_t reg, uint32_t *datap,
+ bus_size_t count)
+{
+ if (sc->sc_reg_read_multi_4 != NULL) {
+ return sc->sc_reg_read_multi_4(sc, reg, datap, count);
+ } else {
+ return bus_space_read_multi_4(sc->sc_mem_bt, sc->sc_mem_bh,
+ reg, datap, count);
+ }
+}
+
+static inline uint16_t
+_bwi_read_2(struct bwi_softc *sc, bus_size_t reg)
+{
+ if (sc->sc_reg_read_2 != NULL) {
+ return sc->sc_reg_read_2(sc, reg);
+ } else {
+ return bus_space_read_2(sc->sc_mem_bt, sc->sc_mem_bh, reg);
+ }
+}
+
+static inline uint32_t
+_bwi_read_4(struct bwi_softc *sc, bus_size_t reg)
+{
+ if (sc->sc_reg_read_4 != NULL) {
+ return sc->sc_reg_read_4(sc, reg);
+ } else {
+ return bus_space_read_4(sc->sc_mem_bt, sc->sc_mem_bh, reg);
+ }
+}
+
+static inline void
+_bwi_write_multi_4(struct bwi_softc *sc, bus_size_t reg, const uint32_t *datap,
+ bus_size_t count)
+{
+ if (sc->sc_reg_read_multi_4 != NULL) {
+ return sc->sc_reg_write_multi_4(sc, reg, datap, count);
+ } else {
+ return bus_space_write_multi_4(sc->sc_mem_bt, sc->sc_mem_bh,
+ reg, datap, count);
+ }
+}
+
+static inline void
+_bwi_write_2(struct bwi_softc *sc, bus_size_t reg, uint16_t val)
+{
+ if (sc->sc_reg_write_2 != NULL) {
+ sc->sc_reg_write_2(sc, reg, val);
+ } else {
+ bus_space_write_2(sc->sc_mem_bt, sc->sc_mem_bh, reg, val);
+ }
+}
+
+static inline void
+_bwi_write_4(struct bwi_softc *sc, bus_size_t reg, uint32_t val)
+{
+ if (sc->sc_reg_write_4 != NULL) {
+ sc->sc_reg_write_4(sc, reg, val);
+ } else {
+ bus_space_write_4(sc->sc_mem_bt, sc->sc_mem_bh, reg, val);
+ }
+}
+
#define BWI_F_BUS_INITED 0x1
#define BWI_F_PROMISC 0x2
+#define BWI_F_SDIO 0x4
+#define BWI_F_PIO 0x8
+
+#define BWI_IS_SDIO(sc) ISSET((sc)->sc_flags, BWI_F_SDIO)
+#define BWI_IS_PIO(sc) ISSET((sc)->sc_flags, BWI_F_PIO)
#define BWI_DBG_MAC 0x00000001
#define BWI_DBG_RF 0x00000002
Index: src/sys/dev/sdmmc/files.sdmmc
diff -u src/sys/dev/sdmmc/files.sdmmc:1.5 src/sys/dev/sdmmc/files.sdmmc:1.5.36.1
--- src/sys/dev/sdmmc/files.sdmmc:1.5 Tue Nov 7 16:30:32 2017
+++ src/sys/dev/sdmmc/files.sdmmc Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-# $NetBSD: files.sdmmc,v 1.5 2017/11/07 16:30:32 khorben Exp $
+# $NetBSD: files.sdmmc,v 1.5.36.1 2025/02/02 14:29:59 martin Exp $
# $OpenBSD: files.sdmmc,v 1.2 2006/06/01 21:53:41 uwe Exp $
#
# Config file and device description for machine-independent SD/MMC code.
@@ -25,3 +25,7 @@ file dev/sdmmc/sbt.c sbt
# Broadcom FullMAC SDIO wireless adapter
attach bwfm at sdmmc with bwfm_sdio
file dev/sdmmc/if_bwfm_sdio.c bwfm_sdio
+
+# Broadcom SoftMAC SDIO wireless driver
+attach bwi at sdmmc with bwi_sdio
+file dev/sdmmc/if_bwi_sdio.c bwi_sdio
Index: src/sys/dev/sdmmc/sdmmc_cis.c
diff -u src/sys/dev/sdmmc/sdmmc_cis.c:1.8.26.1 src/sys/dev/sdmmc/sdmmc_cis.c:1.8.26.2
--- src/sys/dev/sdmmc/sdmmc_cis.c:1.8.26.1 Mon Oct 14 17:47:00 2024
+++ src/sys/dev/sdmmc/sdmmc_cis.c Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmc_cis.c,v 1.8.26.1 2024/10/14 17:47:00 martin Exp $ */
+/* $NetBSD: sdmmc_cis.c,v 1.8.26.2 2025/02/02 14:29:59 martin Exp $ */
/* $OpenBSD: sdmmc_cis.c,v 1.1 2006/06/01 21:53:41 uwe Exp $ */
/*
@@ -20,7 +20,7 @@
/* Routines to decode the Card Information Structure of SD I/O cards */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.8.26.1 2024/10/14 17:47:00 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.8.26.2 2025/02/02 14:29:59 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -41,7 +41,6 @@ __KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,
#define DPRINTF(s) /**/
#endif
-static uint32_t sdmmc_cisptr(struct sdmmc_function *);
static void decode_funce_common(struct sdmmc_function *, struct sdmmc_cis *,
int, uint32_t);
static void decode_funce_function(struct sdmmc_function *, struct sdmmc_cis *,
@@ -49,7 +48,7 @@ static void decode_funce_function(struct
static void decode_vers_1(struct sdmmc_function *, struct sdmmc_cis *, int,
uint32_t);
-static uint32_t
+uint32_t
sdmmc_cisptr(struct sdmmc_function *sf)
{
uint32_t cisptr = 0;
@@ -108,7 +107,6 @@ decode_funce_lan_nid(struct sdmmc_functi
{
struct sdmmc_function *sf0 = sf->sc->sc_fn0;
device_t dev = sf->sc->sc_dev;
- uint8_t mac[6] __unused;
int i;
if (tpllen != 8) {
@@ -117,13 +115,19 @@ decode_funce_lan_nid(struct sdmmc_functi
return;
}
+ if (sdmmc_io_read_1(sf0, reg++) != 6) {
+ aprint_error_dev(dev,
+ "CISTPL_FUNCE(lan_nid) invalid\n");
+ }
+
for (i = 0; i < 6; i++) {
- mac[i] = sdmmc_io_read_1(sf0, reg++);
+ cis->lan_nid[i] = sdmmc_io_read_1(sf0, reg++);
}
DPRINTF(
("CISTPL_FUNCE: LAN_NID=%02x:%02x:%02x:%02x:%02x:%02x\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
+ cis->lan_nid[0], cis->lan_nid[1], cis->lan_nid[2],
+ cis->lan_nid[3], cis->lan_nid[4], cis->lan_nid[5]));
}
static void
Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.36.18.1 src/sys/dev/sdmmc/sdmmcvar.h:1.36.18.2
--- src/sys/dev/sdmmc/sdmmcvar.h:1.36.18.1 Sat Oct 26 15:26:43 2024
+++ src/sys/dev/sdmmc/sdmmcvar.h Sun Feb 2 14:29:59 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmcvar.h,v 1.36.18.1 2024/10/26 15:26:43 martin Exp $ */
+/* $NetBSD: sdmmcvar.h,v 1.36.18.2 2025/02/02 14:29:59 martin Exp $ */
/* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -187,6 +187,7 @@ struct sdmmc_cis {
u_char cis1_minor;
char cis1_info_buf[256];
char *cis1_info[4];
+ uint8_t lan_nid[6];
};
/*
@@ -393,6 +394,7 @@ int sdmmc_io_function_enable(struct sdmm
void sdmmc_io_function_disable(struct sdmmc_function *);
int sdmmc_io_function_abort(struct sdmmc_function *);
+uint32_t sdmmc_cisptr(struct sdmmc_function *);
int sdmmc_read_cis(struct sdmmc_function *, struct sdmmc_cis *);
void sdmmc_print_cis(struct sdmmc_function *);
void sdmmc_check_cis_quirks(struct sdmmc_function *);
Added files:
Index: src/sys/dev/sdmmc/if_bwi_sdio.c
diff -u /dev/null src/sys/dev/sdmmc/if_bwi_sdio.c:1.1.2.2
--- /dev/null Sun Feb 2 14:30:00 2025
+++ src/sys/dev/sdmmc/if_bwi_sdio.c Sun Feb 2 14:29:59 2025
@@ -0,0 +1,453 @@
+/* $NetBSD: if_bwi_sdio.c,v 1.1.2.2 2025/02/02 14:29:59 martin Exp $ */
+
+/*-
+ * Copyright (c) 2025 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(0, "$NetBSD: if_bwi_sdio.c,v 1.1.2.2 2025/02/02 14:29:59 martin Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <netinet/in.h>
+
+#include <net80211/ieee80211_node.h>
+#include <net80211/ieee80211_amrr.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_var.h>
+
+#include <dev/ic/bwireg.h>
+#include <dev/ic/bwivar.h>
+
+#include <dev/pcmcia/pcmciareg.h>
+
+#include <dev/sdmmc/sdmmcdevs.h>
+#include <dev/sdmmc/sdmmcvar.h>
+
+#define BWI_SDIO_FUNC1_SBADDRLOW 0x1000a
+#define BWI_SDIO_FUNC1_SBADDRMID 0x1000b
+#define BWI_SDIO_FUNC1_SBADDRHI 0x1000c
+
+#define BWI_CISTPL_VENDOR 0x80
+#define BWI_VENDOR_SROMREV 0
+#define BWI_VENDOR_ID 1
+#define BWI_VENDOR_BOARDREV 2
+#define BWI_VENDOR_PA 3
+#define BWI_VENDOR_OEMNAME 4
+#define BWI_VENDOR_CCODE 5
+#define BWI_VENDOR_ANTENNA 6
+#define BWI_VENDOR_ANTGAIN 7
+#define BWI_VENDOR_BFLAGS 8
+#define BWI_VENDOR_LEDS 9
+
+#define BWI_SDIO_REG_OFFSET(ssc, reg) \
+ ((reg) | ((ssc)->sc_sel_regwin & 0x7000))
+
+#define BWI_SDIO_REG_32BIT_ACCESS 0x8000
+
+static const struct bwi_sdio_product {
+ uint16_t vendor;
+ uint16_t product;
+} bwi_sdio_products[] = {
+ { SDMMC_VENDOR_BROADCOM, SDMMC_PRODUCT_BROADCOM_NINTENDO_WII },
+};
+
+struct bwi_sdio_sprom {
+ uint16_t pa_params[3];
+ uint16_t board_vendor;
+ uint16_t card_flags;
+ uint8_t srom_rev;
+ uint8_t board_rev;
+ uint8_t idle_tssi;
+ uint8_t max_txpwr;
+ uint8_t country_code;
+ uint8_t ant_avail;
+ uint8_t ant_gain;
+ uint8_t gpio[4];
+};
+
+struct bwi_sdio_softc {
+ struct bwi_softc sc_base;
+
+ struct sdmmc_function *sc_sf;
+ struct bwi_sdio_sprom sc_sprom;
+ uint32_t sc_sel_regwin;
+ kmutex_t sc_lock;
+};
+
+static int bwi_sdio_match(device_t, cfdata_t, void *);
+static void bwi_sdio_attach(device_t, device_t, void *);
+
+static void bwi_sdio_parse_cis(struct bwi_sdio_softc *);
+
+static int bwi_sdio_intr(void *);
+
+static void bwi_sdio_conf_write(void *, uint32_t, uint32_t);
+static uint32_t bwi_sdio_conf_read(void *, uint32_t);
+static void bwi_sdio_reg_write_2(void *, uint32_t, uint16_t);
+static uint16_t bwi_sdio_reg_read_2(void *, uint32_t);
+static void bwi_sdio_reg_write_4(void *, uint32_t, uint32_t);
+static uint32_t bwi_sdio_reg_read_4(void *, uint32_t);
+static void bwi_sdio_reg_write_multi_4(void *, uint32_t, const uint32_t *,
+ size_t);
+static void bwi_sdio_reg_read_multi_4(void *, uint32_t, uint32_t *,
+ size_t);
+
+CFATTACH_DECL_NEW(bwi_sdio, sizeof(struct bwi_sdio_softc),
+ bwi_sdio_match, bwi_sdio_attach, NULL, NULL);
+
+static int
+bwi_sdio_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct sdmmc_attach_args * const saa = aux;
+ struct sdmmc_function *sf = saa->sf;
+ struct sdmmc_cis *cis;
+ u_int n;
+
+ if (sf == NULL) {
+ return 0;
+ }
+ cis = &sf->sc->sc_fn0->cis;
+
+ for (n = 0; n < __arraycount(bwi_sdio_products); n++) {
+ const struct bwi_sdio_product *bsp = &bwi_sdio_products[n];
+
+ if (bsp->vendor == cis->manufacturer &&
+ bsp->product == cis->product) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+bwi_sdio_attach(device_t parent, device_t self, void *aux)
+{
+ struct bwi_sdio_softc * const ssc = device_private(self);
+ struct bwi_softc * const sc = &ssc->sc_base;
+ struct sdmmc_attach_args * const saa = aux;
+ struct sdmmc_function *sf = saa->sf;
+ struct sdmmc_cis *cis = &sf->sc->sc_fn0->cis;
+ int error;
+ void *ih;
+
+ aprint_naive("\n");
+ aprint_normal(": Broadcom Wireless\n");
+
+ sc->sc_dev = self;
+ sc->sc_flags = BWI_F_SDIO | BWI_F_PIO;
+ sc->sc_conf_write = bwi_sdio_conf_write;
+ sc->sc_conf_read = bwi_sdio_conf_read;
+ sc->sc_reg_write_multi_4 = bwi_sdio_reg_write_multi_4;
+ sc->sc_reg_read_multi_4 = bwi_sdio_reg_read_multi_4;
+ sc->sc_reg_write_2 = bwi_sdio_reg_write_2;
+ sc->sc_reg_read_2 = bwi_sdio_reg_read_2;
+ sc->sc_reg_write_4 = bwi_sdio_reg_write_4;
+ sc->sc_reg_read_4 = bwi_sdio_reg_read_4;
+ sc->sc_pci_revid = 0; /* XXX can this come from CIS? */
+ sc->sc_pci_did = cis->product;
+ sc->sc_pci_subvid = cis->manufacturer;
+ sc->sc_pci_subdid = cis->product;
+
+ ssc->sc_sf = sf;
+ mutex_init(&ssc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+
+ sdmmc_io_set_blocklen(ssc->sc_sf, 64);
+ if (sdmmc_io_function_enable(ssc->sc_sf) != 0) {
+ aprint_error_dev(self, "couldn't enable function\n");
+ return;
+ }
+
+ bwi_sdio_parse_cis(ssc);
+
+ ih = sdmmc_intr_establish(parent, bwi_sdio_intr, ssc,
+ device_xname(self));
+ if (ih == NULL) {
+ aprint_error_dev(self, "couldn't establish interrupt\n");
+ return;
+ }
+
+ error = bwi_attach(sc);
+ if (error != 0) {
+ sdmmc_intr_disestablish(ih);
+ return;
+ }
+
+ sdmmc_intr_enable(ssc->sc_sf);
+}
+
+static void
+bwi_sdio_parse_cis(struct bwi_sdio_softc *ssc)
+{
+ struct sdmmc_function *sf0 = ssc->sc_sf->sc->sc_fn0;
+ struct bwi_sdio_sprom *sprom = &ssc->sc_sprom;
+ uint32_t reg;
+ uint8_t tplcode, tpllen;
+
+ reg = sdmmc_cisptr(ssc->sc_sf);
+ for (;;) {
+ tplcode = sdmmc_io_read_1(sf0, reg++);
+ if (tplcode == PCMCIA_CISTPL_NULL) {
+ continue;
+ }
+ tpllen = sdmmc_io_read_1(sf0, reg++);
+ if (tplcode == PCMCIA_CISTPL_END || tpllen == 0) {
+ break;
+ }
+ if (tplcode != BWI_CISTPL_VENDOR) {
+ reg += tpllen;
+ continue;
+ }
+
+ switch (sdmmc_io_read_1(sf0, reg)) {
+ case BWI_VENDOR_SROMREV:
+ sprom->srom_rev = sdmmc_io_read_1(sf0, reg + 1);
+ break;
+ case BWI_VENDOR_ID:
+ sprom->board_vendor =
+ sdmmc_io_read_1(sf0, reg + 1) |
+ ((uint16_t)sdmmc_io_read_1(sf0, reg + 2) << 8);
+ break;
+ case BWI_VENDOR_BOARDREV:
+ sprom->board_rev =
+ sdmmc_io_read_1(sf0, reg + 1);
+ break;
+ case BWI_VENDOR_PA:
+ sprom->pa_params[0] =
+ sdmmc_io_read_1(sf0, reg + 1) |
+ ((uint16_t)sdmmc_io_read_1(sf0, reg + 2) << 8);
+ sprom->pa_params[1] =
+ sdmmc_io_read_1(sf0, reg + 3) |
+ ((uint16_t)sdmmc_io_read_1(sf0, reg + 4) << 8);
+ sprom->pa_params[2] =
+ sdmmc_io_read_1(sf0, reg + 5) |
+ ((uint16_t)sdmmc_io_read_1(sf0, reg + 6) << 8);
+ sprom->idle_tssi =
+ sdmmc_io_read_1(sf0, reg + 7);
+ sprom->max_txpwr =
+ sdmmc_io_read_1(sf0, reg + 8);
+ break;
+ case BWI_VENDOR_CCODE:
+ sprom->country_code =
+ sdmmc_io_read_1(sf0, reg + 1);
+ break;
+ case BWI_VENDOR_ANTGAIN:
+ sprom->ant_gain = sdmmc_io_read_1(sf0, reg + 1);
+ break;
+ case BWI_VENDOR_BFLAGS:
+ sprom->card_flags =
+ sdmmc_io_read_1(sf0, reg + 1) |
+ ((uint16_t)sdmmc_io_read_1(sf0, reg + 2) << 8);
+ break;
+ case BWI_VENDOR_LEDS:
+ sprom->gpio[0] = sdmmc_io_read_1(sf0, reg + 1);
+ sprom->gpio[1] = sdmmc_io_read_1(sf0, reg + 2);
+ sprom->gpio[2] = sdmmc_io_read_1(sf0, reg + 3);
+ sprom->gpio[3] = sdmmc_io_read_1(sf0, reg + 4);
+ break;
+ }
+
+ reg += tpllen;
+ }
+}
+
+static int
+bwi_sdio_intr(void *priv)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+
+ bwi_intr(&ssc->sc_base);
+
+ return 1;
+}
+
+static void
+bwi_sdio_conf_write(void *priv, uint32_t reg, uint32_t val)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+
+ KASSERT(reg == BWI_PCIR_SEL_REGWIN);
+
+ mutex_enter(&ssc->sc_lock);
+ if (reg == BWI_PCIR_SEL_REGWIN && ssc->sc_sel_regwin != val) {
+ sdmmc_io_write_1(ssc->sc_sf, BWI_SDIO_FUNC1_SBADDRLOW,
+ (val >> 8) & 0x80);
+ sdmmc_io_write_1(ssc->sc_sf, BWI_SDIO_FUNC1_SBADDRMID,
+ (val >> 16) & 0xff);
+ sdmmc_io_write_1(ssc->sc_sf, BWI_SDIO_FUNC1_SBADDRHI,
+ (val >> 24) & 0xff);
+ ssc->sc_sel_regwin = val;
+ }
+ mutex_exit(&ssc->sc_lock);
+}
+
+static uint32_t
+bwi_sdio_conf_read(void *priv, uint32_t reg)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+
+ KASSERT(reg == BWI_PCIR_SEL_REGWIN);
+
+ if (reg == BWI_PCIR_SEL_REGWIN) {
+ return ssc->sc_sel_regwin;
+ } else {
+ return 0;
+ }
+}
+
+static void
+bwi_sdio_reg_write_multi_4(void *priv, uint32_t reg, const uint32_t *datap,
+ size_t count)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+
+ mutex_enter(&ssc->sc_lock);
+ sdmmc_io_write_multi_1(ssc->sc_sf,
+ BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS,
+ (uint8_t *)__UNCONST(datap), count * sizeof(uint32_t));
+ mutex_exit(&ssc->sc_lock);
+}
+
+static void
+bwi_sdio_reg_read_multi_4(void *priv, uint32_t reg, uint32_t *datap,
+ size_t count)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+
+ mutex_enter(&ssc->sc_lock);
+ sdmmc_io_read_multi_1(ssc->sc_sf,
+ BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS,
+ (uint8_t *)datap, count * sizeof(uint32_t));
+ mutex_exit(&ssc->sc_lock);
+}
+
+static void
+bwi_sdio_reg_write_2(void *priv, uint32_t reg, uint16_t val)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+
+ val = htole16(val);
+
+ mutex_enter(&ssc->sc_lock);
+ sdmmc_io_write_2(ssc->sc_sf, BWI_SDIO_REG_OFFSET(ssc, reg), val);
+ mutex_exit(&ssc->sc_lock);
+}
+
+static uint16_t
+bwi_sdio_reg_read_sprom(struct bwi_sdio_softc *ssc, uint32_t reg)
+{
+ struct bwi_sdio_sprom *sprom = &ssc->sc_sprom;
+ struct sdmmc_cis *cis = &ssc->sc_sf->cis;
+
+ switch (reg) {
+ case BWI_SPROM_11BG_EADDR ... BWI_SPROM_11BG_EADDR + 4:
+ return *(uint16_t *)&cis->lan_nid[reg - BWI_SPROM_11BG_EADDR];
+ case BWI_SPROM_11A_EADDR ... BWI_SPROM_11A_EADDR + 4:
+ return *(uint16_t *)&cis->lan_nid[reg - BWI_SPROM_11A_EADDR];
+ case BWI_SPROM_CARD_INFO:
+ return (uint16_t)sprom->country_code << 8;
+ case BWI_SPROM_PA_PARAM_11BG ... BWI_SPROM_PA_PARAM_11BG + 4:
+ return sprom->pa_params[(reg - BWI_SPROM_PA_PARAM_11BG) / 2];
+ case BWI_SPROM_PA_PARAM_11A ... BWI_SPROM_PA_PARAM_11A + 4:
+ return sprom->pa_params[(reg - BWI_SPROM_PA_PARAM_11A) / 2];
+ case BWI_SPROM_GPIO01:
+ return sprom->gpio[0] | ((uint16_t)sprom->gpio[1] << 8);
+ case BWI_SPROM_GPIO23:
+ return sprom->gpio[2] | ((uint16_t)sprom->gpio[3] << 8);
+ case BWI_SPROM_MAX_TXPWR:
+ return sprom->max_txpwr | ((uint16_t)sprom->max_txpwr << 8);
+ case BWI_SPROM_IDLE_TSSI:
+ return sprom->idle_tssi | ((uint16_t)sprom->idle_tssi << 8);
+ case BWI_SPROM_CARD_FLAGS:
+ return sprom->card_flags;
+ case BWI_SPROM_ANT_GAIN:
+ return sprom->ant_gain | ((uint16_t)sprom->ant_gain << 8);
+ default:
+ return 0xffff;
+ }
+}
+
+static uint16_t
+bwi_sdio_reg_read_2(void *priv, uint32_t reg)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+ uint16_t val;
+
+ /* Emulate SPROM reads */
+ if (reg >= BWI_SPROM_START &&
+ reg <= BWI_SPROM_START + BWI_SPROM_ANT_GAIN) {
+ return bwi_sdio_reg_read_sprom(ssc, reg - BWI_SPROM_START);
+ }
+
+ mutex_enter(&ssc->sc_lock);
+ val = sdmmc_io_read_2(ssc->sc_sf, BWI_SDIO_REG_OFFSET(ssc, reg));
+ mutex_exit(&ssc->sc_lock);
+
+ val = le16toh(val);
+
+ return val;
+}
+
+static void
+bwi_sdio_reg_write_4(void *priv, uint32_t reg, uint32_t val)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+
+ val = htole32(val);
+
+ mutex_enter(&ssc->sc_lock);
+ sdmmc_io_write_4(ssc->sc_sf,
+ BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS, val);
+ /* SDIO cards require a read after a 32-bit write */
+ sdmmc_io_read_4(ssc->sc_sf, 0);
+ mutex_exit(&ssc->sc_lock);
+}
+
+static uint32_t
+bwi_sdio_reg_read_4(void *priv, uint32_t reg)
+{
+ struct bwi_sdio_softc * const ssc = priv;
+ uint32_t val;
+
+ mutex_enter(&ssc->sc_lock);
+ val = sdmmc_io_read_4(ssc->sc_sf,
+ BWI_SDIO_REG_OFFSET(ssc, reg) | BWI_SDIO_REG_32BIT_ACCESS);
+ mutex_exit(&ssc->sc_lock);
+
+ val = le32toh(val);
+
+ return val;
+}