From c30e4662deca0ed3c2e900a2f4aa514f5e986690 Mon Sep 17 00:00:00 2001 From: damien Date: Sun, 12 Mar 2006 19:01:00 +0000 Subject: sync w/ iwi: o fix locking o use firmware(9) o cosmetic --- sys/dev/ipw/if_ipw.c | 366 +++++++++++++++++++++++------------------------- sys/dev/ipw/if_ipwreg.h | 132 +++++++++-------- sys/dev/ipw/if_ipwvar.h | 21 +-- 3 files changed, 252 insertions(+), 267 deletions(-) (limited to 'sys/dev/ipw') 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 . All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,9 +43,13 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include +#include +#include #include #include @@ -63,15 +67,15 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include + #include #include #include #include #include -#include -#include - #include #include @@ -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 . 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 . 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) -- cgit v1.1