From owner-svn-src-all@FreeBSD.ORG Sat Feb 7 23:11:39 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 6FB0B720; Sat, 7 Feb 2015 23:11:39 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 5A7743D6; Sat, 7 Feb 2015 23:11:39 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t17NBdf7070962; Sat, 7 Feb 2015 23:11:39 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t17NBduF070960; Sat, 7 Feb 2015 23:11:39 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <201502072311.t17NBduF070960@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Sat, 7 Feb 2015 23:11:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r278366 - head/sys/dev/wpi X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 07 Feb 2015 23:11:39 -0000 Author: adrian Date: Sat Feb 7 23:11:38 2015 New Revision: 278366 URL: https://svnweb.freebsd.org/changeset/base/278366 Log: Big wpi(4) overhaul! Not by me! This is a sync against iwn(4) and openbsd. - Add power management support; - Add background scanning support; - Fix few LORs; - Handle rfkill switch state changes properly; - Fix recovering after firmware failure; - Add more error checking; - Cleanup & disable by default debug output; - Update macroses names; - Other various fixes; - Add IBSS support: - don't set data_ntries field for management frames; - Add AHDEMO support: - fix padding; - Sync eeprom functions; - Use CMD_RXON_ASSOC where possible; - Enable HW CCMP encryption/decryption for pairwise keys; - Fix filter flags for CMD_RXON. Tested (by submitter) - iwn 3945 NIC. I have one somewhere; I'll validate this later on and revert it if it's a problem. Thanks! PR: 197143 Submitted by: Andriy Voskoboinyk Added: head/sys/dev/wpi/if_wpi_debug.h (contents, props changed) Modified: head/sys/dev/wpi/if_wpi.c head/sys/dev/wpi/if_wpireg.h head/sys/dev/wpi/if_wpivar.h Modified: head/sys/dev/wpi/if_wpi.c ============================================================================== --- head/sys/dev/wpi/if_wpi.c Sat Feb 7 23:09:03 2015 (r278365) +++ head/sys/dev/wpi/if_wpi.c Sat Feb 7 23:11:38 2015 (r278366) @@ -16,8 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define VERSION "20071127" - #include __FBSDID("$FreeBSD$"); @@ -60,6 +58,7 @@ __FBSDID("$FreeBSD$"); */ #include "opt_wlan.h" +#include "opt_wpi.h" #include #include @@ -93,51 +92,20 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include -#include - #include #include #include -#include #include +#include + +#include +#include +#include +#include #include #include - -#define WPI_DEBUG - -#ifdef WPI_DEBUG -#define DPRINTF(x) do { if (wpi_debug != 0) printf x; } while (0) -#define DPRINTFN(n, x) do { if (wpi_debug & n) printf x; } while (0) -#define WPI_DEBUG_SET (wpi_debug != 0) - -enum { - WPI_DEBUG_UNUSED = 0x00000001, /* Unused */ - WPI_DEBUG_HW = 0x00000002, /* Stage 1 (eeprom) debugging */ - WPI_DEBUG_TX = 0x00000004, /* Stage 2 TX intrp debugging*/ - WPI_DEBUG_RX = 0x00000008, /* Stage 2 RX intrp debugging */ - WPI_DEBUG_CMD = 0x00000010, /* Stage 2 CMD intrp debugging*/ - WPI_DEBUG_FIRMWARE = 0x00000020, /* firmware(9) loading debug */ - WPI_DEBUG_DMA = 0x00000040, /* DMA (de)allocations/syncs */ - WPI_DEBUG_SCANNING = 0x00000080, /* Stage 2 Scanning debugging */ - WPI_DEBUG_NOTIFY = 0x00000100, /* State 2 Noftif intr debug */ - WPI_DEBUG_TEMP = 0x00000200, /* TXPower/Temp Calibration */ - WPI_DEBUG_OPS = 0x00000400, /* wpi_ops taskq debug */ - WPI_DEBUG_WATCHDOG = 0x00000800, /* Watch dog debug */ - WPI_DEBUG_ANY = 0xffffffff -}; - -static int wpi_debug; -SYSCTL_INT(_debug, OID_AUTO, wpi, CTLFLAG_RWTUN, &wpi_debug, 0, "wpi debug level"); - -#else -#define DPRINTF(x) -#define DPRINTFN(n, x) -#define WPI_DEBUG_SET 0 -#endif +#include struct wpi_ident { uint16_t vendor; @@ -158,99 +126,138 @@ static const struct wpi_ident wpi_ident_ { 0, 0, 0, NULL } }; +static int wpi_probe(device_t); +static int wpi_attach(device_t); +static void wpi_radiotap_attach(struct wpi_softc *); +static void wpi_sysctlattach(struct wpi_softc *); static struct ieee80211vap *wpi_vap_create(struct ieee80211com *, const char [IFNAMSIZ], int, enum ieee80211_opmode, int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void wpi_vap_delete(struct ieee80211vap *); +static int wpi_detach(device_t); +static int wpi_shutdown(device_t); +static int wpi_suspend(device_t); +static int wpi_resume(device_t); +static int wpi_nic_lock(struct wpi_softc *); +static int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); +static void wpi_dma_map_addr(void *, bus_dma_segment_t *, int, int); static int wpi_dma_contig_alloc(struct wpi_softc *, struct wpi_dma_info *, - void **, bus_size_t, bus_size_t, int); + void **, bus_size_t, bus_size_t); static void wpi_dma_contig_free(struct wpi_dma_info *); -static void wpi_dma_map_addr(void *, bus_dma_segment_t *, int, int); static int wpi_alloc_shared(struct wpi_softc *); static void wpi_free_shared(struct wpi_softc *); -static int wpi_alloc_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); -static void wpi_reset_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); -static void wpi_free_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); +static int wpi_alloc_fwmem(struct wpi_softc *); +static void wpi_free_fwmem(struct wpi_softc *); +static int wpi_alloc_rx_ring(struct wpi_softc *); +static void wpi_update_rx_ring(struct wpi_softc *); +static void wpi_reset_rx_ring(struct wpi_softc *); +static void wpi_free_rx_ring(struct wpi_softc *); static int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *, - int, int); + int); +static void wpi_update_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); static void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); static void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); +static int wpi_read_eeprom(struct wpi_softc *, + uint8_t macaddr[IEEE80211_ADDR_LEN]); +static uint32_t wpi_eeprom_channel_flags(struct wpi_eeprom_chan *); +static void wpi_read_eeprom_band(struct wpi_softc *, int); +static int wpi_read_eeprom_channels(struct wpi_softc *, int); +static struct wpi_eeprom_chan *wpi_find_eeprom_channel(struct wpi_softc *, + struct ieee80211_channel *); +static int wpi_setregdomain(struct ieee80211com *, + struct ieee80211_regdomain *, int, + struct ieee80211_channel[]); +static int wpi_read_eeprom_group(struct wpi_softc *, int); +static void wpi_node_free(struct ieee80211_node *); +static struct ieee80211_node *wpi_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); static int wpi_newstate(struct ieee80211vap *, enum ieee80211_state, int); -static void wpi_mem_lock(struct wpi_softc *); -static void wpi_mem_unlock(struct wpi_softc *); -static uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); -static void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); -static void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, - const uint32_t *, int); -static uint16_t wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); -static int wpi_alloc_fwmem(struct wpi_softc *); -static void wpi_free_fwmem(struct wpi_softc *); -static int wpi_load_firmware(struct wpi_softc *); -static void wpi_unload_firmware(struct wpi_softc *); -static int wpi_load_microcode(struct wpi_softc *, const uint8_t *, int); -static void wpi_rx_intr(struct wpi_softc *, struct wpi_rx_desc *, +static void wpi_calib_timeout(void *); +static void wpi_rx_done(struct wpi_softc *, struct wpi_rx_desc *, struct wpi_rx_data *); -static void wpi_tx_intr(struct wpi_softc *, struct wpi_rx_desc *); -static void wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *); +static void wpi_rx_statistics(struct wpi_softc *, struct wpi_rx_desc *, + struct wpi_rx_data *); +static void wpi_tx_done(struct wpi_softc *, struct wpi_rx_desc *); +static void wpi_cmd_done(struct wpi_softc *, struct wpi_rx_desc *); static void wpi_notif_intr(struct wpi_softc *); +static void wpi_wakeup_intr(struct wpi_softc *); +static void wpi_fatal_intr(struct wpi_softc *); static void wpi_intr(void *); -static uint8_t wpi_plcp_signal(int); -static void wpi_watchdog(void *); +static int wpi_cmd2(struct wpi_softc *, struct wpi_buf *); static int wpi_tx_data(struct wpi_softc *, struct mbuf *, - struct ieee80211_node *, int); -static void wpi_start(struct ifnet *); -static void wpi_start_locked(struct ifnet *); + struct ieee80211_node *); +static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, + struct ieee80211_node *, + const struct ieee80211_bpf_params *); static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static void wpi_scan_start(struct ieee80211com *); -static void wpi_scan_end(struct ieee80211com *); -static void wpi_set_channel(struct ieee80211com *); -static void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long); -static void wpi_scan_mindwell(struct ieee80211_scan_state *); +static void wpi_start(struct ifnet *); +static void wpi_start_locked(struct ifnet *); +static void wpi_watchdog_rfkill(void *); +static void wpi_watchdog(void *); static int wpi_ioctl(struct ifnet *, u_long, caddr_t); -static void wpi_read_eeprom(struct wpi_softc *, - uint8_t macaddr[IEEE80211_ADDR_LEN]); -static void wpi_read_eeprom_channels(struct wpi_softc *, int); -static void wpi_read_eeprom_group(struct wpi_softc *, int); -static int wpi_cmd(struct wpi_softc *, int, const void *, int, int); -static int wpi_wme_update(struct ieee80211com *); +static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); static int wpi_mrr_setup(struct wpi_softc *); +static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); +static int wpi_add_broadcast_node(struct wpi_softc *, int); +static int wpi_add_ibss_node(struct wpi_softc *, struct ieee80211_node *); +static void wpi_del_node(struct wpi_softc *, struct ieee80211_node *); +static int wpi_updateedca(struct ieee80211com *); +static void wpi_set_promisc(struct wpi_softc *); +static void wpi_update_promisc(struct ifnet *); +static void wpi_update_mcast(struct ifnet *); static void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t); -static void wpi_enable_tsf(struct wpi_softc *, struct ieee80211_node *); -#if 0 -static int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); -#endif +static int wpi_set_timing(struct wpi_softc *, struct ieee80211_node *); +static void wpi_power_calibration(struct wpi_softc *); +static int wpi_set_txpower(struct wpi_softc *, int); +static int wpi_get_power_index(struct wpi_softc *, + struct wpi_power_group *, struct ieee80211_channel *, int); +static int wpi_set_pslevel(struct wpi_softc *, uint8_t, int, int); +static int wpi_send_btcoex(struct wpi_softc *); +static int wpi_send_rxon(struct wpi_softc *, int, int); +static int wpi_config(struct wpi_softc *); +static uint16_t wpi_get_active_dwell_time(struct wpi_softc *, + struct ieee80211_channel *, uint8_t); +static uint16_t wpi_limit_dwell(struct wpi_softc *, uint16_t); +static uint16_t wpi_get_passive_dwell_time(struct wpi_softc *, + struct ieee80211_channel *); +static int wpi_scan(struct wpi_softc *, struct ieee80211_channel *); static int wpi_auth(struct wpi_softc *, struct ieee80211vap *); +static void wpi_update_beacon(struct ieee80211vap *, int); +static int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); static int wpi_run(struct wpi_softc *, struct ieee80211vap *); -static int wpi_scan(struct wpi_softc *); -static int wpi_config(struct wpi_softc *); -static void wpi_stop_master(struct wpi_softc *); -static int wpi_power_up(struct wpi_softc *); -static int wpi_reset(struct wpi_softc *); -static void wpi_hwreset(void *, int); -static void wpi_rfreset(void *, int); -static void wpi_hw_config(struct wpi_softc *); +static int wpi_key_alloc(struct ieee80211vap *, struct ieee80211_key *, + ieee80211_keyix *, ieee80211_keyix *); +static int wpi_key_set(struct ieee80211vap *, + const struct ieee80211_key *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static int wpi_key_delete(struct ieee80211vap *, + const struct ieee80211_key *); +static int wpi_post_alive(struct wpi_softc *); +static int wpi_load_bootcode(struct wpi_softc *, const uint8_t *, int); +static int wpi_load_firmware(struct wpi_softc *); +static int wpi_read_firmware(struct wpi_softc *); +static void wpi_unload_firmware(struct wpi_softc *); +static int wpi_clock_wait(struct wpi_softc *); +static int wpi_apm_init(struct wpi_softc *); +static void wpi_apm_stop_master(struct wpi_softc *); +static void wpi_apm_stop(struct wpi_softc *); +static void wpi_nic_config(struct wpi_softc *); +static int wpi_hw_init(struct wpi_softc *); +static void wpi_hw_stop(struct wpi_softc *); +static void wpi_radio_on(void *, int); +static void wpi_radio_off(void *, int); +static void wpi_init_locked(struct wpi_softc *); static void wpi_init(void *); -static void wpi_init_locked(struct wpi_softc *, int); -static void wpi_stop(struct wpi_softc *); static void wpi_stop_locked(struct wpi_softc *); - -static int wpi_set_txpower(struct wpi_softc *, struct ieee80211_channel *, - int); -static void wpi_calib_timeout(void *); -static void wpi_power_calibration(struct wpi_softc *, int); -static int wpi_get_power_index(struct wpi_softc *, - struct wpi_power_group *, struct ieee80211_channel *, int); -#ifdef WPI_DEBUG -static const char *wpi_cmd_str(int); -#endif -static int wpi_probe(device_t); -static int wpi_attach(device_t); -static int wpi_detach(device_t); -static int wpi_shutdown(device_t); -static int wpi_suspend(device_t); -static int wpi_resume(device_t); +static void wpi_stop(struct wpi_softc *); +static void wpi_scan_start(struct ieee80211com *); +static void wpi_scan_end(struct ieee80211com *); +static void wpi_set_channel(struct ieee80211com *); +static void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long); +static void wpi_scan_mindwell(struct ieee80211_scan_state *); +static void wpi_hw_reset(void *, int); static device_method_t wpi_methods[] = { /* Device interface */ @@ -269,25 +276,15 @@ static driver_t wpi_driver = { wpi_methods, sizeof (struct wpi_softc) }; - static devclass_t wpi_devclass; DRIVER_MODULE(wpi, pci, wpi_driver, wpi_devclass, NULL, NULL); MODULE_VERSION(wpi, 1); -static const uint8_t wpi_ridx_to_plcp[] = { - /* OFDM: IEEE Std 802.11a-1999, pp. 14 Table 80 */ - /* R1-R4 (ral/ural is R4-R1) */ - 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, - /* CCK: device-dependent */ - 10, 20, 55, 110 -}; - -static const uint8_t wpi_ridx_to_rate[] = { - 12, 18, 24, 36, 48, 72, 96, 108, /* OFDM */ - 2, 4, 11, 22 /*CCK */ -}; +MODULE_DEPEND(wpi, pci, 1, 1, 1); +MODULE_DEPEND(wpi, wlan, 1, 1, 1); +MODULE_DEPEND(wpi, firmware, 1, 1, 1); static int wpi_probe(device_t dev) @@ -304,202 +301,38 @@ wpi_probe(device_t dev) return ENXIO; } -/** - * Load the firmare image from disk to the allocated dma buffer. - * we also maintain the reference to the firmware pointer as there - * is times where we may need to reload the firmware but we are not - * in a context that can access the filesystem (ie taskq cause by restart) - * - * @return 0 on success, an errno on failure - */ -static int -wpi_load_firmware(struct wpi_softc *sc) -{ - const struct firmware *fp; - struct wpi_dma_info *dma = &sc->fw_dma; - const struct wpi_firmware_hdr *hdr; - const uint8_t *itext, *idata, *rtext, *rdata, *btext; - uint32_t itextsz, idatasz, rtextsz, rdatasz, btextsz; - int error; - - DPRINTFN(WPI_DEBUG_FIRMWARE, - ("Attempting Loading Firmware from wpi_fw module\n")); - - WPI_UNLOCK(sc); - - if (sc->fw_fp == NULL && (sc->fw_fp = firmware_get("wpifw")) == NULL) { - device_printf(sc->sc_dev, - "could not load firmware image 'wpifw'\n"); - error = ENOENT; - WPI_LOCK(sc); - goto fail; - } - - fp = sc->fw_fp; - - WPI_LOCK(sc); - - /* Validate the firmware is minimum a particular version */ - if (fp->version < WPI_FW_MINVERSION) { - device_printf(sc->sc_dev, - "firmware version is too old. Need %d, got %d\n", - WPI_FW_MINVERSION, - fp->version); - error = ENXIO; - goto fail; - } - - if (fp->datasize < sizeof (struct wpi_firmware_hdr)) { - device_printf(sc->sc_dev, - "firmware file too short: %zu bytes\n", fp->datasize); - error = ENXIO; - goto fail; - } - - hdr = (const struct wpi_firmware_hdr *)fp->data; - - /* | RUNTIME FIRMWARE | INIT FIRMWARE | BOOT FW | - |HDR|<--TEXT-->|<--DATA-->|<--TEXT-->|<--DATA-->|<--TEXT-->| */ - - rtextsz = le32toh(hdr->rtextsz); - rdatasz = le32toh(hdr->rdatasz); - itextsz = le32toh(hdr->itextsz); - idatasz = le32toh(hdr->idatasz); - btextsz = le32toh(hdr->btextsz); - - /* check that all firmware segments are present */ - if (fp->datasize < sizeof (struct wpi_firmware_hdr) + - rtextsz + rdatasz + itextsz + idatasz + btextsz) { - device_printf(sc->sc_dev, - "firmware file too short: %zu bytes\n", fp->datasize); - error = ENXIO; /* XXX appropriate error code? */ - goto fail; - } - - /* get pointers to firmware segments */ - rtext = (const uint8_t *)(hdr + 1); - rdata = rtext + rtextsz; - itext = rdata + rdatasz; - idata = itext + itextsz; - btext = idata + idatasz; - - DPRINTFN(WPI_DEBUG_FIRMWARE, - ("Firmware Version: Major %d, Minor %d, Driver %d, \n" - "runtime (text: %u, data: %u) init (text: %u, data %u) boot (text %u)\n", - (le32toh(hdr->version) & 0xff000000) >> 24, - (le32toh(hdr->version) & 0x00ff0000) >> 16, - (le32toh(hdr->version) & 0x0000ffff), - rtextsz, rdatasz, - itextsz, idatasz, btextsz)); - - DPRINTFN(WPI_DEBUG_FIRMWARE,("rtext 0x%x\n", *(const uint32_t *)rtext)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("rdata 0x%x\n", *(const uint32_t *)rdata)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("itext 0x%x\n", *(const uint32_t *)itext)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("idata 0x%x\n", *(const uint32_t *)idata)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("btext 0x%x\n", *(const uint32_t *)btext)); - - /* sanity checks */ - if (rtextsz > WPI_FW_MAIN_TEXT_MAXSZ || - rdatasz > WPI_FW_MAIN_DATA_MAXSZ || - itextsz > WPI_FW_INIT_TEXT_MAXSZ || - idatasz > WPI_FW_INIT_DATA_MAXSZ || - btextsz > WPI_FW_BOOT_TEXT_MAXSZ || - (btextsz & 3) != 0) { - device_printf(sc->sc_dev, "firmware invalid\n"); - error = EINVAL; - goto fail; - } - - /* copy initialization images into pre-allocated DMA-safe memory */ - memcpy(dma->vaddr, idata, idatasz); - memcpy(dma->vaddr + WPI_FW_INIT_DATA_MAXSZ, itext, itextsz); - - bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); - - /* tell adapter where to find initialization images */ - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); - wpi_mem_write(sc, WPI_MEM_DATA_SIZE, idatasz); - wpi_mem_write(sc, WPI_MEM_TEXT_BASE, - dma->paddr + WPI_FW_INIT_DATA_MAXSZ); - wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, itextsz); - wpi_mem_unlock(sc); - - /* load firmware boot code */ - if ((error = wpi_load_microcode(sc, btext, btextsz)) != 0) { - device_printf(sc->sc_dev, "Failed to load microcode\n"); - goto fail; - } - - /* now press "execute" */ - WPI_WRITE(sc, WPI_RESET, 0); - - /* wait at most one second for the first alive notification */ - if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { - device_printf(sc->sc_dev, - "timeout waiting for adapter to initialize\n"); - goto fail; - } - - /* copy runtime images into pre-allocated DMA-sage memory */ - memcpy(dma->vaddr, rdata, rdatasz); - memcpy(dma->vaddr + WPI_FW_MAIN_DATA_MAXSZ, rtext, rtextsz); - bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); - - /* tell adapter where to find runtime images */ - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); - wpi_mem_write(sc, WPI_MEM_DATA_SIZE, rdatasz); - wpi_mem_write(sc, WPI_MEM_TEXT_BASE, - dma->paddr + WPI_FW_MAIN_DATA_MAXSZ); - wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, WPI_FW_UPDATED | rtextsz); - wpi_mem_unlock(sc); - - /* wait at most one second for the first alive notification */ - if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { - device_printf(sc->sc_dev, - "timeout waiting for adapter to initialize2\n"); - goto fail; - } - - DPRINTFN(WPI_DEBUG_FIRMWARE, - ("Firmware loaded to driver successfully\n")); - return error; -fail: - wpi_unload_firmware(sc); - return error; -} - -/** - * Free the referenced firmware image - */ -static void -wpi_unload_firmware(struct wpi_softc *sc) -{ - - if (sc->fw_fp) { - WPI_UNLOCK(sc); - firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); - WPI_LOCK(sc); - sc->fw_fp = NULL; - } -} - static int wpi_attach(device_t dev) { - struct wpi_softc *sc = device_get_softc(dev); - struct ifnet *ifp; + struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); struct ieee80211com *ic; - int ac, error, rid, supportsa = 1; - uint32_t tmp; + struct ifnet *ifp; + int i, error, rid, supportsa = 1; const struct wpi_ident *ident; uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; - if (bootverbose || WPI_DEBUG_SET) - device_printf(sc->sc_dev,"Driver Revision %s\n", VERSION); +#ifdef WPI_DEBUG + error = resource_int_value(device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug)); + if (error != 0) + sc->sc_debug = 0; +#else + sc->sc_debug = 0; +#endif + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* + * Get the offset of the PCI Express Capability Structure in PCI + * Configuration Space. + */ + error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off); + if (error != 0) { + device_printf(dev, "PCIe capability structure not found!\n"); + return error; + } /* * Some card's only support 802.11b/g not a, check to see if @@ -514,131 +347,118 @@ wpi_attach(device_t dev) } } - /* Create the tasks that can be queued */ - TASK_INIT(&sc->sc_restarttask, 0, wpi_hwreset, sc); - TASK_INIT(&sc->sc_radiotask, 0, wpi_rfreset, sc); - - WPI_LOCK_INIT(sc); - - callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); - callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); - - /* disable the retry timeout register */ + /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); - /* enable bus-mastering */ + /* Enable bus-mastering. */ pci_enable_busmaster(dev); rid = PCIR_BAR(0); sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem == NULL) { - device_printf(dev, "could not allocate memory resource\n"); + device_printf(dev, "can't map mem space\n"); error = ENOMEM; - goto fail; + return error; } - sc->sc_st = rman_get_bustag(sc->mem); sc->sc_sh = rman_get_bushandle(sc->mem); + i = 1; rid = 0; - sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE | RF_SHAREABLE); + if (pci_alloc_msi(dev, &i) == 0) + rid = 1; + /* Install interrupt handler. */ + sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | + (rid != 0 ? 0 : RF_SHAREABLE)); if (sc->irq == NULL) { - device_printf(dev, "could not allocate interrupt resource\n"); + device_printf(dev, "can't map interrupt\n"); error = ENOMEM; goto fail; } - /* - * Allocate DMA memory for firmware transfers. - */ - if ((error = wpi_alloc_fwmem(sc)) != 0) { - printf(": could not allocate firmware memory\n"); - error = ENOMEM; - goto fail; - } + WPI_LOCK_INIT(sc); - /* - * Put adapter into a known state. - */ - if ((error = wpi_reset(sc)) != 0) { - device_printf(dev, "could not reset adapter\n"); + sc->sc_unr = new_unrhdr(WPI_ID_IBSS_MIN, WPI_ID_IBSS_MAX, &sc->sc_mtx); + + /* Allocate DMA memory for firmware transfers. */ + if ((error = wpi_alloc_fwmem(sc)) != 0) { + device_printf(dev, + "could not allocate memory for firmware, error %d\n", + error); goto fail; } - wpi_mem_lock(sc); - tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV); - if (bootverbose || WPI_DEBUG_SET) - device_printf(sc->sc_dev, "Hardware Revision (0x%X)\n", tmp); - - wpi_mem_unlock(sc); - - /* Allocate shared page */ + /* Allocate shared page. */ if ((error = wpi_alloc_shared(sc)) != 0) { device_printf(dev, "could not allocate shared page\n"); goto fail; } - /* tx data queues - 4 for QoS purposes */ - for (ac = 0; ac < WME_NUM_AC; ac++) { - error = wpi_alloc_tx_ring(sc, &sc->txq[ac], WPI_TX_RING_COUNT, ac); - if (error != 0) { - device_printf(dev, "could not allocate Tx ring %d\n",ac); - goto fail; + /* Allocate TX rings - 4 for QoS purposes, 1 for commands. */ + for (i = 0; i < WPI_NTXQUEUES; i++) { + if ((error = wpi_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { + device_printf(dev, + "could not allocate TX ring %d, error %d\n", i, + error); + goto fail; } } - /* command queue to talk to the card's firmware */ - error = wpi_alloc_tx_ring(sc, &sc->cmdq, WPI_CMD_RING_COUNT, 4); - if (error != 0) { - device_printf(dev, "could not allocate command ring\n"); + /* Allocate RX ring. */ + if ((error = wpi_alloc_rx_ring(sc)) != 0) { + device_printf(dev, "could not allocate RX ring, error %d\n", + error); goto fail; } - /* receive data queue */ - error = wpi_alloc_rx_ring(sc, &sc->rxq); - if (error != 0) { - device_printf(dev, "could not allocate Rx ring\n"); - goto fail; - } + /* Clear pending interrupts. */ + WPI_WRITE(sc, WPI_INT, 0xffffffff); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { - device_printf(dev, "can not if_alloc()\n"); - error = ENOMEM; + device_printf(dev, "can not allocate ifnet structure\n"); goto fail; } - ic = ifp->if_l2com; + ic = ifp->if_l2com; ic->ic_ifp = ifp; ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ - /* set device capabilities */ + /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_STA /* station mode supported */ + | IEEE80211_C_IBSS /* IBSS mode supported */ | IEEE80211_C_MONITOR /* monitor mode supported */ + | IEEE80211_C_AHDEMO /* adhoc demo mode */ + | IEEE80211_C_BGSCAN /* capable of bg scanning */ | IEEE80211_C_TXPMGT /* tx power management */ | IEEE80211_C_SHSLOT /* short slot time supported */ - | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | IEEE80211_C_WPA /* 802.11i */ -/* XXX looks like WME is partly supported? */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ #if 0 - | IEEE80211_C_IBSS /* IBSS mode support */ - | IEEE80211_C_BGSCAN /* capable of bg scanning */ - | IEEE80211_C_WME /* 802.11e */ | IEEE80211_C_HOSTAP /* Host access point mode */ #endif + | IEEE80211_C_WME /* 802.11e */ + | IEEE80211_C_PMGT /* Station-side power mgmt */ ; + ic->ic_cryptocaps = + IEEE80211_CRYPTO_AES_CCM; + /* * Read in the eeprom and also setup the channels for * net80211. We don't set the rates as net80211 does this for us */ - wpi_read_eeprom(sc, macaddr); + if ((error = wpi_read_eeprom(sc, macaddr)) != 0) { + device_printf(dev, "could not read EEPROM, error %d\n", + error); + goto fail; + } - if (bootverbose || WPI_DEBUG_SET) { +#ifdef WPI_DEBUG + if (bootverbose) { device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", sc->domain); device_printf(sc->sc_dev, "Hardware Type: %c\n", sc->type > 1 ? 'B': '?'); @@ -650,6 +470,7 @@ wpi_attach(device_t dev) /* XXX hw_config uses the PCIDEV for the Hardware rev. Must check what sc->rev really represents - benjsc 20070615 */ } +#endif if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_softc = sc; @@ -662,99 +483,90 @@ wpi_attach(device_t dev) IFQ_SET_READY(&ifp->if_snd); ieee80211_ifattach(ic, macaddr); - /* override default methods */ + ic->ic_vap_create = wpi_vap_create; + ic->ic_vap_delete = wpi_vap_delete; ic->ic_raw_xmit = wpi_raw_xmit; - ic->ic_wme.wme_update = wpi_wme_update; + ic->ic_node_alloc = wpi_node_alloc; + sc->sc_node_free = ic->ic_node_free; + ic->ic_node_free = wpi_node_free; + ic->ic_wme.wme_update = wpi_updateedca; + ic->ic_update_promisc = wpi_update_promisc; + ic->ic_update_mcast = wpi_update_mcast; ic->ic_scan_start = wpi_scan_start; ic->ic_scan_end = wpi_scan_end; ic->ic_set_channel = wpi_set_channel; + sc->sc_scan_curchan = ic->ic_scan_curchan; ic->ic_scan_curchan = wpi_scan_curchan; ic->ic_scan_mindwell = wpi_scan_mindwell; + ic->ic_setregdomain = wpi_setregdomain; - ic->ic_vap_create = wpi_vap_create; - ic->ic_vap_delete = wpi_vap_delete; + wpi_radiotap_attach(sc); - ieee80211_radiotap_attach(ic, - &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), - WPI_TX_RADIOTAP_PRESENT, - &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), - WPI_RX_RADIOTAP_PRESENT); + callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); + callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); + callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); + TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); + TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); + TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); + + wpi_sysctlattach(sc); /* * Hook our interrupt after all initialization is complete. */ - error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET |INTR_MPSAFE, + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, wpi_intr, sc, &sc->sc_ih); if (error != 0) { - device_printf(dev, "could not set up interrupt\n"); + device_printf(dev, "can't establish interrupt, error %d\n", + error); goto fail; } if (bootverbose) ieee80211_announce(ic); -#ifdef XXX_DEBUG - ieee80211_announce_channels(ic); + +#ifdef WPI_DEBUG + if (sc->sc_debug & WPI_DEBUG_HW) + ieee80211_announce_channels(ic); #endif + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); return 0; fail: wpi_detach(dev); - return ENXIO; + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + return error; } -static int -wpi_detach(device_t dev) +/* + * Attach the interface to 802.11 radiotap. + */ +static void +wpi_radiotap_attach(struct wpi_softc *sc) { - struct wpi_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic; - int ac; + struct ieee80211com *ic = ifp->if_l2com; + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + WPI_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + WPI_RX_RADIOTAP_PRESENT); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); +} - if (sc->irq != NULL) - bus_teardown_intr(dev, sc->irq, sc->sc_ih); +static void +wpi_sysctlattach(struct wpi_softc *sc) +{ +#ifdef WPI_DEBUG + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); - if (ifp != NULL) { - ic = ifp->if_l2com; - - ieee80211_draintask(ic, &sc->sc_restarttask); - ieee80211_draintask(ic, &sc->sc_radiotask); - wpi_stop(sc); - callout_drain(&sc->watchdog_to); - callout_drain(&sc->calib_to); - ieee80211_ifdetach(ic); - } - - WPI_LOCK(sc); - if (sc->txq[0].data_dmat) { - for (ac = 0; ac < WME_NUM_AC; ac++) - wpi_free_tx_ring(sc, &sc->txq[ac]); - - wpi_free_tx_ring(sc, &sc->cmdq); - wpi_free_rx_ring(sc, &sc->rxq); - wpi_free_shared(sc); - } - - if (sc->fw_fp != NULL) { - wpi_unload_firmware(sc); - } - - if (sc->fw_dma.tag) - wpi_free_fwmem(sc); - WPI_UNLOCK(sc); - - if (sc->irq != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), - sc->irq); - if (sc->mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - rman_get_rid(sc->mem), sc->mem); - - if (ifp != NULL) - if_free(ifp); - - WPI_LOCK_DESTROY(sc); - - return 0; -} + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "debug", CTLFLAG_RW, &sc->sc_debug, sc->sc_debug, + "control debugging printfs"); +#endif +} static struct ieee80211vap * wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, @@ -763,22 +575,32 @@ wpi_vap_create(struct ieee80211com *ic, const uint8_t mac[IEEE80211_ADDR_LEN]) { struct wpi_vap *wvp; + struct wpi_buf *bcn; struct ieee80211vap *vap; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; + wvp = (struct wpi_vap *) malloc(sizeof(struct wpi_vap), M_80211_VAP, M_NOWAIT | M_ZERO); if (wvp == NULL) return NULL; vap = &wvp->vap; ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); - /* override with driver methods */ + + bcn = &wvp->wv_bcbuf; + bcn->data = NULL; + + /* Override with driver methods. */ wvp->newstate = vap->iv_newstate; + vap->iv_key_alloc = wpi_key_alloc; + vap->iv_key_set = wpi_key_set; + vap->iv_key_delete = wpi_key_delete; vap->iv_newstate = wpi_newstate; + vap->iv_update_beacon = wpi_update_beacon; ieee80211_ratectl_init(vap); - /* complete setup */ + /* Complete setup. */ ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; @@ -788,127 +610,291 @@ static void wpi_vap_delete(struct ieee80211vap *vap) { struct wpi_vap *wvp = WPI_VAP(vap); + struct wpi_buf *bcn = &wvp->wv_bcbuf; ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); + + if (bcn->data != NULL) + free(bcn->data, M_DEVBUF); free(wvp, M_80211_VAP); } -static void -wpi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +static int +wpi_detach(device_t dev) { - if (error != 0) - return; + struct wpi_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; + int qid; - KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - *(bus_addr_t *)arg = segs[0].ds_addr; + if (ifp != NULL) { + ic = ifp->if_l2com; + + ieee80211_draintask(ic, &sc->sc_reinittask); + ieee80211_draintask(ic, &sc->sc_radiooff_task); + + wpi_stop(sc); + + callout_drain(&sc->watchdog_to); + callout_drain(&sc->watchdog_rfkill); + callout_drain(&sc->calib_to); + ieee80211_ifdetach(ic); + } + + /* Uninstall interrupt handler. */ + if (sc->irq != NULL) { + bus_teardown_intr(dev, sc->irq, sc->sc_ih); + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), + sc->irq); + pci_release_msi(dev); + } + + if (sc->txq[0].data_dmat) { + /* Free DMA resources. */ + for (qid = 0; qid < WPI_NTXQUEUES; qid++) + wpi_free_tx_ring(sc, &sc->txq[qid]); + + wpi_free_rx_ring(sc); + wpi_free_shared(sc); + } + + if (sc->fw_dma.tag) + wpi_free_fwmem(sc); + + if (sc->mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(sc->mem), sc->mem); + + if (ifp != NULL) + if_free(ifp); + + delete_unrhdr(sc->sc_unr); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + WPI_LOCK_DESTROY(sc); + return 0; +} + +static int *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***