summaryrefslogtreecommitdiffstats
path: root/sys/dev/ipw
diff options
context:
space:
mode:
authordamien <damien@FreeBSD.org>2006-03-12 19:01:00 +0000
committerdamien <damien@FreeBSD.org>2006-03-12 19:01:00 +0000
commitc30e4662deca0ed3c2e900a2f4aa514f5e986690 (patch)
tree6bab3065b3c8ab33fb158e3d4730dbf9fe23ceab /sys/dev/ipw
parent0deb63e3848dd85b797ae4a3217f88995c22b755 (diff)
downloadFreeBSD-src-c30e4662deca0ed3c2e900a2f4aa514f5e986690.zip
FreeBSD-src-c30e4662deca0ed3c2e900a2f4aa514f5e986690.tar.gz
sync w/ iwi:
o fix locking o use firmware(9) o cosmetic
Diffstat (limited to 'sys/dev/ipw')
-rw-r--r--sys/dev/ipw/if_ipw.c366
-rw-r--r--sys/dev/ipw/if_ipwreg.h132
-rw-r--r--sys/dev/ipw/if_ipwvar.h21
3 files changed, 252 insertions, 267 deletions
diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c
index 8a8d93d..9f23918 100644
--- a/sys/dev/ipw/if_ipw.c
+++ b/sys/dev/ipw/if_ipw.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*-
- * Copyright (c) 2004, 2005
+ * Copyright (c) 2004-2006
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,9 +43,13 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/endian.h>
+#include <sys/linker.h>
+#include <sys/firmware.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -63,15 +67,15 @@ __FBSDID("$FreeBSD$");
#include <net/if_media.h>
#include <net/if_types.h>
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
-#include <net80211/ieee80211_var.h>
-#include <net80211/ieee80211_radiotap.h>
-
#include <dev/ipw/if_ipwreg.h>
#include <dev/ipw/if_ipwvar.h>
@@ -87,6 +91,7 @@ SYSCTL_INT(_debug, OID_AUTO, ipw, CTLFLAG_RW, &ipw_debug, 0, "ipw debug level");
MODULE_DEPEND(ipw, pci, 1, 1, 1);
MODULE_DEPEND(ipw, wlan, 1, 1, 1);
+MODULE_DEPEND(ipw, firmware, 1, 1, 1);
struct ipw_ident {
uint16_t vendor;
@@ -123,11 +128,10 @@ static void ipw_watchdog(struct ifnet *);
static int ipw_ioctl(struct ifnet *, u_long, caddr_t);
static void ipw_stop_master(struct ipw_softc *);
static int ipw_reset(struct ipw_softc *);
-static int ipw_load_ucode(struct ipw_softc *, u_char *, int);
-static int ipw_load_firmware(struct ipw_softc *, u_char *, int);
-static int ipw_cache_firmware(struct ipw_softc *, void *);
-static void ipw_free_firmware(struct ipw_softc *);
+static int ipw_load_ucode(struct ipw_softc *, const char *, int);
+static int ipw_load_firmware(struct ipw_softc *, const char *, int);
static int ipw_config(struct ipw_softc *);
+static void ipw_init_task(void *, int);
static void ipw_init(void *);
static void ipw_stop(void *);
static int ipw_sysctl_stats(SYSCTL_HANDLER_ARGS);
@@ -138,8 +142,8 @@ static int ipw_read_table2(struct ipw_softc *, uint32_t, void *,
uint32_t *);
static void ipw_read_mem_1(struct ipw_softc *, bus_size_t, uint8_t *,
bus_size_t);
-static void ipw_write_mem_1(struct ipw_softc *, bus_size_t, uint8_t *,
- bus_size_t);
+static void ipw_write_mem_1(struct ipw_softc *, bus_size_t,
+ const uint8_t *, bus_size_t);
static int ipw_probe(device_t);
static int ipw_attach(device_t);
@@ -176,20 +180,6 @@ DRIVER_MODULE(ipw, pci, ipw_driver, ipw_devclass, 0, 0);
static const struct ieee80211_rateset ipw_rateset_11b =
{ 4, { 2, 4, 11, 22 } };
-static __inline uint8_t
-MEM_READ_1(struct ipw_softc *sc, uint32_t addr)
-{
- CSR_WRITE_4(sc, IPW_CSR_INDIRECT_ADDR, addr);
- return CSR_READ_1(sc, IPW_CSR_INDIRECT_DATA);
-}
-
-static __inline uint32_t
-MEM_READ_4(struct ipw_softc *sc, uint32_t addr)
-{
- CSR_WRITE_4(sc, IPW_CSR_INDIRECT_ADDR, addr);
- return CSR_READ_4(sc, IPW_CSR_INDIRECT_DATA);
-}
-
static int
ipw_probe(device_t dev)
{
@@ -222,6 +212,8 @@ ipw_attach(device_t dev)
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF | MTX_RECURSE);
+ TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc);
+
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
device_printf(dev, "chip is in D%d power mode "
"-- setting to D0\n", pci_get_powerstate(dev));
@@ -285,8 +277,11 @@ ipw_attach(device_t dev)
ic->ic_state = IEEE80211_S_INIT;
/* set device capabilities */
- ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
- IEEE80211_C_PMGT | IEEE80211_C_IBSS | IEEE80211_C_MONITOR;
+ ic->ic_caps =
+ IEEE80211_C_IBSS | /* IBSS mode supported */
+ IEEE80211_C_MONITOR | /* monitor mode supported */
+ IEEE80211_C_TXPMGT | /* tx power management */
+ IEEE80211_C_SHPREAMBLE; /* short preamble supported */
/* read MAC address from EEPROM */
val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0);
@@ -381,12 +376,7 @@ ipw_detach(device_t dev)
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
- IPW_LOCK(sc);
-
ipw_stop(sc);
- ipw_free_firmware(sc);
-
- IPW_UNLOCK(sc);
if (ifp != NULL) {
bpfdetach(ifp);
@@ -402,6 +392,7 @@ ipw_detach(device_t dev)
if (sc->mem != NULL)
bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
+
if (ifp != NULL)
if_free(ifp);
@@ -723,7 +714,7 @@ ipw_resume(device_t dev)
struct ipw_softc *sc = device_get_softc(dev);
struct ifnet *ifp = sc->sc_ic.ic_ifp;
- IPW_LOCK(sc);
+ mtx_lock(&sc->sc_mtx);
pci_write_config(dev, 0x41, 0, 1);
@@ -733,7 +724,7 @@ ipw_resume(device_t dev)
ifp->if_start(ifp);
}
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
return 0;
}
@@ -744,25 +735,25 @@ ipw_media_change(struct ifnet *ifp)
struct ipw_softc *sc = ifp->if_softc;
int error;
- IPW_LOCK(sc);
+ mtx_lock(&sc->sc_mtx);
error = ieee80211_media_change(ifp);
if (error != ENETRESET) {
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
return error;
}
if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
ipw_init(sc);
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
return 0;
}
/*
- * The firmware automaticly adapt the transmit speed. We report the current
- * transmit speed here.
+ * The firmware automatically adapts the transmit speed. We report its current
+ * value here.
*/
static void
ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
@@ -852,6 +843,7 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
}
ic->ic_state = nstate;
+
return 0;
}
@@ -1073,8 +1065,8 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
tap->wr_flags = 0;
tap->wr_antsignal = status->rssi;
- tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
- tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
+ tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
@@ -1223,26 +1215,27 @@ ipw_intr(void *arg)
struct ipw_softc *sc = arg;
uint32_t r;
- IPW_LOCK(sc);
+ mtx_lock(&sc->sc_mtx);
if ((r = CSR_READ_4(sc, IPW_CSR_INTR)) == 0 || r == 0xffffffff) {
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
return;
}
/* disable interrupts */
CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
+ /* acknowledge all interrupts */
+ CSR_WRITE_4(sc, IPW_CSR_INTR, r);
+
if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) {
- device_printf(sc->sc_dev, "fatal error\n");
- sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
- ipw_stop(sc);
+ device_printf(sc->sc_dev, "firmware error\n");
+ taskqueue_enqueue_fast(taskqueue_fast, &sc->sc_init_task);
+ r = 0; /* don't process more interrupts */
}
- if (r & IPW_INTR_FW_INIT_DONE) {
- if (!(r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)))
- wakeup(sc);
- }
+ if (r & IPW_INTR_FW_INIT_DONE)
+ wakeup(sc);
if (r & IPW_INTR_RX_TRANSFER)
ipw_rx_intr(sc);
@@ -1250,13 +1243,10 @@ ipw_intr(void *arg)
if (r & IPW_INTR_TX_TRANSFER)
ipw_tx_intr(sc);
- /* acknowledge all interrupts */
- CSR_WRITE_4(sc, IPW_CSR_INTR, r);
-
/* re-enable interrupts */
CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK);
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
}
static void
@@ -1348,8 +1338,8 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
struct ipw_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
- tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
- tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
+ tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
}
@@ -1475,10 +1465,10 @@ ipw_start(struct ifnet *ifp)
struct ether_header *eh;
struct ieee80211_node *ni;
- IPW_LOCK(sc);
+ mtx_lock(&sc->sc_mtx);
if (ic->ic_state != IEEE80211_S_RUN) {
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
return;
}
@@ -1525,7 +1515,7 @@ ipw_start(struct ifnet *ifp)
ifp->if_timer = 1;
}
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
}
static void
@@ -1534,20 +1524,25 @@ ipw_watchdog(struct ifnet *ifp)
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
+ mtx_lock(&sc->sc_mtx);
+
ifp->if_timer = 0;
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
if_printf(ifp, "device timeout\n");
ifp->if_oerrors++;
- ifp->if_flags &= ~IFF_UP;
- ipw_stop(sc);
+ taskqueue_enqueue_fast(taskqueue_fast,
+ &sc->sc_init_task);
+ mtx_unlock(&sc->sc_mtx);
return;
}
ifp->if_timer = 1;
}
ieee80211_watchdog(ic);
+
+ mtx_unlock(&sc->sc_mtx);
}
static int
@@ -1555,10 +1550,9 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
- struct ifreq *ifr;
int error = 0;
- IPW_LOCK(sc);
+ mtx_lock(&sc->sc_mtx);
switch (cmd) {
case SIOCSIFFLAGS:
@@ -1571,25 +1565,6 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
break;
- case SIOCSLOADFW:
- /* only super-user can do that! */
- if ((error = suser(curthread)) != 0)
- break;
-
- ifr = (struct ifreq *)data;
- error = ipw_cache_firmware(sc, ifr->ifr_data);
- break;
-
- case SIOCSKILLFW:
- /* only super-user can do that! */
- if ((error = suser(curthread)) != 0)
- break;
-
- ifp->if_flags &= ~IFF_UP;
- ipw_stop(sc);
- ipw_free_firmware(sc);
- break;
-
default:
error = ieee80211_ioctl(ic, cmd, data);
}
@@ -1601,7 +1576,7 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = 0;
}
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
return error;
}
@@ -1609,6 +1584,7 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
static void
ipw_stop_master(struct ipw_softc *sc)
{
+ uint32_t tmp;
int ntries;
/* disable interrupts */
@@ -1623,8 +1599,8 @@ ipw_stop_master(struct ipw_softc *sc)
if (ntries == 50)
device_printf(sc->sc_dev, "timeout waiting for master\n");
- CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
- IPW_RST_PRINCETON_RESET);
+ tmp = CSR_READ_4(sc, IPW_CSR_RST);
+ CSR_WRITE_4(sc, IPW_CSR_RST, tmp | IPW_RST_PRINCETON_RESET);
sc->flags &= ~IPW_FLAG_FW_INITED;
}
@@ -1632,13 +1608,14 @@ ipw_stop_master(struct ipw_softc *sc)
static int
ipw_reset(struct ipw_softc *sc)
{
+ uint32_t tmp;
int ntries;
ipw_stop_master(sc);
/* move adapter to D0 state */
- CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
- IPW_CTL_INIT);
+ tmp = CSR_READ_4(sc, IPW_CSR_CTL);
+ CSR_WRITE_4(sc, IPW_CSR_CTL, tmp | IPW_CTL_INIT);
/* wait for clock stabilization */
for (ntries = 0; ntries < 1000; ntries++) {
@@ -1649,13 +1626,13 @@ ipw_reset(struct ipw_softc *sc)
if (ntries == 1000)
return EIO;
- CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
- IPW_RST_SW_RESET);
+ tmp = CSR_READ_4(sc, IPW_CSR_RST);
+ CSR_WRITE_4(sc, IPW_CSR_RST, tmp | IPW_RST_SW_RESET);
DELAY(10);
- CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
- IPW_CTL_INIT);
+ tmp = CSR_READ_4(sc, IPW_CSR_CTL);
+ CSR_WRITE_4(sc, IPW_CSR_CTL, tmp | IPW_CTL_INIT);
return 0;
}
@@ -1664,7 +1641,7 @@ ipw_reset(struct ipw_softc *sc)
* Upload the microcode to the device.
*/
static int
-ipw_load_ucode(struct ipw_softc *sc, u_char *uc, int size)
+ipw_load_ucode(struct ipw_softc *sc, const char *uc, int size)
{
int ntries;
@@ -1716,10 +1693,10 @@ ipw_load_ucode(struct ipw_softc *sc, u_char *uc, int size)
#define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24)
#define GETLE16(p) ((p)[0] | (p)[1] << 8)
static int
-ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
+ipw_load_firmware(struct ipw_softc *sc, const char *fw, int size)
{
- u_char *p, *end;
- uint32_t dst;
+ const uint8_t *p, *end;
+ uint32_t tmp, dst;
uint16_t len;
int error;
@@ -1742,8 +1719,8 @@ ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
/* kick the firmware */
CSR_WRITE_4(sc, IPW_CSR_RST, 0);
- CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
- IPW_CTL_ALLOW_STANDBY);
+ tmp = CSR_READ_4(sc, IPW_CSR_CTL);
+ CSR_WRITE_4(sc, IPW_CSR_CTL, tmp | IPW_CTL_ALLOW_STANDBY);
/* wait at most one second for firmware initialization to complete */
if ((error = msleep(sc, &sc->sc_mtx, 0, "ipwinit", hz)) != 0) {
@@ -1752,80 +1729,11 @@ ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
return error;
}
- CSR_WRITE_4(sc, IPW_CSR_IO, CSR_READ_4(sc, IPW_CSR_IO) |
- IPW_IO_GPIO1_MASK | IPW_IO_GPIO3_MASK);
-
- return 0;
-}
-
-/*
- * Store firmware into kernel memory so we can download it when we need to,
- * e.g when the adapter wakes up from suspend mode.
- */
-static int
-ipw_cache_firmware(struct ipw_softc *sc, void *data)
-{
- struct ipw_firmware *fw = &sc->fw;
- struct ipw_firmware_hdr hdr;
- u_char *p = data;
- int error;
-
- ipw_free_firmware(sc);
-
- IPW_UNLOCK(sc);
-
- if ((error = copyin(data, &hdr, sizeof hdr)) != 0)
- goto fail1;
-
- fw->main_size = le32toh(hdr.main_size);
- fw->ucode_size = le32toh(hdr.ucode_size);
- p += sizeof hdr;
-
- fw->main = malloc(fw->main_size, M_DEVBUF, M_NOWAIT);
- if (fw->main == NULL) {
- error = ENOMEM;
- goto fail1;
- }
-
- fw->ucode = malloc(fw->ucode_size, M_DEVBUF, M_NOWAIT);
- if (fw->ucode == NULL) {
- error = ENOMEM;
- goto fail2;
- }
-
- if ((error = copyin(p, fw->main, fw->main_size)) != 0)
- goto fail3;
-
- p += fw->main_size;
- if ((error = copyin(p, fw->ucode, fw->ucode_size)) != 0)
- goto fail3;
-
- DPRINTF(("Firmware cached: main %u, ucode %u\n", fw->main_size,
- fw->ucode_size));
-
- IPW_LOCK(sc);
-
- sc->flags |= IPW_FLAG_FW_CACHED;
+ tmp = CSR_READ_4(sc, IPW_CSR_IO);
+ CSR_WRITE_4(sc, IPW_CSR_IO, tmp | IPW_IO_GPIO1_MASK |
+ IPW_IO_GPIO3_MASK);
return 0;
-
-fail3: free(fw->ucode, M_DEVBUF);
-fail2: free(fw->main, M_DEVBUF);
-fail1: IPW_LOCK(sc);
-
- return error;
-}
-
-static void
-ipw_free_firmware(struct ipw_softc *sc)
-{
- if (!(sc->flags & IPW_FLAG_FW_CACHED))
- return;
-
- free(sc->fw.main, M_DEVBUF);
- free(sc->fw.ucode, M_DEVBUF);
-
- sc->flags &= ~IPW_FLAG_FW_CACHED;
}
static int
@@ -1846,12 +1754,10 @@ ipw_config(struct ipw_softc *sc)
case IEEE80211_M_HOSTAP:
data = htole32(IPW_MODE_BSS);
break;
-
case IEEE80211_M_IBSS:
case IEEE80211_M_AHDEMO:
data = htole32(IPW_MODE_IBSS);
break;
-
case IEEE80211_M_MONITOR:
data = htole32(IPW_MODE_MONITOR);
break;
@@ -1863,7 +1769,7 @@ ipw_config(struct ipw_softc *sc)
if (ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_MONITOR) {
- data = htole32(ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
+ data = htole32(ieee80211_chan2ieee(ic, ic->ic_curchan));
DPRINTF(("Setting channel to %u\n", le32toh(data)));
error = ipw_cmd(sc, IPW_CMD_SET_CHANNEL, &data, sizeof data);
if (error != 0)
@@ -2035,33 +1941,102 @@ ipw_config(struct ipw_softc *sc)
return ipw_cmd(sc, IPW_CMD_ENABLE, NULL, 0);
}
+/*
+ * Handler for sc_init_task. This is a simple wrapper around ipw_init().
+ * It is called on firmware panics or on watchdog timeouts.
+ */
+static void
+ipw_init_task(void *context, int pending)
+{
+ ipw_init(context);
+}
+
static void
ipw_init(void *priv)
{
struct ipw_softc *sc = priv;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
- struct ipw_firmware *fw = &sc->fw;
-
- /* exit immediately if firmware has not been ioctl'd */
- if (!(sc->flags & IPW_FLAG_FW_CACHED)) {
- if (!(sc->flags & IPW_FLAG_FW_WARNED))
- device_printf(sc->sc_dev, "Please load firmware\n");
- sc->flags |= IPW_FLAG_FW_WARNED;
- ifp->if_flags &= ~IFF_UP;
+ struct firmware *fp;
+ const struct ipw_firmware_hdr *hdr;
+ const char *imagename, *fw;
+ int owned;
+
+ /*
+ * ipw_init() is exposed through ifp->if_init so it might be called
+ * without the driver's lock held. Since msleep() doesn't like being
+ * called on a recursed mutex, we acquire the driver's lock only if
+ * we're not already holding it.
+ */
+ if (!(owned = mtx_owned(&sc->sc_mtx)))
+ mtx_lock(&sc->sc_mtx);
+
+ /*
+ * Avoid re-entrant calls. We need to release the mutex in ipw_init()
+ * when loading the firmware and we don't want to be called during this
+ * operation.
+ */
+ if (sc->flags & IPW_FLAG_INIT_LOCKED) {
+ if (!owned)
+ mtx_unlock(&sc->sc_mtx);
return;
}
+ sc->flags |= IPW_FLAG_INIT_LOCKED;
ipw_stop(sc);
if (ipw_reset(sc) != 0) {
device_printf(sc->sc_dev, "could not reset adapter\n");
- goto fail;
+ goto fail1;
+ }
+
+ switch (ic->ic_opmode) {
+ case IEEE80211_M_STA:
+ imagename = "ipw_bss";
+ break;
+ case IEEE80211_M_IBSS:
+ imagename = "ipw_ibss";
+ break;
+ case IEEE80211_M_MONITOR:
+ imagename = "ipw_monitor";
+ break;
+ default:
+ imagename = NULL; /* should not get there */
+ }
+
+ /*
+ * Load firmware image using the firmware(9) subsystem. We need to
+ * release the driver's lock first.
+ */
+ mtx_unlock(&sc->sc_mtx);
+ fp = firmware_get(imagename);
+ mtx_lock(&sc->sc_mtx);
+
+ if (fp == NULL) {
+ device_printf(sc->sc_dev,
+ "could not load firmware image '%s'\n", imagename);
+ goto fail1;
+ }
+
+ if (fp->datasize < sizeof *hdr) {
+ device_printf(sc->sc_dev,
+ "firmware image too short %zu\n", fp->datasize);
+ goto fail2;
+ }
+
+ hdr = (const struct ipw_firmware_hdr *)fp->data;
+
+ if (fp->datasize < sizeof *hdr + le32toh(hdr->mainsz) +
+ le32toh(hdr->ucodesz)) {
+ device_printf(sc->sc_dev,
+ "firmware image too short %zu\n", fp->datasize);
+ goto fail2;
}
- if (ipw_load_ucode(sc, fw->ucode, fw->ucode_size) != 0) {
+ fw = (const char *)fp->data + sizeof *hdr + le32toh(hdr->mainsz);
+ if (ipw_load_ucode(sc, fw, le32toh(hdr->ucodesz)) != 0) {
device_printf(sc->sc_dev, "could not load microcode\n");
- goto fail;
+ goto fail2;
}
ipw_stop_master(sc);
@@ -2086,11 +2061,13 @@ ipw_init(void *priv)
CSR_WRITE_4(sc, IPW_CSR_STATUS_BASE, sc->status_phys);
- if (ipw_load_firmware(sc, fw->main, fw->main_size) != 0) {
+ fw = (const char *)fp->data + sizeof *hdr;
+ if (ipw_load_firmware(sc, fw, le32toh(hdr->mainsz)) != 0) {
device_printf(sc->sc_dev, "could not load firmware\n");
- goto fail;
+ goto fail2;
}
+ firmware_put(fp, FIRMWARE_UNLOAD);
sc->flags |= IPW_FLAG_FW_INITED;
/* retrieve information tables base addresses */
@@ -2101,16 +2078,25 @@ ipw_init(void *priv)
if (ipw_config(sc) != 0) {
device_printf(sc->sc_dev, "device configuration failed\n");
- goto fail;
+ goto fail1;
}
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ sc->flags &=~ IPW_FLAG_INIT_LOCKED;
+
+ if (!owned)
+ mtx_unlock(&sc->sc_mtx);
+
return;
-fail: ifp->if_flags &= ~IFF_UP;
+fail2: firmware_put(fp, FIRMWARE_UNLOAD);
+fail1: ifp->if_flags &= ~IFF_UP;
ipw_stop(sc);
+ sc->flags &=~ IPW_FLAG_INIT_LOCKED;
+ if (!owned)
+ mtx_unlock(&sc->sc_mtx);
}
static void
@@ -2121,6 +2107,10 @@ ipw_stop(void *priv)
struct ifnet *ifp = ic->ic_ifp;
int i;
+ mtx_lock(&sc->sc_mtx);
+
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
ipw_stop_master(sc);
CSR_WRITE_4(sc, IPW_CSR_RST, IPW_RST_SW_RESET);
@@ -2135,7 +2125,7 @@ ipw_stop(void *priv)
ifp->if_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+ mtx_unlock(&sc->sc_mtx);
}
static int
@@ -2219,7 +2209,7 @@ ipw_read_mem_1(struct ipw_softc *sc, bus_size_t offset, uint8_t *datap,
}
static void
-ipw_write_mem_1(struct ipw_softc *sc, bus_size_t offset, uint8_t *datap,
+ipw_write_mem_1(struct ipw_softc *sc, bus_size_t offset, const uint8_t *datap,
bus_size_t count)
{
for (; count > 0; offset++, datap++, count--) {
diff --git a/sys/dev/ipw/if_ipwreg.h b/sys/dev/ipw/if_ipwreg.h
index 9cbd62f..96741d0 100644
--- a/sys/dev/ipw/if_ipwreg.h
+++ b/sys/dev/ipw/if_ipwreg.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*-
- * Copyright (c) 2004, 2005
+ * Copyright (c) 2004-2006
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -115,59 +115,59 @@
/* firmware binary image header */
struct ipw_firmware_hdr {
- u_int32_t version;
- u_int32_t main_size; /* firmware size */
- u_int32_t ucode_size; /* microcode size */
+ uint32_t version;
+ uint32_t mainsz;
+ uint32_t ucodesz;
} __packed;
/* buffer descriptor */
struct ipw_bd {
- u_int32_t physaddr;
- u_int32_t len;
- u_int8_t flags;
+ uint32_t physaddr;
+ uint32_t len;
+ uint8_t flags;
#define IPW_BD_FLAG_TX_FRAME_802_3 0x00
#define IPW_BD_FLAG_TX_NOT_LAST_FRAGMENT 0x01
#define IPW_BD_FLAG_TX_FRAME_COMMAND 0x02
#define IPW_BD_FLAG_TX_FRAME_802_11 0x04
#define IPW_BD_FLAG_TX_LAST_FRAGMENT 0x08
- u_int8_t nfrag; /* number of fragments */
- u_int8_t reserved[6];
+ uint8_t nfrag; /* number of fragments */
+ uint8_t reserved[6];
} __packed;
/* status */
struct ipw_status {
- u_int32_t len;
- u_int16_t code;
+ uint32_t len;
+ uint16_t code;
#define IPW_STATUS_CODE_COMMAND 0
#define IPW_STATUS_CODE_NEWSTATE 1
#define IPW_STATUS_CODE_DATA_802_11 2
#define IPW_STATUS_CODE_DATA_802_3 3
#define IPW_STATUS_CODE_NOTIFICATION 4
- u_int8_t flags;
+ uint8_t flags;
#define IPW_STATUS_FLAG_DECRYPTED 0x01
#define IPW_STATUS_FLAG_WEP_ENCRYPTED 0x02
- u_int8_t rssi; /* received signal strength indicator */
+ uint8_t rssi; /* received signal strength indicator */
} __packed;
/* data header */
struct ipw_hdr {
- u_int32_t type;
+ uint32_t type;
#define IPW_HDR_TYPE_SEND 33
- u_int32_t subtype;
- u_int8_t encrypted;
- u_int8_t encrypt;
- u_int8_t keyidx;
- u_int8_t keysz;
- u_int8_t key[IEEE80211_KEYBUF_SIZE];
- u_int8_t reserved[10];
- u_int8_t src_addr[IEEE80211_ADDR_LEN];
- u_int8_t dst_addr[IEEE80211_ADDR_LEN];
- u_int16_t fragmentsz;
+ uint32_t subtype;
+ uint8_t encrypted;
+ uint8_t encrypt;
+ uint8_t keyidx;
+ uint8_t keysz;
+ uint8_t key[IEEE80211_KEYBUF_SIZE];
+ uint8_t reserved[10];
+ uint8_t src_addr[IEEE80211_ADDR_LEN];
+ uint8_t dst_addr[IEEE80211_ADDR_LEN];
+ uint16_t fragmentsz;
} __packed;
/* command */
struct ipw_cmd {
- u_int32_t type;
+ uint32_t type;
#define IPW_CMD_ENABLE 2
#define IPW_CMD_SET_CONFIGURATION 6
#define IPW_CMD_SET_ESSID 8
@@ -194,12 +194,12 @@ struct ipw_cmd {
#define IPW_CMD_DISABLE_PHY 61
#define IPW_CMD_SET_SECURITY_INFORMATION 67
#define IPW_CMD_SET_WPA_IE 69
- u_int32_t subtype;
- u_int32_t seq;
- u_int32_t len;
- u_int8_t data[400];
- u_int32_t status;
- u_int8_t reserved[68];
+ uint32_t subtype;
+ uint32_t seq;
+ uint32_t len;
+ uint8_t data[400];
+ uint32_t status;
+ uint8_t reserved[68];
} __packed;
/* possible values for command IPW_CMD_SET_POWER_MODE */
@@ -216,74 +216,74 @@ struct ipw_cmd {
/* structure for command IPW_CMD_SET_WEP_KEY */
struct ipw_wep_key {
- u_int8_t idx;
- u_int8_t len;
- u_int8_t key[13];
+ uint8_t idx;
+ uint8_t len;
+ uint8_t key[13];
} __packed;
/* structure for command IPW_CMD_SET_SECURITY_INFORMATION */
struct ipw_security {
- u_int32_t ciphers;
+ uint32_t ciphers;
#define IPW_CIPHER_NONE 0x00000001
#define IPW_CIPHER_WEP40 0x00000002
#define IPW_CIPHER_TKIP 0x00000004
#define IPW_CIPHER_CCMP 0x00000010
#define IPW_CIPHER_WEP104 0x00000020
#define IPW_CIPHER_CKIP 0x00000040
- u_int16_t reserved1;
- u_int8_t authmode;
+ uint16_t reserved1;
+ uint8_t authmode;
#define IPW_AUTH_OPEN 0
#define IPW_AUTH_SHARED 1
- u_int16_t reserved2;
+ uint16_t reserved2;
} __packed;
/* structure for command IPW_CMD_SET_SCAN_OPTIONS */
struct ipw_scan_options {
- u_int32_t flags;
+ uint32_t flags;
#define IPW_SCAN_DO_NOT_ASSOCIATE 0x00000001
#define IPW_SCAN_PASSIVE 0x00000008
- u_int32_t channels;
+ uint32_t channels;
} __packed;
/* structure for command IPW_CMD_SET_CONFIGURATION */
struct ipw_configuration {
- u_int32_t flags;
+ uint32_t flags;
#define IPW_CFG_PROMISCUOUS 0x00000004
#define IPW_CFG_PREAMBLE_AUTO 0x00000010
#define IPW_CFG_IBSS_AUTO_START 0x00000020
#define IPW_CFG_802_1x_ENABLE 0x00004000
#define IPW_CFG_BSS_MASK 0x00008000
#define IPW_CFG_IBSS_MASK 0x00010000
- u_int32_t bss_chan;
- u_int32_t ibss_chan;
+ uint32_t bss_chan;
+ uint32_t ibss_chan;
} __packed;
/* structure for command IPW_CMD_SET_WPA_IE */
struct ipw_wpa_ie {
- u_int16_t mask;
- u_int16_t capinfo;
- u_int16_t lintval;
- u_int8_t bssid[IEEE80211_ADDR_LEN];
- u_int32_t len;
+ uint16_t mask;
+ uint16_t capinfo;
+ uint16_t lintval;
+ uint8_t bssid[IEEE80211_ADDR_LEN];
+ uint32_t len;
struct ieee80211_ie_wpa ie;
} __packed;
/* element in AP table */
struct ipw_node {
- u_int32_t reserved1[2];
- u_int8_t bssid[IEEE80211_ADDR_LEN];
- u_int8_t chan;
- u_int8_t rates;
- u_int16_t reserved2;
- u_int16_t capinfo;
- u_int16_t reserved3;
- u_int16_t intval;
- u_int8_t reserved4[28];
- u_int8_t essid[IEEE80211_NWID_LEN];
- u_int16_t reserved5;
- u_int8_t esslen;
- u_int8_t reserved6[7];
- u_int8_t rssi;
+ uint32_t reserved1[2];
+ uint8_t bssid[IEEE80211_ADDR_LEN];
+ uint8_t chan;
+ uint8_t rates;
+ uint16_t reserved2;
+ uint16_t capinfo;
+ uint16_t reserved3;
+ uint16_t intval;
+ uint8_t reserved4[28];
+ uint8_t essid[IEEE80211_NWID_LEN];
+ uint16_t reserved5;
+ uint8_t esslen;
+ uint8_t reserved6[7];
+ uint8_t rssi;
} __packed;
/* EEPROM = Electrically Erasable Programmable Read-Only Memory */
@@ -332,6 +332,14 @@ struct ipw_node {
/*
* indirect memory space access macros
*/
+#define MEM_READ_1(sc, addr) \
+ (CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr)), \
+ CSR_READ_1((sc), IPW_CSR_INDIRECT_DATA))
+
+#define MEM_READ_4(sc, addr) \
+ (CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr)), \
+ CSR_READ_4((sc), IPW_CSR_INDIRECT_DATA))
+
#define MEM_WRITE_1(sc, addr, val) do { \
CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr)); \
CSR_WRITE_1((sc), IPW_CSR_INDIRECT_DATA, (val)); \
diff --git a/sys/dev/ipw/if_ipwvar.h b/sys/dev/ipw/if_ipwvar.h
index e1f3ea1..aaf1a0a 100644
--- a/sys/dev/ipw/if_ipwvar.h
+++ b/sys/dev/ipw/if_ipwvar.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*-
- * Copyright (c) 2004, 2005
+ * Copyright (c) 2004-2006
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,13 +27,6 @@
* SUCH DAMAGE.
*/
-struct ipw_firmware {
- void *main;
- int main_size;
- void *ucode;
- int ucode_size;
-};
-
#define IPW_MAX_NSEG 1
struct ipw_soft_bd {
@@ -91,11 +84,11 @@ struct ipw_softc {
device_t sc_dev;
struct mtx sc_mtx;
+ struct task sc_init_task;
- struct ipw_firmware fw;
uint32_t flags;
-#define IPW_FLAG_FW_CACHED (1 << 0)
-#define IPW_FLAG_FW_INITED (1 << 1)
+#define IPW_FLAG_FW_INITED (1 << 0)
+#define IPW_FLAG_INIT_LOCKED (1 << 1)
#define IPW_FLAG_HAS_RADIO_SWITCH (1 << 2)
#define IPW_FLAG_FW_WARNED (1 << 3)
@@ -166,9 +159,3 @@ struct ipw_softc {
#define sc_txtap sc_txtapu.th
int sc_txtap_len;
};
-
-#define SIOCSLOADFW _IOW('i', 137, struct ifreq)
-#define SIOCSKILLFW _IOW('i', 138, struct ifreq)
-
-#define IPW_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
-#define IPW_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
OpenPOWER on IntegriCloud