version 1.62.6.3, 2017/12/03 11:37:08 |
version 1.63, 2013/03/30 03:21:05 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
/* $OpenBSD: if_iwn.c,v 1.135 2014/09/10 07:22:09 dcoppa Exp $ */ |
/* $OpenBSD: if_iwn.c,v 1.96 2010/05/13 09:25:03 damien Exp $ */ |
|
|
/*- |
/*- |
* Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> |
* Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> |
Line 35 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 35 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/socket.h> |
#include <sys/socket.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
#ifdef notyetMODULE |
|
#include <sys/module.h> |
|
#endif |
|
#include <sys/mutex.h> |
#include <sys/mutex.h> |
#include <sys/conf.h> |
#include <sys/conf.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
Line 47 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 44 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include <sys/bus.h> |
#include <sys/bus.h> |
#include <machine/endian.h> |
#include <machine/endian.h> |
#include <sys/intr.h> |
#include <machine/intr.h> |
|
|
#include <dev/pci/pcireg.h> |
#include <dev/pci/pcireg.h> |
#include <dev/pci/pcivar.h> |
#include <dev/pci/pcivar.h> |
Line 102 static const pci_product_id_t iwn_device |
|
Line 99 static const pci_product_id_t iwn_device |
|
PCI_PRODUCT_INTEL_WIFI_LINK_6005_2X2_2, |
PCI_PRODUCT_INTEL_WIFI_LINK_6005_2X2_2, |
PCI_PRODUCT_INTEL_WIFI_LINK_6230_1, |
PCI_PRODUCT_INTEL_WIFI_LINK_6230_1, |
PCI_PRODUCT_INTEL_WIFI_LINK_6230_2, |
PCI_PRODUCT_INTEL_WIFI_LINK_6230_2, |
PCI_PRODUCT_INTEL_WIFI_LINK_6235, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_6235_2, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_100_1, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_100_2, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_130_1, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_130_2, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_2230_1, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_2230_2, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_2200_1, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_2200_2, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_135_1, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_135_2, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_105_1, |
|
PCI_PRODUCT_INTEL_WIFI_LINK_105_2, |
|
}; |
}; |
|
|
/* |
/* |
Line 201 static void iwn_notif_intr(struct iwn_so |
|
Line 184 static void iwn_notif_intr(struct iwn_so |
|
static void iwn_wakeup_intr(struct iwn_softc *); |
static void iwn_wakeup_intr(struct iwn_softc *); |
static void iwn_fatal_intr(struct iwn_softc *); |
static void iwn_fatal_intr(struct iwn_softc *); |
static int iwn_intr(void *); |
static int iwn_intr(void *); |
static void iwn_softintr(void *); |
|
static void iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t, |
static void iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t, |
uint16_t); |
uint16_t); |
static void iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t, |
static void iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t, |
Line 245 static void iwn_tune_sensitivity(struct |
|
Line 227 static void iwn_tune_sensitivity(struct |
|
static int iwn_send_sensitivity(struct iwn_softc *); |
static int iwn_send_sensitivity(struct iwn_softc *); |
static int iwn_set_pslevel(struct iwn_softc *, int, int, int); |
static int iwn_set_pslevel(struct iwn_softc *, int, int, int); |
static int iwn5000_runtime_calib(struct iwn_softc *); |
static int iwn5000_runtime_calib(struct iwn_softc *); |
|
|
static int iwn_config_bt_coex_bluetooth(struct iwn_softc *); |
|
static int iwn_config_bt_coex_prio_table(struct iwn_softc *); |
|
static int iwn_config_bt_coex_adv1(struct iwn_softc *); |
|
static int iwn_config_bt_coex_adv2(struct iwn_softc *); |
|
|
|
static int iwn_config(struct iwn_softc *); |
static int iwn_config(struct iwn_softc *); |
static uint16_t iwn_get_active_dwell_time(struct iwn_softc *, uint16_t, |
|
uint8_t); |
|
static uint16_t iwn_limit_dwell(struct iwn_softc *, uint16_t); |
|
static uint16_t iwn_get_passive_dwell_time(struct iwn_softc *, uint16_t); |
|
static int iwn_scan(struct iwn_softc *, uint16_t); |
static int iwn_scan(struct iwn_softc *, uint16_t); |
static int iwn_auth(struct iwn_softc *); |
static int iwn_auth(struct iwn_softc *); |
static int iwn_run(struct iwn_softc *); |
static int iwn_run(struct iwn_softc *); |
Line 287 static void iwn5000_ampdu_tx_stop(struct |
|
Line 259 static void iwn5000_ampdu_tx_stop(struct |
|
static int iwn5000_query_calibration(struct iwn_softc *); |
static int iwn5000_query_calibration(struct iwn_softc *); |
static int iwn5000_send_calibration(struct iwn_softc *); |
static int iwn5000_send_calibration(struct iwn_softc *); |
static int iwn5000_send_wimax_coex(struct iwn_softc *); |
static int iwn5000_send_wimax_coex(struct iwn_softc *); |
static int iwn6000_temp_offset_calib(struct iwn_softc *); |
|
static int iwn2000_temp_offset_calib(struct iwn_softc *); |
|
static int iwn4965_post_alive(struct iwn_softc *); |
static int iwn4965_post_alive(struct iwn_softc *); |
static int iwn5000_post_alive(struct iwn_softc *); |
static int iwn5000_post_alive(struct iwn_softc *); |
static int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *, |
static int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *, |
Line 324 static int iwn_alloc_rpool(struct iwn_so |
|
Line 294 static int iwn_alloc_rpool(struct iwn_so |
|
static void iwn_free_rpool(struct iwn_softc *); |
static void iwn_free_rpool(struct iwn_softc *); |
#endif |
#endif |
|
|
static void iwn_fix_channel(struct ieee80211com *, struct mbuf *, |
/* XXX needed by iwn_scan */ |
struct iwn_rx_stat *); |
static u_int8_t *ieee80211_add_ssid(u_int8_t *, const u_int8_t *, u_int); |
|
static u_int8_t *ieee80211_add_rates(u_int8_t *, |
|
const struct ieee80211_rateset *); |
|
static u_int8_t *ieee80211_add_xrates(u_int8_t *, |
|
const struct ieee80211_rateset *); |
|
|
|
static void iwn_fix_channel(struct ieee80211com *, struct mbuf *); |
|
|
#ifdef IWN_DEBUG |
#ifdef IWN_DEBUG |
#define DPRINTF(x) do { if (iwn_debug > 0) printf x; } while (0) |
#define DPRINTF(x) do { if (iwn_debug > 0) printf x; } while (0) |
Line 363 iwn_attach(device_t parent __unused, dev |
|
Line 339 iwn_attach(device_t parent __unused, dev |
|
struct ifnet *ifp = &sc->sc_ec.ec_if; |
struct ifnet *ifp = &sc->sc_ec.ec_if; |
struct pci_attach_args *pa = aux; |
struct pci_attach_args *pa = aux; |
const char *intrstr; |
const char *intrstr; |
|
pci_intr_handle_t ih; |
pcireg_t memtype, reg; |
pcireg_t memtype, reg; |
int i, error; |
int i, error; |
char intrbuf[PCI_INTRSTR_LEN]; |
|
|
|
sc->sc_dev = self; |
sc->sc_dev = self; |
sc->sc_pct = pa->pa_pc; |
sc->sc_pct = pa->pa_pc; |
Line 385 iwn_attach(device_t parent __unused, dev |
|
Line 361 iwn_attach(device_t parent __unused, dev |
|
error = pci_get_capability(sc->sc_pct, sc->sc_pcitag, |
error = pci_get_capability(sc->sc_pct, sc->sc_pcitag, |
PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL); |
PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL); |
if (error == 0) { |
if (error == 0) { |
aprint_error_dev(self, |
aprint_error(": PCIe capability structure not found!\n"); |
"PCIe capability structure not found!\n"); |
|
return; |
return; |
} |
} |
|
|
Line 395 iwn_attach(device_t parent __unused, dev |
|
Line 370 iwn_attach(device_t parent __unused, dev |
|
if (reg & 0xff00) |
if (reg & 0xff00) |
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); |
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); |
|
|
/* Enable bus-mastering. */ |
/* Enable bus-mastering and hardware bug workaround. */ |
/* XXX verify the bus-mastering is really needed (not in OpenBSD) */ |
/* XXX verify the bus-mastering is really needed (not in OpenBSD) */ |
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); |
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); |
reg |= PCI_COMMAND_MASTER_ENABLE; |
reg |= PCI_COMMAND_MASTER_ENABLE; |
|
if (reg & PCI_COMMAND_INTERRUPT_DISABLE) { |
|
DPRINTF(("PCIe INTx Disable set\n")); |
|
reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; |
|
} |
pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); |
pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); |
|
|
memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, IWN_PCI_BAR0); |
memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, IWN_PCI_BAR0); |
error = pci_mapreg_map(pa, IWN_PCI_BAR0, memtype, 0, &sc->sc_st, |
error = pci_mapreg_map(pa, IWN_PCI_BAR0, memtype, 0, &sc->sc_st, |
&sc->sc_sh, NULL, &sc->sc_sz); |
&sc->sc_sh, NULL, &sc->sc_sz); |
if (error != 0) { |
if (error != 0) { |
aprint_error_dev(self, "can't map mem space\n"); |
aprint_error(": can't map mem space\n"); |
return; |
return; |
} |
} |
|
|
sc->sc_soft_ih = softint_establish(SOFTINT_NET, iwn_softintr, sc); |
|
if (sc->sc_soft_ih == NULL) { |
|
aprint_error_dev(self, "can't establish soft interrupt\n"); |
|
goto unmap; |
|
} |
|
|
|
/* Install interrupt handler. */ |
/* Install interrupt handler. */ |
error = pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0); |
if (pci_intr_map(pa, &ih) != 0) { |
if (error) { |
aprint_error(": can't map interrupt\n"); |
aprint_error_dev(self, "can't allocate interrupt\n"); |
return; |
goto failsi; |
|
} |
} |
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); |
intrstr = pci_intr_string(sc->sc_pct, ih); |
if (pci_intr_type(sc->sc_pct, sc->sc_pihp[0]) == PCI_INTR_TYPE_INTX) |
sc->sc_ih = pci_intr_establish(sc->sc_pct, ih, IPL_NET, iwn_intr, sc); |
CLR(reg, PCI_COMMAND_INTERRUPT_DISABLE); |
|
else |
|
SET(reg, PCI_COMMAND_INTERRUPT_DISABLE); |
|
pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); |
|
intrstr = pci_intr_string(sc->sc_pct, sc->sc_pihp[0], intrbuf, |
|
sizeof(intrbuf)); |
|
sc->sc_ih = pci_intr_establish_xname(sc->sc_pct, sc->sc_pihp[0], |
|
IPL_NET, iwn_intr, sc, device_xname(self)); |
|
if (sc->sc_ih == NULL) { |
if (sc->sc_ih == NULL) { |
aprint_error_dev(self, "can't establish interrupt"); |
aprint_error(": can't establish interrupt"); |
if (intrstr != NULL) |
if (intrstr != NULL) |
aprint_error(" at %s", intrstr); |
aprint_error(" at %s", intrstr); |
aprint_error("\n"); |
aprint_error("\n"); |
goto failia; |
return; |
} |
} |
aprint_normal_dev(self, "interrupting at %s\n", intrstr); |
aprint_normal_dev(self, "interrupting at %s\n", intrstr); |
|
|
/* Read hardware revision and attach. */ |
/* Read hardware revision and attach. */ |
sc->hw_type = |
sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> 4) & 0xf; |
(IWN_READ(sc, IWN_HW_REV) & IWN_HW_REV_TYPE_MASK) |
|
>> IWN_HW_REV_TYPE_SHIFT; |
|
if (sc->hw_type == IWN_HW_REV_TYPE_4965) |
if (sc->hw_type == IWN_HW_REV_TYPE_4965) |
error = iwn4965_attach(sc, PCI_PRODUCT(pa->pa_id)); |
error = iwn4965_attach(sc, PCI_PRODUCT(pa->pa_id)); |
else |
else |
error = iwn5000_attach(sc, PCI_PRODUCT(pa->pa_id)); |
error = iwn5000_attach(sc, PCI_PRODUCT(pa->pa_id)); |
if (error != 0) { |
if (error != 0) { |
aprint_error_dev(self, "could not attach device\n"); |
aprint_error(": could not attach device\n"); |
goto failih; |
return; |
} |
} |
|
|
if ((error = iwn_hw_prepare(sc)) != 0) { |
if ((error = iwn_hw_prepare(sc)) != 0) { |
aprint_error_dev(self, "hardware not ready\n"); |
aprint_error(": hardware not ready\n"); |
goto failih; |
return; |
} |
} |
|
|
/* Read MAC address, channels, etc from EEPROM. */ |
/* Read MAC address, channels, etc from EEPROM. */ |
if ((error = iwn_read_eeprom(sc)) != 0) { |
if ((error = iwn_read_eeprom(sc)) != 0) { |
aprint_error_dev(self, "could not read EEPROM\n"); |
aprint_error(": could not read EEPROM\n"); |
goto failih; |
return; |
} |
} |
|
|
/* Allocate DMA memory for firmware transfers. */ |
/* Allocate DMA memory for firmware transfers. */ |
if ((error = iwn_alloc_fwmem(sc)) != 0) { |
if ((error = iwn_alloc_fwmem(sc)) != 0) { |
aprint_error_dev(self, |
aprint_error(": could not allocate memory for firmware\n"); |
"could not allocate memory for firmware\n"); |
return; |
goto failih; |
|
} |
} |
|
|
/* Allocate "Keep Warm" page. */ |
/* Allocate "Keep Warm" page. */ |
if ((error = iwn_alloc_kw(sc)) != 0) { |
if ((error = iwn_alloc_kw(sc)) != 0) { |
aprint_error_dev(self, "could not allocate keep warm page\n"); |
aprint_error(": could not allocate keep warm page\n"); |
goto fail1; |
goto fail1; |
} |
} |
|
|
/* Allocate ICT table for 5000 Series. */ |
/* Allocate ICT table for 5000 Series. */ |
if (sc->hw_type != IWN_HW_REV_TYPE_4965 && |
if (sc->hw_type != IWN_HW_REV_TYPE_4965 && |
(error = iwn_alloc_ict(sc)) != 0) { |
(error = iwn_alloc_ict(sc)) != 0) { |
aprint_error_dev(self, "could not allocate ICT table\n"); |
aprint_error(": could not allocate ICT table\n"); |
goto fail2; |
goto fail2; |
} |
} |
|
|
/* Allocate TX scheduler "rings". */ |
/* Allocate TX scheduler "rings". */ |
if ((error = iwn_alloc_sched(sc)) != 0) { |
if ((error = iwn_alloc_sched(sc)) != 0) { |
aprint_error_dev(self, |
aprint_error(": could not allocate TX scheduler rings\n"); |
"could not allocate TX scheduler rings\n"); |
|
goto fail3; |
goto fail3; |
} |
} |
|
|
Line 502 iwn_attach(device_t parent __unused, dev |
|
Line 462 iwn_attach(device_t parent __unused, dev |
|
/* Allocate TX rings (16 on 4965AGN, 20 on >=5000). */ |
/* Allocate TX rings (16 on 4965AGN, 20 on >=5000). */ |
for (i = 0; i < sc->ntxqs; i++) { |
for (i = 0; i < sc->ntxqs; i++) { |
if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { |
if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { |
aprint_error_dev(self, |
aprint_error(": could not allocate TX ring %d\n", i); |
"could not allocate TX ring %d\n", i); |
|
goto fail4; |
goto fail4; |
} |
} |
} |
} |
|
|
/* Allocate RX ring. */ |
/* Allocate RX ring. */ |
if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) { |
if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) { |
aprint_error_dev(self, "could not allocate RX ring\n"); |
aprint_error(": could not allocate RX ring\n"); |
goto fail4; |
goto fail4; |
} |
} |
|
|
Line 596 iwn_attach(device_t parent __unused, dev |
|
Line 555 iwn_attach(device_t parent __unused, dev |
|
IFQ_SET_READY(&ifp->if_snd); |
IFQ_SET_READY(&ifp->if_snd); |
memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); |
memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); |
|
|
error = if_initialize(ifp); |
if_attach(ifp); |
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, "if_initialize failed(%d)\n", |
|
error); |
|
goto fail5; |
|
} |
|
ieee80211_ifattach(ic); |
ieee80211_ifattach(ic); |
/* Use common softint-based if_input */ |
|
ifp->if_percpuq = if_percpuq_create(ifp); |
|
if_register(ifp); |
|
|
|
ic->ic_node_alloc = iwn_node_alloc; |
ic->ic_node_alloc = iwn_node_alloc; |
ic->ic_newassoc = iwn_newassoc; |
ic->ic_newassoc = iwn_newassoc; |
#ifdef IWN_HWCRYPTO |
#ifdef IWN_HWCRYPTO |
Line 644 iwn_attach(device_t parent __unused, dev |
|
Line 594 iwn_attach(device_t parent __unused, dev |
|
/* XXX NetBSD add call to ieee80211_announce for dmesg. */ |
/* XXX NetBSD add call to ieee80211_announce for dmesg. */ |
ieee80211_announce(ic); |
ieee80211_announce(ic); |
|
|
sc->sc_flags |= IWN_FLAG_ATTACHED; |
|
return; |
return; |
|
|
/* Free allocated memory if something failed during attachment. */ |
/* Free allocated memory if something failed during attachment. */ |
fail5: iwn_free_rx_ring(sc, &sc->rxq); |
|
fail4: while (--i >= 0) |
fail4: while (--i >= 0) |
iwn_free_tx_ring(sc, &sc->txq[i]); |
iwn_free_tx_ring(sc, &sc->txq[i]); |
#ifdef IWN_USE_RBUF |
#ifdef IWN_USE_RBUF |
Line 659 fail3: if (sc->ict != NULL) |
|
Line 607 fail3: if (sc->ict != NULL) |
|
iwn_free_ict(sc); |
iwn_free_ict(sc); |
fail2: iwn_free_kw(sc); |
fail2: iwn_free_kw(sc); |
fail1: iwn_free_fwmem(sc); |
fail1: iwn_free_fwmem(sc); |
failih: pci_intr_disestablish(sc->sc_pct, sc->sc_ih); |
|
sc->sc_ih = NULL; |
|
failia: pci_intr_release(sc->sc_pct, sc->sc_pihp, 1); |
|
sc->sc_pihp = NULL; |
|
failsi: softint_disestablish(sc->sc_soft_ih); |
|
sc->sc_soft_ih = NULL; |
|
unmap: bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz); |
|
} |
} |
|
|
int |
int |
Line 677 iwn4965_attach(struct iwn_softc *sc, pci |
|
Line 618 iwn4965_attach(struct iwn_softc *sc, pci |
|
ops->read_eeprom = iwn4965_read_eeprom; |
ops->read_eeprom = iwn4965_read_eeprom; |
ops->post_alive = iwn4965_post_alive; |
ops->post_alive = iwn4965_post_alive; |
ops->nic_config = iwn4965_nic_config; |
ops->nic_config = iwn4965_nic_config; |
ops->config_bt_coex = iwn_config_bt_coex_bluetooth; |
|
ops->update_sched = iwn4965_update_sched; |
ops->update_sched = iwn4965_update_sched; |
ops->get_temperature = iwn4965_get_temperature; |
ops->get_temperature = iwn4965_get_temperature; |
ops->get_rssi = iwn4965_get_rssi; |
ops->get_rssi = iwn4965_get_rssi; |
Line 717 iwn5000_attach(struct iwn_softc *sc, pci |
|
Line 657 iwn5000_attach(struct iwn_softc *sc, pci |
|
ops->read_eeprom = iwn5000_read_eeprom; |
ops->read_eeprom = iwn5000_read_eeprom; |
ops->post_alive = iwn5000_post_alive; |
ops->post_alive = iwn5000_post_alive; |
ops->nic_config = iwn5000_nic_config; |
ops->nic_config = iwn5000_nic_config; |
ops->config_bt_coex = iwn_config_bt_coex_bluetooth; |
|
ops->update_sched = iwn5000_update_sched; |
ops->update_sched = iwn5000_update_sched; |
ops->get_temperature = iwn5000_get_temperature; |
ops->get_temperature = iwn5000_get_temperature; |
ops->get_rssi = iwn5000_get_rssi; |
ops->get_rssi = iwn5000_get_rssi; |
Line 759 iwn5000_attach(struct iwn_softc *sc, pci |
|
Line 698 iwn5000_attach(struct iwn_softc *sc, pci |
|
break; |
break; |
case IWN_HW_REV_TYPE_1000: |
case IWN_HW_REV_TYPE_1000: |
sc->limits = &iwn1000_sensitivity_limits; |
sc->limits = &iwn1000_sensitivity_limits; |
if (pid == PCI_PRODUCT_INTEL_WIFI_LINK_100_1 || |
sc->fwname = "iwlwifi-1000-3.ucode"; |
pid == PCI_PRODUCT_INTEL_WIFI_LINK_100_2) |
|
sc->fwname = "iwlwifi-100-5.ucode"; |
|
else |
|
sc->fwname = "iwlwifi-1000-3.ucode"; |
|
break; |
break; |
case IWN_HW_REV_TYPE_6000: |
case IWN_HW_REV_TYPE_6000: |
sc->limits = &iwn6000_sensitivity_limits; |
sc->limits = &iwn6000_sensitivity_limits; |
Line 782 iwn5000_attach(struct iwn_softc *sc, pci |
|
Line 717 iwn5000_attach(struct iwn_softc *sc, pci |
|
break; |
break; |
case IWN_HW_REV_TYPE_6005: |
case IWN_HW_REV_TYPE_6005: |
sc->limits = &iwn6000_sensitivity_limits; |
sc->limits = &iwn6000_sensitivity_limits; |
/* Type 6030 cards return IWN_HW_REV_TYPE_6005 */ |
sc->fwname = "iwlwifi-6000g2a-5.ucode"; |
if (pid == PCI_PRODUCT_INTEL_WIFI_LINK_1030_1 || |
|
pid == PCI_PRODUCT_INTEL_WIFI_LINK_1030_2 || |
|
pid == PCI_PRODUCT_INTEL_WIFI_LINK_6230_1 || |
|
pid == PCI_PRODUCT_INTEL_WIFI_LINK_6230_2 || |
|
pid == PCI_PRODUCT_INTEL_WIFI_LINK_6235 || |
|
pid == PCI_PRODUCT_INTEL_WIFI_LINK_6235_2) { |
|
sc->fwname = "iwlwifi-6000g2b-6.ucode"; |
|
ops->config_bt_coex = iwn_config_bt_coex_adv1; |
|
} |
|
else |
|
sc->fwname = "iwlwifi-6000g2a-5.ucode"; |
|
break; |
|
case IWN_HW_REV_TYPE_2030: |
|
sc->limits = &iwn2030_sensitivity_limits; |
|
sc->fwname = "iwlwifi-2030-6.ucode"; |
|
ops->config_bt_coex = iwn_config_bt_coex_adv2; |
|
break; |
|
case IWN_HW_REV_TYPE_2000: |
|
sc->limits = &iwn2000_sensitivity_limits; |
|
sc->fwname = "iwlwifi-2000-6.ucode"; |
|
break; |
|
case IWN_HW_REV_TYPE_135: |
|
sc->limits = &iwn2000_sensitivity_limits; |
|
sc->fwname = "iwlwifi-135-6.ucode"; |
|
ops->config_bt_coex = iwn_config_bt_coex_adv2; |
|
break; |
|
case IWN_HW_REV_TYPE_105: |
|
sc->limits = &iwn2000_sensitivity_limits; |
|
sc->fwname = "iwlwifi-105-6.ucode"; |
|
break; |
break; |
default: |
default: |
aprint_normal(": adapter type %d not supported\n", sc->hw_type); |
aprint_normal(": adapter type %d not supported\n", sc->hw_type); |
Line 848 iwn_detach(device_t self, int flags __un |
|
Line 754 iwn_detach(device_t self, int flags __un |
|
struct ifnet *ifp = sc->sc_ic.ic_ifp; |
struct ifnet *ifp = sc->sc_ic.ic_ifp; |
int qid; |
int qid; |
|
|
if (!(sc->sc_flags & IWN_FLAG_ATTACHED)) |
|
return 0; |
|
|
|
callout_stop(&sc->calib_to); |
callout_stop(&sc->calib_to); |
|
|
/* Uninstall interrupt handler. */ |
/* Uninstall interrupt handler. */ |
if (sc->sc_ih != NULL) |
if (sc->sc_ih != NULL) |
pci_intr_disestablish(sc->sc_pct, sc->sc_ih); |
pci_intr_disestablish(sc->sc_pct, sc->sc_ih); |
if (sc->sc_pihp != NULL) |
|
pci_intr_release(sc->sc_pct, sc->sc_pihp, 1); |
|
if (sc->sc_soft_ih != NULL) |
|
softint_disestablish(sc->sc_soft_ih); |
|
|
|
/* Free DMA resources. */ |
/* Free DMA resources. */ |
iwn_free_rx_ring(sc, &sc->rxq); |
iwn_free_rx_ring(sc, &sc->rxq); |
Line 998 iwn_mem_write(struct iwn_softc *sc, uint |
|
Line 897 iwn_mem_write(struct iwn_softc *sc, uint |
|
IWN_WRITE(sc, IWN_MEM_WDATA, data); |
IWN_WRITE(sc, IWN_MEM_WDATA, data); |
} |
} |
|
|
#ifndef IEEE80211_NO_HT |
|
static __inline void |
static __inline void |
iwn_mem_write_2(struct iwn_softc *sc, uint32_t addr, uint16_t data) |
iwn_mem_write_2(struct iwn_softc *sc, uint32_t addr, uint16_t data) |
{ |
{ |
Line 1011 iwn_mem_write_2(struct iwn_softc *sc, ui |
|
Line 909 iwn_mem_write_2(struct iwn_softc *sc, ui |
|
tmp = (tmp & 0xffff0000) | data; |
tmp = (tmp & 0xffff0000) | data; |
iwn_mem_write(sc, addr & ~3, tmp); |
iwn_mem_write(sc, addr & ~3, tmp); |
} |
} |
#endif |
|
|
|
static __inline void |
static __inline void |
iwn_mem_read_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t *data, |
iwn_mem_read_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t *data, |
Line 1498 iwn5000_ict_reset(struct iwn_softc *sc) |
|
Line 1395 iwn5000_ict_reset(struct iwn_softc *sc) |
|
|
|
/* Reset ICT table. */ |
/* Reset ICT table. */ |
memset(sc->ict, 0, IWN_ICT_SIZE); |
memset(sc->ict, 0, IWN_ICT_SIZE); |
bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map, 0, IWN_ICT_SIZE, |
|
BUS_DMASYNC_PREWRITE); |
|
sc->ict_cur = 0; |
sc->ict_cur = 0; |
|
|
/* Set physical address of ICT table (4KB aligned). */ |
/* Set physical address of ICT table (4KB aligned). */ |
Line 1696 iwn5000_read_eeprom(struct iwn_softc *sc |
|
Line 1591 iwn5000_read_eeprom(struct iwn_softc *sc |
|
hdr.version, hdr.pa_type, le16toh(hdr.volt))); |
hdr.version, hdr.pa_type, le16toh(hdr.volt))); |
sc->calib_ver = hdr.version; |
sc->calib_ver = hdr.version; |
|
|
if (sc->hw_type == IWN_HW_REV_TYPE_2030 || |
|
sc->hw_type == IWN_HW_REV_TYPE_2000 || |
|
sc->hw_type == IWN_HW_REV_TYPE_135 || |
|
sc->hw_type == IWN_HW_REV_TYPE_105) { |
|
sc->eeprom_voltage = le16toh(hdr.volt); |
|
iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); |
|
sc->eeprom_temp = le16toh(val); |
|
iwn_read_prom_data(sc, base + IWN2000_EEPROM_RAWTEMP, &val, 2); |
|
sc->eeprom_rawtemp = le16toh(val); |
|
} |
|
|
|
if (sc->hw_type == IWN_HW_REV_TYPE_5150) { |
if (sc->hw_type == IWN_HW_REV_TYPE_5150) { |
/* Compute temperature offset. */ |
/* Compute temperature offset. */ |
iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); |
iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); |
Line 1787 iwn_read_eeprom_enhinfo(struct iwn_softc |
|
Line 1671 iwn_read_eeprom_enhinfo(struct iwn_softc |
|
struct iwn_eeprom_enhinfo enhinfo[35]; |
struct iwn_eeprom_enhinfo enhinfo[35]; |
uint16_t val, base; |
uint16_t val, base; |
int8_t maxpwr; |
int8_t maxpwr; |
uint8_t flags; |
|
int i; |
int i; |
|
|
iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); |
iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); |
Line 1797 iwn_read_eeprom_enhinfo(struct iwn_softc |
|
Line 1680 iwn_read_eeprom_enhinfo(struct iwn_softc |
|
|
|
memset(sc->enh_maxpwr, 0, sizeof sc->enh_maxpwr); |
memset(sc->enh_maxpwr, 0, sizeof sc->enh_maxpwr); |
for (i = 0; i < __arraycount(enhinfo); i++) { |
for (i = 0; i < __arraycount(enhinfo); i++) { |
flags = enhinfo[i].flags; |
if (enhinfo[i].chan == 0 || enhinfo[i].reserved != 0) |
if (!(flags & IWN_ENHINFO_VALID)) |
|
continue; /* Skip invalid entries. */ |
continue; /* Skip invalid entries. */ |
|
|
maxpwr = 0; |
maxpwr = 0; |
Line 1891 iwn_newstate(struct ieee80211com *ic, en |
|
Line 1773 iwn_newstate(struct ieee80211com *ic, en |
|
/* XXX Do not abort a running scan. */ |
/* XXX Do not abort a running scan. */ |
if (sc->sc_flags & IWN_FLAG_SCANNING) { |
if (sc->sc_flags & IWN_FLAG_SCANNING) { |
if (ic->ic_state != nstate) |
if (ic->ic_state != nstate) |
aprint_debug_dev(sc->sc_dev, "scan request(%d) " |
aprint_error_dev(sc->sc_dev, "scan request(%d) " |
"while scanning(%d) ignored\n", nstate, |
"while scanning(%d) ignored\n", nstate, |
ic->ic_state); |
ic->ic_state); |
break; |
break; |
Line 1900 iwn_newstate(struct ieee80211com *ic, en |
|
Line 1782 iwn_newstate(struct ieee80211com *ic, en |
|
/* XXX Not sure if call and flags are needed. */ |
/* XXX Not sure if call and flags are needed. */ |
ieee80211_node_table_reset(&ic->ic_scan); |
ieee80211_node_table_reset(&ic->ic_scan); |
ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; |
ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; |
sc->sc_flags |= IWN_FLAG_SCANNING_2GHZ; |
sc->sc_flags |= IWN_FLAG_SCANNING; |
|
|
/* Make the link LED blink while we're scanning. */ |
/* Make the link LED blink while we're scanning. */ |
iwn_set_led(sc, IWN_LED_LINK, 10, 10); |
iwn_set_led(sc, IWN_LED_LINK, 10, 10); |
Line 1923 iwn_newstate(struct ieee80211com *ic, en |
|
Line 1805 iwn_newstate(struct ieee80211com *ic, en |
|
sc->rxon.filter &= ~htole32(IWN_FILTER_BSS); |
sc->rxon.filter &= ~htole32(IWN_FILTER_BSS); |
sc->calib.state = IWN_CALIB_STATE_INIT; |
sc->calib.state = IWN_CALIB_STATE_INIT; |
|
|
/* Wait until we hear a beacon before we transmit */ |
|
if (IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) |
|
sc->sc_beacon_wait = 1; |
|
|
|
if ((error = iwn_auth(sc)) != 0) { |
if ((error = iwn_auth(sc)) != 0) { |
aprint_error_dev(sc->sc_dev, |
aprint_error_dev(sc->sc_dev, |
"could not move to auth state\n"); |
"could not move to auth state\n"); |
Line 1935 iwn_newstate(struct ieee80211com *ic, en |
|
Line 1813 iwn_newstate(struct ieee80211com *ic, en |
|
break; |
break; |
|
|
case IEEE80211_S_RUN: |
case IEEE80211_S_RUN: |
/* |
|
* RUN -> RUN transition; Just restart timers. |
|
*/ |
|
if (ic->ic_state == IEEE80211_S_RUN) { |
|
sc->calib_cnt = 0; |
|
break; |
|
} |
|
|
|
/* Wait until we hear a beacon before we transmit */ |
|
if (IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) |
|
sc->sc_beacon_wait = 1; |
|
|
|
if ((error = iwn_run(sc)) != 0) { |
if ((error = iwn_run(sc)) != 0) { |
aprint_error_dev(sc->sc_dev, |
aprint_error_dev(sc->sc_dev, |
"could not move to run state\n"); |
"could not move to run state\n"); |
Line 1957 iwn_newstate(struct ieee80211com *ic, en |
|
Line 1823 iwn_newstate(struct ieee80211com *ic, en |
|
case IEEE80211_S_INIT: |
case IEEE80211_S_INIT: |
sc->sc_flags &= ~IWN_FLAG_SCANNING; |
sc->sc_flags &= ~IWN_FLAG_SCANNING; |
sc->calib.state = IWN_CALIB_STATE_INIT; |
sc->calib.state = IWN_CALIB_STATE_INIT; |
/* |
|
* Purge the xmit queue so we don't have old frames |
|
* during a new association attempt. |
|
*/ |
|
sc->sc_beacon_wait = 0; |
|
ifp->if_flags &= ~IFF_OACTIVE; |
|
iwn_start(ifp); |
|
break; |
break; |
} |
} |
|
|
Line 2005 iwn_calib_timeout(void *arg) |
|
Line 1864 iwn_calib_timeout(void *arg) |
|
splx(s); |
splx(s); |
|
|
/* Automatic rate control triggered every 500ms. */ |
/* Automatic rate control triggered every 500ms. */ |
callout_schedule(&sc->calib_to, mstohz(500)); |
callout_schedule(&sc->calib_to, hz/2); |
} |
} |
|
|
/* |
/* |
Line 2045 iwn_rx_done(struct iwn_softc *sc, struct |
|
Line 1904 iwn_rx_done(struct iwn_softc *sc, struct |
|
struct iwn_rx_stat *stat; |
struct iwn_rx_stat *stat; |
char *head; |
char *head; |
uint32_t flags; |
uint32_t flags; |
int error, len, rssi, s; |
int error, len, rssi; |
|
|
if (desc->type == IWN_MPDU_RX_DONE) { |
if (desc->type == IWN_MPDU_RX_DONE) { |
/* Check for prior RX_PHY notification. */ |
/* Check for prior RX_PHY notification. */ |
Line 2131 iwn_rx_done(struct iwn_softc *sc, struct |
|
Line 1990 iwn_rx_done(struct iwn_softc *sc, struct |
|
BUS_DMASYNC_PREWRITE); |
BUS_DMASYNC_PREWRITE); |
|
|
/* Finalize mbuf. */ |
/* Finalize mbuf. */ |
m_set_rcvif(m, ifp); |
m->m_pkthdr.rcvif = ifp; |
m->m_data = head; |
m->m_data = head; |
m->m_pkthdr.len = m->m_len = len; |
m->m_pkthdr.len = m->m_len = len; |
|
|
s = splnet(); |
|
|
|
/* Grab a reference to the source node. */ |
/* Grab a reference to the source node. */ |
wh = mtod(m, struct ieee80211_frame *); |
wh = mtod(m, struct ieee80211_frame *); |
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); |
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); |
Line 2148 iwn_rx_done(struct iwn_softc *sc, struct |
|
Line 2005 iwn_rx_done(struct iwn_softc *sc, struct |
|
|
|
/* XXX Added for NetBSD: scans never stop without it */ |
/* XXX Added for NetBSD: scans never stop without it */ |
if (ic->ic_state == IEEE80211_S_SCAN) |
if (ic->ic_state == IEEE80211_S_SCAN) |
iwn_fix_channel(ic, m, stat); |
iwn_fix_channel(ic, m); |
|
|
if (sc->sc_drvbpf != NULL) { |
if (sc->sc_drvbpf != NULL) { |
struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap; |
struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap; |
Line 2185 iwn_rx_done(struct iwn_softc *sc, struct |
|
Line 2042 iwn_rx_done(struct iwn_softc *sc, struct |
|
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); |
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); |
} |
} |
|
|
/* |
|
* If it's a beacon and we're waiting, then do the wakeup. |
|
*/ |
|
if (sc->sc_beacon_wait) { |
|
uint8_t type, subtype; |
|
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; |
|
subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; |
|
/* |
|
* This assumes at this point we've received our own |
|
* beacon. |
|
*/ |
|
if (type == IEEE80211_FC0_TYPE_MGT && |
|
subtype == IEEE80211_FC0_SUBTYPE_BEACON) { |
|
sc->sc_beacon_wait = 0; |
|
ifp->if_flags &= ~IFF_OACTIVE; |
|
iwn_start(ifp); |
|
} |
|
} |
|
|
|
/* Send the frame to the 802.11 layer. */ |
/* Send the frame to the 802.11 layer. */ |
ieee80211_input(ic, m, ni, rssi, 0); |
ieee80211_input(ic, m, ni, rssi, 0); |
|
|
/* Node is no longer needed. */ |
/* Node is no longer needed. */ |
ieee80211_free_node(ni); |
ieee80211_free_node(ni); |
|
|
splx(s); |
|
} |
} |
|
|
#ifndef IEEE80211_NO_HT |
#ifndef IEEE80211_NO_HT |
Line 2251 iwn5000_rx_calib_results(struct iwn_soft |
|
Line 2087 iwn5000_rx_calib_results(struct iwn_soft |
|
|
|
switch (calib->code) { |
switch (calib->code) { |
case IWN5000_PHY_CALIB_DC: |
case IWN5000_PHY_CALIB_DC: |
if (sc->hw_type == IWN_HW_REV_TYPE_5150 || |
if (sc->hw_type == IWN_HW_REV_TYPE_5150) |
sc->hw_type == IWN_HW_REV_TYPE_2030 || |
|
sc->hw_type == IWN_HW_REV_TYPE_2000 || |
|
sc->hw_type == IWN_HW_REV_TYPE_135 || |
|
sc->hw_type == IWN_HW_REV_TYPE_105) |
|
idx = 0; |
idx = 0; |
break; |
break; |
case IWN5000_PHY_CALIB_LO: |
case IWN5000_PHY_CALIB_LO: |
Line 2395 iwn_tx_done(struct iwn_softc *sc, struct |
|
Line 2227 iwn_tx_done(struct iwn_softc *sc, struct |
|
struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; |
struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; |
struct iwn_tx_data *data = &ring->data[desc->idx]; |
struct iwn_tx_data *data = &ring->data[desc->idx]; |
struct iwn_node *wn = (struct iwn_node *)data->ni; |
struct iwn_node *wn = (struct iwn_node *)data->ni; |
int s; |
|
|
|
s = splnet(); |
|
|
|
/* Update rate control statistics. */ |
/* Update rate control statistics. */ |
wn->amn.amn_txcnt++; |
wn->amn.amn_txcnt++; |
Line 2423 iwn_tx_done(struct iwn_softc *sc, struct |
|
Line 2252 iwn_tx_done(struct iwn_softc *sc, struct |
|
sc->qfullmsk &= ~(1 << ring->qid); |
sc->qfullmsk &= ~(1 << ring->qid); |
if (sc->qfullmsk == 0 && (ifp->if_flags & IFF_OACTIVE)) { |
if (sc->qfullmsk == 0 && (ifp->if_flags & IFF_OACTIVE)) { |
ifp->if_flags &= ~IFF_OACTIVE; |
ifp->if_flags &= ~IFF_OACTIVE; |
iwn_start(ifp); |
(*ifp->if_start)(ifp); |
} |
} |
} |
} |
|
|
splx(s); |
|
} |
} |
|
|
/* |
/* |
Line 2466 iwn_notif_intr(struct iwn_softc *sc) |
|
Line 2293 iwn_notif_intr(struct iwn_softc *sc) |
|
struct ieee80211com *ic = &sc->sc_ic; |
struct ieee80211com *ic = &sc->sc_ic; |
struct ifnet *ifp = ic->ic_ifp; |
struct ifnet *ifp = ic->ic_ifp; |
uint16_t hw; |
uint16_t hw; |
int s; |
|
|
|
bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map, |
bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map, |
0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD); |
0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD); |
Line 2570 iwn_notif_intr(struct iwn_softc *sc) |
|
Line 2396 iwn_notif_intr(struct iwn_softc *sc) |
|
aprint_error_dev(sc->sc_dev, |
aprint_error_dev(sc->sc_dev, |
"Radio transmitter is off\n"); |
"Radio transmitter is off\n"); |
/* Turn the interface down. */ |
/* Turn the interface down. */ |
s = splnet(); |
|
ifp->if_flags &= ~IFF_UP; |
ifp->if_flags &= ~IFF_UP; |
iwn_stop(ifp, 1); |
iwn_stop(ifp, 1); |
splx(s); |
|
return; /* No further processing. */ |
return; /* No further processing. */ |
} |
} |
break; |
break; |
Line 2608 iwn_notif_intr(struct iwn_softc *sc) |
|
Line 2432 iwn_notif_intr(struct iwn_softc *sc) |
|
* We just finished scanning 2GHz channels, |
* We just finished scanning 2GHz channels, |
* start scanning 5GHz ones. |
* start scanning 5GHz ones. |
*/ |
*/ |
sc->sc_flags &= ~IWN_FLAG_SCANNING_2GHZ; |
|
sc->sc_flags |= IWN_FLAG_SCANNING_5GHZ; |
|
if (iwn_scan(sc, IEEE80211_CHAN_5GHZ) == 0) |
if (iwn_scan(sc, IEEE80211_CHAN_5GHZ) == 0) |
break; |
break; |
} |
} |
|
|
iwn_intr(void *arg) |
iwn_intr(void *arg) |
{ |
{ |
struct iwn_softc *sc = arg; |
struct iwn_softc *sc = arg; |
|
struct ifnet *ifp = sc->sc_ic.ic_ifp; |
|
uint32_t r1, r2, tmp; |
|
|
/* Disable interrupts. */ |
/* Disable interrupts. */ |
IWN_WRITE(sc, IWN_INT_MASK, 0); |
IWN_WRITE(sc, IWN_INT_MASK, 0); |
|
|
softint_schedule(sc->sc_soft_ih); |
|
return 1; |
|
} |
|
|
|
static void |
|
iwn_softintr(void *arg) |
|
{ |
|
struct iwn_softc *sc = arg; |
|
struct ifnet *ifp = sc->sc_ic.ic_ifp; |
|
uint32_t r1, r2, tmp; |
|
int s; |
|
|
|
/* Read interrupts from ICT (fast) or from registers (slow). */ |
/* Read interrupts from ICT (fast) or from registers (slow). */ |
if (sc->sc_flags & IWN_FLAG_USE_ICT) { |
if (sc->sc_flags & IWN_FLAG_USE_ICT) { |
bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map, 0, |
|
IWN_ICT_SIZE, BUS_DMASYNC_POSTREAD); |
|
tmp = 0; |
tmp = 0; |
while (sc->ict[sc->ict_cur] != 0) { |
while (sc->ict[sc->ict_cur] != 0) { |
tmp |= sc->ict[sc->ict_cur]; |
tmp |= sc->ict[sc->ict_cur]; |
sc->ict[sc->ict_cur] = 0; /* Acknowledge. */ |
sc->ict[sc->ict_cur] = 0; /* Acknowledge. */ |
sc->ict_cur = (sc->ict_cur + 1) % IWN_ICT_COUNT; |
sc->ict_cur = (sc->ict_cur + 1) % IWN_ICT_COUNT; |
} |
} |
bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map, 0, |
|
IWN_ICT_SIZE, BUS_DMASYNC_PREWRITE); |
|
tmp = le32toh(tmp); |
tmp = le32toh(tmp); |
if (tmp == 0xffffffff) /* Shouldn't happen. */ |
if (tmp == 0xffffffff) /* Shouldn't happen. */ |
tmp = 0; |
tmp = 0; |
Line 2759 iwn_softintr(void *arg) |
|
Line 2567 iwn_softintr(void *arg) |
|
} else { |
} else { |
r1 = IWN_READ(sc, IWN_INT); |
r1 = IWN_READ(sc, IWN_INT); |
if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) |
if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) |
return; /* Hardware gone! */ |
return 0; /* Hardware gone! */ |
r2 = IWN_READ(sc, IWN_FH_INT); |
r2 = IWN_READ(sc, IWN_FH_INT); |
} |
} |
if (r1 == 0 && r2 == 0) { |
if (r1 == 0 && r2 == 0) { |
goto out; /* Interrupt not for us. */ |
if (ifp->if_flags & IFF_UP) |
|
IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); |
|
return 0; /* Interrupt not for us. */ |
} |
} |
|
|
/* Acknowledge interrupts. */ |
/* Acknowledge interrupts. */ |
Line 2786 iwn_softintr(void *arg) |
|
Line 2596 iwn_softintr(void *arg) |
|
"fatal firmware error\n"); |
"fatal firmware error\n"); |
/* Dump firmware error log and stop. */ |
/* Dump firmware error log and stop. */ |
iwn_fatal_intr(sc); |
iwn_fatal_intr(sc); |
s = splnet(); |
|
ifp->if_flags &= ~IFF_UP; |
ifp->if_flags &= ~IFF_UP; |
iwn_stop(ifp, 1); |
iwn_stop(ifp, 1); |
splx(s); |
return 1; |
return; |
|
} |
} |
if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) || |
if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) || |
(r2 & IWN_FH_INT_RX)) { |
(r2 & IWN_FH_INT_RX)) { |
if (sc->sc_flags & IWN_FLAG_USE_ICT) { |
if (sc->sc_flags & IWN_FLAG_USE_ICT) { |
if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) |
if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) |
IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_RX); |
IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_RX); |
IWN_WRITE_1(sc, IWN_INT_PERIODIC, IWN_INT_PERIODIC_DIS); |
IWN_WRITE_1(sc, IWN_INT_PERIODIC, |
|
IWN_INT_PERIODIC_DIS); |
iwn_notif_intr(sc); |
iwn_notif_intr(sc); |
if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) { |
if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) { |
IWN_WRITE_1(sc, IWN_INT_PERIODIC, |
IWN_WRITE_1(sc, IWN_INT_PERIODIC, |
Line 2819 iwn_softintr(void *arg) |
|
Line 2628 iwn_softintr(void *arg) |
|
if (r1 & IWN_INT_WAKEUP) |
if (r1 & IWN_INT_WAKEUP) |
iwn_wakeup_intr(sc); |
iwn_wakeup_intr(sc); |
|
|
out: |
|
/* Re-enable interrupts. */ |
/* Re-enable interrupts. */ |
if (ifp->if_flags & IFF_UP) |
if (ifp->if_flags & IFF_UP) |
IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); |
IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); |
|
|
|
return 1; |
} |
} |
|
|
/* |
/* |
Line 2916 iwn_tx(struct iwn_softc *sc, struct mbuf |
|
Line 2726 iwn_tx(struct iwn_softc *sc, struct mbuf |
|
hdrlen = ieee80211_anyhdrsize(wh); |
hdrlen = ieee80211_anyhdrsize(wh); |
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; |
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; |
|
|
hdrlen2 = (ieee80211_has_qos(wh)) ? |
hdrlen2 = (IEEE80211_QOS_HAS_SEQ(wh)) ? |
sizeof (struct ieee80211_qosframe) : |
sizeof (struct ieee80211_qosframe) : |
sizeof (struct ieee80211_frame); |
sizeof (struct ieee80211_frame); |
|
|
Line 2926 iwn_tx(struct iwn_softc *sc, struct mbuf |
|
Line 2736 iwn_tx(struct iwn_softc *sc, struct mbuf |
|
|
|
/* XXX OpenBSD sets a different tid when using QOS */ |
/* XXX OpenBSD sets a different tid when using QOS */ |
tid = 0; |
tid = 0; |
if (ieee80211_has_qos(wh)) { |
if (IEEE80211_QOS_HAS_SEQ(wh)) { |
cap = &ic->ic_wme.wme_chanParams; |
cap = &ic->ic_wme.wme_chanParams; |
noack = cap->cap_wmeParams[ac].wmep_noackPolicy; |
noack = cap->cap_wmeParams[ac].wmep_noackPolicy; |
} |
} |
Line 3192 iwn_start(struct ifnet *ifp) |
|
Line 3002 iwn_start(struct ifnet *ifp) |
|
return; |
return; |
|
|
for (;;) { |
for (;;) { |
if (sc->sc_beacon_wait == 1) { |
|
ifp->if_flags |= IFF_OACTIVE; |
|
break; |
|
} |
|
|
|
if (sc->qfullmsk != 0) { |
if (sc->qfullmsk != 0) { |
ifp->if_flags |= IFF_OACTIVE; |
ifp->if_flags |= IFF_OACTIVE; |
break; |
break; |
Line 3204 iwn_start(struct ifnet *ifp) |
|
Line 3009 iwn_start(struct ifnet *ifp) |
|
/* Send pending management frames first. */ |
/* Send pending management frames first. */ |
IF_DEQUEUE(&ic->ic_mgtq, m); |
IF_DEQUEUE(&ic->ic_mgtq, m); |
if (m != NULL) { |
if (m != NULL) { |
ni = M_GETCTX(m, struct ieee80211_node *); |
ni = (void *)m->m_pkthdr.rcvif; |
ac = 0; |
ac = 0; |
goto sendit; |
goto sendit; |
} |
} |
Line 3239 iwn_start(struct ifnet *ifp) |
|
Line 3044 iwn_start(struct ifnet *ifp) |
|
ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ? |
ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ? |
M_WME_GETAC(m) : WME_AC_BE; |
M_WME_GETAC(m) : WME_AC_BE; |
|
|
if (sc->sc_beacon_wait == 0) |
bpf_mtap(ifp, m); |
bpf_mtap(ifp, m); |
|
|
|
if ((m = ieee80211_encap(ic, m, ni)) == NULL) { |
if ((m = ieee80211_encap(ic, m, ni)) == NULL) { |
ieee80211_free_node(ni); |
ieee80211_free_node(ni); |
Line 3248 iwn_start(struct ifnet *ifp) |
|
Line 3052 iwn_start(struct ifnet *ifp) |
|
continue; |
continue; |
} |
} |
sendit: |
sendit: |
if (sc->sc_beacon_wait) |
|
continue; |
|
|
|
bpf_mtap3(ic->ic_rawbpf, m); |
bpf_mtap3(ic->ic_rawbpf, m); |
|
|
if (iwn_tx(sc, m, ni, ac) != 0) { |
if (iwn_tx(sc, m, ni, ac) != 0) { |
|
|
sc->sc_tx_timer = 5; |
sc->sc_tx_timer = 5; |
ifp->if_timer = 1; |
ifp->if_timer = 1; |
} |
} |
|
|
if (sc->sc_beacon_wait > 1) |
|
sc->sc_beacon_wait = 0; |
|
} |
} |
|
|
static void |
static void |
Line 3294 iwn_ioctl(struct ifnet *ifp, u_long cmd, |
|
Line 3092 iwn_ioctl(struct ifnet *ifp, u_long cmd, |
|
{ |
{ |
struct iwn_softc *sc = ifp->if_softc; |
struct iwn_softc *sc = ifp->if_softc; |
struct ieee80211com *ic = &sc->sc_ic; |
struct ieee80211com *ic = &sc->sc_ic; |
|
struct ifaddr *ifa; |
const struct sockaddr *sa; |
const struct sockaddr *sa; |
int s, error = 0; |
int s, error = 0; |
|
|
Line 3301 iwn_ioctl(struct ifnet *ifp, u_long cmd, |
|
Line 3100 iwn_ioctl(struct ifnet *ifp, u_long cmd, |
|
|
|
switch (cmd) { |
switch (cmd) { |
case SIOCSIFADDR: |
case SIOCSIFADDR: |
|
ifa = (struct ifaddr *)data; |
ifp->if_flags |= IFF_UP; |
ifp->if_flags |= IFF_UP; |
|
#ifdef INET |
|
if (ifa->ifa_addr->sa_family == AF_INET) |
|
arp_ifinit(&ic->ic_ac, ifa); |
|
#endif |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case SIOCSIFFLAGS: |
case SIOCSIFFLAGS: |
/* XXX Added as it is in every NetBSD driver */ |
/* XXX Added as it is in every NetBSD driver */ |
|
|
iwn5000_set_txpower(struct iwn_softc *sc, int async) |
iwn5000_set_txpower(struct iwn_softc *sc, int async) |
{ |
{ |
struct iwn5000_cmd_txpower cmd; |
struct iwn5000_cmd_txpower cmd; |
int cmdid; |
|
|
|
/* |
/* |
* TX power calibration is handled automatically by the firmware |
* TX power calibration is handled automatically by the firmware |
Line 3768 iwn5000_set_txpower(struct iwn_softc *sc |
|
Line 3571 iwn5000_set_txpower(struct iwn_softc *sc |
|
cmd.flags = IWN5000_TXPOWER_NO_CLOSED; |
cmd.flags = IWN5000_TXPOWER_NO_CLOSED; |
cmd.srv_limit = IWN5000_TXPOWER_AUTO; |
cmd.srv_limit = IWN5000_TXPOWER_AUTO; |
DPRINTF(("setting TX power\n")); |
DPRINTF(("setting TX power\n")); |
if (IWN_UCODE_API(sc->ucode_rev) == 1) |
return iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async); |
cmdid = IWN_CMD_TXPOWER_DBM_V1; |
|
else |
|
cmdid = IWN_CMD_TXPOWER_DBM; |
|
return iwn_cmd(sc, cmdid, &cmd, sizeof cmd, async); |
|
} |
} |
|
|
/* |
/* |
Line 3988 iwn5000_init_gains(struct iwn_softc *sc) |
|
Line 3787 iwn5000_init_gains(struct iwn_softc *sc) |
|
struct iwn_phy_calib cmd; |
struct iwn_phy_calib cmd; |
|
|
memset(&cmd, 0, sizeof cmd); |
memset(&cmd, 0, sizeof cmd); |
cmd.code = sc->reset_noise_gain; |
cmd.code = IWN5000_PHY_CALIB_RESET_NOISE_GAIN; |
cmd.ngroups = 1; |
cmd.ngroups = 1; |
cmd.isvalid = 1; |
cmd.isvalid = 1; |
DPRINTF(("setting initial differential gains\n")); |
DPRINTF(("setting initial differential gains\n")); |
Line 4038 iwn5000_set_gains(struct iwn_softc *sc) |
|
Line 3837 iwn5000_set_gains(struct iwn_softc *sc) |
|
div = (sc->hw_type == IWN_HW_REV_TYPE_6050) ? 20 : 30; |
div = (sc->hw_type == IWN_HW_REV_TYPE_6050) ? 20 : 30; |
|
|
memset(&cmd, 0, sizeof cmd); |
memset(&cmd, 0, sizeof cmd); |
cmd.code = sc->noise_gain; |
cmd.code = IWN5000_PHY_CALIB_NOISE_GAIN; |
cmd.ngroups = 1; |
cmd.ngroups = 1; |
cmd.isvalid = 1; |
cmd.isvalid = 1; |
/* Get first available RX antenna as referential. */ |
/* Get first available RX antenna as referential. */ |
|
|
iwn_send_sensitivity(struct iwn_softc *sc) |
iwn_send_sensitivity(struct iwn_softc *sc) |
{ |
{ |
struct iwn_calib_state *calib = &sc->calib; |
struct iwn_calib_state *calib = &sc->calib; |
struct iwn_enhanced_sensitivity_cmd cmd; |
struct iwn_sensitivity_cmd cmd; |
int len; |
|
|
|
memset(&cmd, 0, sizeof cmd); |
memset(&cmd, 0, sizeof cmd); |
len = sizeof (struct iwn_sensitivity_cmd); |
|
cmd.which = IWN_SENSITIVITY_WORKTBL; |
cmd.which = IWN_SENSITIVITY_WORKTBL; |
/* OFDM modulation. */ |
/* OFDM modulation. */ |
cmd.corr_ofdm_x1 = htole16(calib->ofdm_x1); |
cmd.corr_ofdm_x1 = htole16(calib->ofdm_x1); |
Line 4233 iwn_send_sensitivity(struct iwn_softc *s |
|
Line 4030 iwn_send_sensitivity(struct iwn_softc *s |
|
cmd.energy_cck = htole16(calib->energy_cck); |
cmd.energy_cck = htole16(calib->energy_cck); |
/* Barker modulation: use default values. */ |
/* Barker modulation: use default values. */ |
cmd.corr_barker = htole16(190); |
cmd.corr_barker = htole16(190); |
cmd.corr_barker_mrc = htole16(sc->limits->barker_mrc); |
cmd.corr_barker_mrc = htole16(390); |
if (!(sc->sc_flags & IWN_FLAG_ENH_SENS)) |
|
goto send; |
|
/* Enhanced sensitivity settings. */ |
|
len = sizeof (struct iwn_enhanced_sensitivity_cmd); |
|
cmd.ofdm_det_slope_mrc = htole16(668); |
|
cmd.ofdm_det_icept_mrc = htole16(4); |
|
cmd.ofdm_det_slope = htole16(486); |
|
cmd.ofdm_det_icept = htole16(37); |
|
cmd.cck_det_slope_mrc = htole16(853); |
|
cmd.cck_det_icept_mrc = htole16(4); |
|
cmd.cck_det_slope = htole16(476); |
|
cmd.cck_det_icept = htole16(99); |
|
send: |
|
DPRINTFN(2, ("setting sensitivity %d/%d/%d/%d/%d/%d/%d\n", |
DPRINTFN(2, ("setting sensitivity %d/%d/%d/%d/%d/%d/%d\n", |
calib->ofdm_x1, calib->ofdm_mrc_x1, calib->ofdm_x4, |
calib->ofdm_x1, calib->ofdm_mrc_x1, calib->ofdm_x4, |
calib->ofdm_mrc_x4, calib->cck_x4, calib->cck_mrc_x4, |
calib->ofdm_mrc_x4, calib->cck_x4, calib->cck_mrc_x4, |
calib->energy_cck)); |
calib->energy_cck)); |
return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, len, 1); |
return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, sizeof cmd, 1); |
} |
} |
|
|
/* |
/* |
Line 4282 iwn_set_pslevel(struct iwn_softc *sc, in |
|
Line 4067 iwn_set_pslevel(struct iwn_softc *sc, in |
|
cmd.flags |= htole16(IWN_PS_FAST_PD); |
cmd.flags |= htole16(IWN_PS_FAST_PD); |
/* Retrieve PCIe Active State Power Management (ASPM). */ |
/* Retrieve PCIe Active State Power Management (ASPM). */ |
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, |
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, |
sc->sc_cap_off + PCIE_LCSR); |
sc->sc_cap_off + PCI_PCIE_LCSR); |
if (!(reg & PCIE_LCSR_ASPM_L0S)) /* L0s Entry disabled. */ |
if (!(reg & PCI_PCIE_LCSR_ASPM_L0S)) /* L0s Entry disabled. */ |
cmd.flags |= htole16(IWN_PS_PCI_PMGT); |
cmd.flags |= htole16(IWN_PS_PCI_PMGT); |
cmd.rxtimeout = htole32(pmgt->rxtimeout * 1024); |
cmd.rxtimeout = htole32(pmgt->rxtimeout * 1024); |
cmd.txtimeout = htole32(pmgt->txtimeout * 1024); |
cmd.txtimeout = htole32(pmgt->txtimeout * 1024); |
Line 4322 iwn5000_runtime_calib(struct iwn_softc * |
|
Line 4107 iwn5000_runtime_calib(struct iwn_softc * |
|
} |
} |
|
|
static int |
static int |
iwn_config_bt_coex_bluetooth(struct iwn_softc *sc) |
|
{ |
|
struct iwn_bluetooth bluetooth; |
|
|
|
memset(&bluetooth, 0, sizeof bluetooth); |
|
bluetooth.flags = IWN_BT_COEX_ENABLE; |
|
bluetooth.lead_time = IWN_BT_LEAD_TIME_DEF; |
|
bluetooth.max_kill = IWN_BT_MAX_KILL_DEF; |
|
|
|
DPRINTF(("configuring bluetooth coexistence\n")); |
|
return iwn_cmd(sc, IWN_CMD_BT_COEX, &bluetooth, sizeof bluetooth, 0); |
|
} |
|
|
|
static int |
|
iwn_config_bt_coex_prio_table(struct iwn_softc *sc) |
|
{ |
|
uint8_t prio_table[16]; |
|
|
|
memset(&prio_table, 0, sizeof prio_table); |
|
prio_table[ 0] = 6; /* init calibration 1 */ |
|
prio_table[ 1] = 7; /* init calibration 2 */ |
|
prio_table[ 2] = 2; /* periodic calib low 1 */ |
|
prio_table[ 3] = 3; /* periodic calib low 2 */ |
|
prio_table[ 4] = 4; /* periodic calib high 1 */ |
|
prio_table[ 5] = 5; /* periodic calib high 2 */ |
|
prio_table[ 6] = 6; /* dtim */ |
|
prio_table[ 7] = 8; /* scan52 */ |
|
prio_table[ 8] = 10; /* scan24 */ |
|
|
|
DPRINTF(("sending priority lookup table\n")); |
|
return iwn_cmd(sc, IWN_CMD_BT_COEX_PRIO_TABLE, |
|
&prio_table, sizeof prio_table, 0); |
|
} |
|
|
|
static int |
|
iwn_config_bt_coex_adv_config(struct iwn_softc *sc, struct iwn_bt_basic *basic, |
|
size_t len) |
|
{ |
|
struct iwn_btcoex_prot btprot; |
|
int error; |
|
|
|
basic->bt.flags = IWN_BT_COEX_ENABLE; |
|
basic->bt.lead_time = IWN_BT_LEAD_TIME_DEF; |
|
basic->bt.max_kill = IWN_BT_MAX_KILL_DEF; |
|
basic->bt.bt3_timer_t7_value = IWN_BT_BT3_T7_DEF; |
|
basic->bt.kill_ack_mask = IWN_BT_KILL_ACK_MASK_DEF; |
|
basic->bt.kill_cts_mask = IWN_BT_KILL_CTS_MASK_DEF; |
|
basic->bt3_prio_sample_time = IWN_BT_BT3_PRIO_SAMPLE_DEF; |
|
basic->bt3_timer_t2_value = IWN_BT_BT3_T2_DEF; |
|
basic->bt3_lookup_table[ 0] = htole32(0xaaaaaaaa); /* Normal */ |
|
basic->bt3_lookup_table[ 1] = htole32(0xaaaaaaaa); |
|
basic->bt3_lookup_table[ 2] = htole32(0xaeaaaaaa); |
|
basic->bt3_lookup_table[ 3] = htole32(0xaaaaaaaa); |
|
basic->bt3_lookup_table[ 4] = htole32(0xcc00ff28); |
|
basic->bt3_lookup_table[ 5] = htole32(0x0000aaaa); |
|
basic->bt3_lookup_table[ 6] = htole32(0xcc00aaaa); |
|
basic->bt3_lookup_table[ 7] = htole32(0x0000aaaa); |
|
basic->bt3_lookup_table[ 8] = htole32(0xc0004000); |
|
basic->bt3_lookup_table[ 9] = htole32(0x00004000); |
|
basic->bt3_lookup_table[10] = htole32(0xf0005000); |
|
basic->bt3_lookup_table[11] = htole32(0xf0005000); |
|
basic->reduce_txpower = 0; /* as not implemented */ |
|
basic->valid = IWN_BT_ALL_VALID_MASK; |
|
|
|
DPRINTF(("configuring advanced bluetooth coexistence v1\n")); |
|
error = iwn_cmd(sc, IWN_CMD_BT_COEX, basic, len, 0); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"could not configure advanced bluetooth coexistence\n"); |
|
return error; |
|
} |
|
|
|
error = iwn_config_bt_coex_prio_table(sc); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"could not configure send BT priority table\n"); |
|
return error; |
|
} |
|
|
|
/* Force BT state machine change */ |
|
memset(&btprot, 0, sizeof btprot); |
|
btprot.open = 1; |
|
btprot.type = 1; |
|
error = iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof btprot, 1); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, "could not open BT protcol\n"); |
|
return error; |
|
} |
|
|
|
btprot.open = 0; |
|
error = iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof btprot, 1); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, "could not close BT protcol\n"); |
|
return error; |
|
} |
|
return 0; |
|
} |
|
|
|
static int |
|
iwn_config_bt_coex_adv1(struct iwn_softc *sc) |
|
{ |
|
struct iwn_bt_adv1 d; |
|
|
|
memset(&d, 0, sizeof d); |
|
d.prio_boost = IWN_BT_PRIO_BOOST_DEF; |
|
d.tx_prio_boost = 0; |
|
d.rx_prio_boost = 0; |
|
return iwn_config_bt_coex_adv_config(sc, &d.basic, sizeof d); |
|
} |
|
|
|
static int |
|
iwn_config_bt_coex_adv2(struct iwn_softc *sc) |
|
{ |
|
struct iwn_bt_adv2 d; |
|
|
|
memset(&d, 0, sizeof d); |
|
d.prio_boost = IWN_BT_PRIO_BOOST_DEF; |
|
d.tx_prio_boost = 0; |
|
d.rx_prio_boost = 0; |
|
return iwn_config_bt_coex_adv_config(sc, &d.basic, sizeof d); |
|
} |
|
|
|
static int |
|
iwn_config(struct iwn_softc *sc) |
iwn_config(struct iwn_softc *sc) |
{ |
{ |
struct iwn_ops *ops = &sc->ops; |
struct iwn_ops *ops = &sc->ops; |
struct ieee80211com *ic = &sc->sc_ic; |
struct ieee80211com *ic = &sc->sc_ic; |
struct ifnet *ifp = ic->ic_ifp; |
struct ifnet *ifp = ic->ic_ifp; |
|
struct iwn_bluetooth bluetooth; |
uint32_t txmask; |
uint32_t txmask; |
uint16_t rxchain; |
uint16_t rxchain; |
int error; |
int error; |
|
|
error = ops->config_bt_coex(sc); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"could not configure bluetooth coexistence\n"); |
|
return error; |
|
} |
|
|
|
/* Set radio temperature sensor offset. */ |
|
if (sc->hw_type == IWN_HW_REV_TYPE_6005) { |
|
error = iwn6000_temp_offset_calib(sc); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"could not set temperature offset\n"); |
|
return error; |
|
} |
|
} |
|
|
|
if (sc->hw_type == IWN_HW_REV_TYPE_2030 || |
|
sc->hw_type == IWN_HW_REV_TYPE_2000 || |
|
sc->hw_type == IWN_HW_REV_TYPE_135 || |
|
sc->hw_type == IWN_HW_REV_TYPE_105) { |
|
error = iwn2000_temp_offset_calib(sc); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"could not set temperature offset\n"); |
|
return error; |
|
} |
|
} |
|
|
|
if (sc->hw_type == IWN_HW_REV_TYPE_6050 || |
if (sc->hw_type == IWN_HW_REV_TYPE_6050 || |
sc->hw_type == IWN_HW_REV_TYPE_6005) { |
sc->hw_type == IWN_HW_REV_TYPE_6005) { |
/* Configure runtime DC calibration. */ |
/* Configure runtime DC calibration. */ |
Line 4507 iwn_config(struct iwn_softc *sc) |
|
Line 4141 iwn_config(struct iwn_softc *sc) |
|
} |
} |
} |
} |
|
|
|
/* Configure bluetooth coexistence. */ |
|
memset(&bluetooth, 0, sizeof bluetooth); |
|
bluetooth.flags = IWN_BT_COEX_CHAN_ANN | IWN_BT_COEX_BT_PRIO; |
|
bluetooth.lead_time = IWN_BT_LEAD_TIME_DEF; |
|
bluetooth.max_kill = IWN_BT_MAX_KILL_DEF; |
|
DPRINTF(("configuring bluetooth coexistence\n")); |
|
error = iwn_cmd(sc, IWN_CMD_BT_COEX, &bluetooth, sizeof bluetooth, 0); |
|
if (error != 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"could not configure bluetooth coexistence\n"); |
|
return error; |
|
} |
|
|
/* Set mode, channel, RX filter and enable RX. */ |
/* Set mode, channel, RX filter and enable RX. */ |
memset(&sc->rxon, 0, sizeof (struct iwn_rxon)); |
memset(&sc->rxon, 0, sizeof (struct iwn_rxon)); |
IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); |
IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); |
Line 4576 iwn_config(struct iwn_softc *sc) |
|
Line 4223 iwn_config(struct iwn_softc *sc) |
|
return 0; |
return 0; |
} |
} |
|
|
static uint16_t |
|
iwn_get_active_dwell_time(struct iwn_softc *sc, uint16_t flags, |
|
uint8_t n_probes) |
|
{ |
|
/* No channel? Default to 2GHz settings */ |
|
if (flags & IEEE80211_CHAN_2GHZ) |
|
return IWN_ACTIVE_DWELL_TIME_2GHZ + |
|
IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1); |
|
|
|
/* 5GHz dwell time */ |
|
return IWN_ACTIVE_DWELL_TIME_5GHZ + |
|
IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1); |
|
} |
|
|
|
/* |
|
* Limit the total dwell time to 85% of the beacon interval. |
|
* |
|
* Returns the dwell time in milliseconds. |
|
*/ |
|
static uint16_t |
|
iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) |
|
{ |
|
struct ieee80211com *ic = &sc->sc_ic; |
|
struct ieee80211_node *ni = ic->ic_bss; |
|
int bintval = 0; |
|
|
|
/* bintval is in TU (1.024mS) */ |
|
if (ni != NULL) |
|
bintval = ni->ni_intval; |
|
|
|
/* |
|
* If it's non-zero, we should calculate the minimum of |
|
* it and the DWELL_BASE. |
|
* |
|
* XXX Yes, the math should take into account that bintval |
|
* is 1.024mS, not 1mS.. |
|
*/ |
|
if (bintval > 0) |
|
return MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100)); |
|
|
|
/* No association context? Default */ |
|
return IWN_PASSIVE_DWELL_BASE; |
|
} |
|
|
|
static uint16_t |
|
iwn_get_passive_dwell_time(struct iwn_softc *sc, uint16_t flags) |
|
{ |
|
uint16_t passive; |
|
if (flags & IEEE80211_CHAN_2GHZ) |
|
passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ; |
|
else |
|
passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ; |
|
|
|
/* Clamp to the beacon interval if we're associated */ |
|
return iwn_limit_dwell(sc, passive); |
|
} |
|
|
|
static int |
static int |
iwn_scan(struct iwn_softc *sc, uint16_t flags) |
iwn_scan(struct iwn_softc *sc, uint16_t flags) |
{ |
{ |
Line 4645 iwn_scan(struct iwn_softc *sc, uint16_t |
|
Line 4235 iwn_scan(struct iwn_softc *sc, uint16_t |
|
struct ieee80211_rateset *rs; |
struct ieee80211_rateset *rs; |
struct ieee80211_channel *c; |
struct ieee80211_channel *c; |
uint8_t *buf, *frm; |
uint8_t *buf, *frm; |
uint16_t rxchain, dwell_active, dwell_passive; |
uint16_t rxchain; |
uint8_t txant; |
uint8_t txant; |
int buflen, error, is_active; |
int buflen, error; |
|
|
buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); |
buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); |
if (buf == NULL) { |
if (buf == NULL) { |
Line 4698 iwn_scan(struct iwn_softc *sc, uint16_t |
|
Line 4288 iwn_scan(struct iwn_softc *sc, uint16_t |
|
txant = IWN_LSB(sc->txchainmask); |
txant = IWN_LSB(sc->txchainmask); |
tx->rflags |= IWN_RFLAG_ANT(txant); |
tx->rflags |= IWN_RFLAG_ANT(txant); |
|
|
/* |
|
* Only do active scanning if we're announcing a probe request |
|
* for a given SSID (or more, if we ever add it to the driver.) |
|
*/ |
|
is_active = 0; |
|
|
|
essid = (struct iwn_scan_essid *)(tx + 1); |
essid = (struct iwn_scan_essid *)(tx + 1); |
if (ic->ic_des_esslen != 0) { |
if (ic->ic_des_esslen != 0) { |
essid[0].id = IEEE80211_ELEMID_SSID; |
essid[0].id = IEEE80211_ELEMID_SSID; |
essid[0].len = ic->ic_des_esslen; |
essid[0].len = ic->ic_des_esslen; |
memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen); |
memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen); |
|
|
is_active = 1; |
|
} |
} |
/* |
/* |
* Build a probe request frame. Most of the following code is a |
* Build a probe request frame. Most of the following code is a |
Line 4739 iwn_scan(struct iwn_softc *sc, uint16_t |
|
Line 4321 iwn_scan(struct iwn_softc *sc, uint16_t |
|
/* Set length of probe request. */ |
/* Set length of probe request. */ |
tx->len = htole16(frm - (uint8_t *)wh); |
tx->len = htole16(frm - (uint8_t *)wh); |
|
|
|
|
/* |
|
* If active scanning is requested but a certain channel is |
|
* marked passive, we can do active scanning if we detect |
|
* transmissions. |
|
* |
|
* There is an issue with some firmware versions that triggers |
|
* a sysassert on a "good CRC threshold" of zero (== disabled), |
|
* on a radar channel even though this means that we should NOT |
|
* send probes. |
|
* |
|
* The "good CRC threshold" is the number of frames that we |
|
* need to receive during our dwell time on a channel before |
|
* sending out probes -- setting this to a huge value will |
|
* mean we never reach it, but at the same time work around |
|
* the aforementioned issue. Thus use IWN_GOOD_CRC_TH_NEVER |
|
* here instead of IWN_GOOD_CRC_TH_DISABLED. |
|
* |
|
* This was fixed in later versions along with some other |
|
* scan changes, and the threshold behaves as a flag in those |
|
* versions. |
|
*/ |
|
|
|
/* |
|
* If we're doing active scanning, set the crc_threshold |
|
* to a suitable value. This is different to active veruss |
|
* passive scanning depending upon the channel flags; the |
|
* firmware will obey that particular check for us. |
|
*/ |
|
if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN) |
|
hdr->crc_threshold = is_active ? |
|
IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED; |
|
else |
|
hdr->crc_threshold = is_active ? |
|
IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER; |
|
|
|
chan = (struct iwn_scan_chan *)frm; |
chan = (struct iwn_scan_chan *)frm; |
for (c = &ic->ic_channels[1]; |
for (c = &ic->ic_channels[1]; |
c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) { |
c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) { |
Line 4788 iwn_scan(struct iwn_softc *sc, uint16_t |
|
Line 4334 iwn_scan(struct iwn_softc *sc, uint16_t |
|
chan->flags |= htole32(IWN_CHAN_ACTIVE); |
chan->flags |= htole32(IWN_CHAN_ACTIVE); |
if (ic->ic_des_esslen != 0) |
if (ic->ic_des_esslen != 0) |
chan->flags |= htole32(IWN_CHAN_NPBREQS(1)); |
chan->flags |= htole32(IWN_CHAN_NPBREQS(1)); |
|
|
/* |
|
* Calculate the active/passive dwell times. |
|
*/ |
|
|
|
dwell_active = iwn_get_active_dwell_time(sc, flags, is_active); |
|
dwell_passive = iwn_get_passive_dwell_time(sc, flags); |
|
|
|
/* Make sure they're valid */ |
|
if (dwell_passive <= dwell_active) |
|
dwell_passive = dwell_active + 1; |
|
|
|
chan->active = htole16(dwell_active); |
|
chan->passive = htole16(dwell_passive); |
|
|
|
chan->dsp_gain = 0x6e; |
chan->dsp_gain = 0x6e; |
if (IEEE80211_IS_CHAN_5GHZ(c)) { |
if (IEEE80211_IS_CHAN_5GHZ(c)) { |
chan->rf_gain = 0x3b; |
chan->rf_gain = 0x3b; |
|
chan->active = htole16(24); |
|
chan->passive = htole16(110); |
} else { |
} else { |
chan->rf_gain = 0x28; |
chan->rf_gain = 0x28; |
|
chan->active = htole16(36); |
|
chan->passive = htole16(120); |
} |
} |
hdr->nchan++; |
hdr->nchan++; |
chan++; |
chan++; |
Line 5355 iwn5000_send_wimax_coex(struct iwn_softc |
|
Line 4890 iwn5000_send_wimax_coex(struct iwn_softc |
|
return iwn_cmd(sc, IWN5000_CMD_WIMAX_COEX, &wimax, sizeof wimax, 0); |
return iwn_cmd(sc, IWN5000_CMD_WIMAX_COEX, &wimax, sizeof wimax, 0); |
} |
} |
|
|
static int |
|
iwn6000_temp_offset_calib(struct iwn_softc *sc) |
|
{ |
|
struct iwn6000_phy_calib_temp_offset cmd; |
|
|
|
memset(&cmd, 0, sizeof cmd); |
|
cmd.code = IWN6000_PHY_CALIB_TEMP_OFFSET; |
|
cmd.ngroups = 1; |
|
cmd.isvalid = 1; |
|
if (sc->eeprom_temp != 0) |
|
cmd.offset = htole16(sc->eeprom_temp); |
|
else |
|
cmd.offset = htole16(IWN_DEFAULT_TEMP_OFFSET); |
|
DPRINTF(("setting radio sensor offset to %d\n", le16toh(cmd.offset))); |
|
return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); |
|
} |
|
|
|
static int |
|
iwn2000_temp_offset_calib(struct iwn_softc *sc) |
|
{ |
|
struct iwn2000_phy_calib_temp_offset cmd; |
|
|
|
memset(&cmd, 0, sizeof cmd); |
|
cmd.code = IWN2000_PHY_CALIB_TEMP_OFFSET; |
|
cmd.ngroups = 1; |
|
cmd.isvalid = 1; |
|
if (sc->eeprom_rawtemp != 0) { |
|
cmd.offset_low = htole16(sc->eeprom_rawtemp); |
|
cmd.offset_high = htole16(sc->eeprom_temp); |
|
} else { |
|
cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET); |
|
cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET); |
|
} |
|
cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage); |
|
DPRINTF(("setting radio sensor offset to %d:%d, voltage to %d\n", |
|
le16toh(cmd.offset_low), le16toh(cmd.offset_high), |
|
le16toh(cmd.burnt_voltage_ref))); |
|
return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); |
|
} |
|
|
|
/* |
/* |
* This function is called after the runtime firmware notifies us of its |
* This function is called after the runtime firmware notifies us of its |
* readiness (called in a process context). |
* readiness (called in a process context). |
Line 5744 iwn_read_firmware_leg(struct iwn_softc * |
|
Line 5239 iwn_read_firmware_leg(struct iwn_softc * |
|
ptr = (const uint32_t *)fw->data; |
ptr = (const uint32_t *)fw->data; |
rev = le32toh(*ptr++); |
rev = le32toh(*ptr++); |
|
|
sc->ucode_rev = rev; |
|
|
|
/* Check firmware API version. */ |
/* Check firmware API version. */ |
if (IWN_FW_API(rev) <= 1) { |
if (IWN_FW_API(rev) <= 1) { |
aprint_error_dev(sc->sc_dev, |
aprint_error_dev(sc->sc_dev, |
Line 5811 iwn_read_firmware_tlv(struct iwn_softc * |
|
Line 5304 iwn_read_firmware_tlv(struct iwn_softc * |
|
} |
} |
DPRINTF(("FW: \"%.64s\", build 0x%x\n", hdr->descr, |
DPRINTF(("FW: \"%.64s\", build 0x%x\n", hdr->descr, |
le32toh(hdr->build))); |
le32toh(hdr->build))); |
sc->ucode_rev = le32toh(hdr->rev); |
|
|
|
/* |
/* |
* Select the closest supported alternative that is less than |
* Select the closest supported alternative that is less than |
Line 5861 iwn_read_firmware_tlv(struct iwn_softc * |
|
Line 5353 iwn_read_firmware_tlv(struct iwn_softc * |
|
fw->boot.text = ptr; |
fw->boot.text = ptr; |
fw->boot.textsz = len; |
fw->boot.textsz = len; |
break; |
break; |
case IWN_FW_TLV_ENH_SENS: |
|
if (len != 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"TLV type %d has invalid size %u\n", |
|
le16toh(tlv->type), len); |
|
goto next; |
|
} |
|
sc->sc_flags |= IWN_FLAG_ENH_SENS; |
|
break; |
|
case IWN_FW_TLV_PHY_CALIB: |
|
if (len != sizeof(uint32_t)) { |
|
aprint_error_dev(sc->sc_dev, |
|
"TLV type %d has invalid size %u\n", |
|
le16toh(tlv->type), len); |
|
goto next; |
|
} |
|
if (le32toh(*ptr) <= IWN5000_PHY_CALIB_MAX) { |
|
sc->reset_noise_gain = le32toh(*ptr); |
|
sc->noise_gain = le32toh(*ptr) + 1; |
|
} |
|
break; |
|
case IWN_FW_TLV_FLAGS: |
|
if (len < sizeof(uint32_t)) |
|
break; |
|
if (len % sizeof(uint32_t)) |
|
break; |
|
sc->tlv_feature_flags = le32toh(*ptr); |
|
DPRINTF(("feature: 0x%08x\n", sc->tlv_feature_flags)); |
|
break; |
|
default: |
default: |
DPRINTF(("TLV type %d not handled\n", |
DPRINTF(("TLV type %d not handled\n", |
le16toh(tlv->type))); |
le16toh(tlv->type))); |
Line 5908 iwn_read_firmware(struct iwn_softc *sc) |
|
Line 5371 iwn_read_firmware(struct iwn_softc *sc) |
|
firmware_handle_t fwh; |
firmware_handle_t fwh; |
int error; |
int error; |
|
|
/* |
|
* Some PHY calibration commands are firmware-dependent; these |
|
* are the default values that will be overridden if |
|
* necessary. |
|
*/ |
|
sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN; |
|
sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN; |
|
|
|
/* Initialize for error returns */ |
/* Initialize for error returns */ |
fw->data = NULL; |
fw->data = NULL; |
fw->size = 0; |
fw->size = 0; |
Line 6020 iwn_apm_init(struct iwn_softc *sc) |
|
Line 5475 iwn_apm_init(struct iwn_softc *sc) |
|
|
|
/* Retrieve PCIe Active State Power Management (ASPM). */ |
/* Retrieve PCIe Active State Power Management (ASPM). */ |
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, |
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, |
sc->sc_cap_off + PCIE_LCSR); |
sc->sc_cap_off + PCI_PCIE_LCSR); |
/* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ |
/* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ |
if (reg & PCIE_LCSR_ASPM_L1) /* L1 Entry enabled. */ |
if (reg & PCI_PCIE_LCSR_ASPM_L1) /* L1 Entry enabled. */ |
IWN_SETBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); |
IWN_SETBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); |
else |
else |
IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); |
IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); |
Line 6067 iwn_apm_stop_master(struct iwn_softc *sc |
|
Line 5522 iwn_apm_stop_master(struct iwn_softc *sc |
|
return; |
return; |
DELAY(10); |
DELAY(10); |
} |
} |
aprint_error_dev(sc->sc_dev, "timeout waiting for master\n"); |
aprint_error_dev(sc->sc_dev, |
|
"timeout waiting for master\n"); |
} |
} |
|
|
static void |
static void |
Line 6138 iwn5000_nic_config(struct iwn_softc *sc) |
|
Line 5594 iwn5000_nic_config(struct iwn_softc *sc) |
|
IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA); |
IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA); |
} |
} |
if ((sc->hw_type == IWN_HW_REV_TYPE_6050 || |
if ((sc->hw_type == IWN_HW_REV_TYPE_6050 || |
sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) { |
sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) { |
/* Indicate that ROM calibration version is >=6. */ |
/* Indicate that ROM calibration version is >=6. */ |
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6); |
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6); |
} |
} |
if (sc->hw_type == IWN_HW_REV_TYPE_6005) |
if (sc->hw_type == IWN_HW_REV_TYPE_6005) |
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2); |
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2); |
if (sc->hw_type == IWN_HW_REV_TYPE_2030 || |
|
sc->hw_type == IWN_HW_REV_TYPE_2000 || |
|
sc->hw_type == IWN_HW_REV_TYPE_135 || |
|
sc->hw_type == IWN_HW_REV_TYPE_105) |
|
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_IQ_INVERT); |
|
return 0; |
return 0; |
} |
} |
|
|
Line 6400 iwn_init(struct ifnet *ifp) |
|
Line 5851 iwn_init(struct ifnet *ifp) |
|
goto fail; |
goto fail; |
} |
} |
|
|
sc->sc_beacon_wait = 0; |
|
|
|
ifp->if_flags &= ~IFF_OACTIVE; |
ifp->if_flags &= ~IFF_OACTIVE; |
ifp->if_flags |= IFF_RUNNING; |
ifp->if_flags |= IFF_RUNNING; |
|
|
Line 6572 iwn_free_rpool(struct iwn_softc *sc) |
|
Line 6021 iwn_free_rpool(struct iwn_softc *sc) |
|
#endif |
#endif |
|
|
/* |
/* |
|
* XXX code from OpenBSD src/sys/net80211/ieee80211_output.c |
|
* Copyright (c) 2001 Atsushi Onoe |
|
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting |
|
* Copyright (c) 2007-2009 Damien Bergamini |
|
* All rights reserved. |
|
*/ |
|
|
|
/* |
|
* Add an SSID element to a frame (see 7.3.2.1). |
|
*/ |
|
static u_int8_t * |
|
ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) |
|
{ |
|
*frm++ = IEEE80211_ELEMID_SSID; |
|
*frm++ = len; |
|
memcpy(frm, ssid, len); |
|
return frm + len; |
|
} |
|
|
|
/* |
|
* Add a supported rates element to a frame (see 7.3.2.2). |
|
*/ |
|
static u_int8_t * |
|
ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs) |
|
{ |
|
int nrates; |
|
|
|
*frm++ = IEEE80211_ELEMID_RATES; |
|
nrates = min(rs->rs_nrates, IEEE80211_RATE_SIZE); |
|
*frm++ = nrates; |
|
memcpy(frm, rs->rs_rates, nrates); |
|
return frm + nrates; |
|
} |
|
|
|
/* |
|
* Add an extended supported rates element to a frame (see 7.3.2.14). |
|
*/ |
|
static u_int8_t * |
|
ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs) |
|
{ |
|
int nrates; |
|
|
|
KASSERT(rs->rs_nrates > IEEE80211_RATE_SIZE); |
|
|
|
*frm++ = IEEE80211_ELEMID_XRATES; |
|
nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; |
|
*frm++ = nrates; |
|
memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); |
|
return frm + nrates; |
|
} |
|
|
|
/* |
* XXX: Hack to set the current channel to the value advertised in beacons or |
* XXX: Hack to set the current channel to the value advertised in beacons or |
* probe responses. Only used during AP detection. |
* probe responses. Only used during AP detection. |
* XXX: Duplicated from if_iwi.c |
* XXX: Duplicated from if_iwi.c |
*/ |
*/ |
static void |
static void |
iwn_fix_channel(struct ieee80211com *ic, struct mbuf *m, |
iwn_fix_channel(struct ieee80211com *ic, struct mbuf *m) |
struct iwn_rx_stat *stat) |
|
{ |
{ |
struct iwn_softc *sc = ic->ic_ifp->if_softc; |
|
struct ieee80211_frame *wh; |
struct ieee80211_frame *wh; |
uint8_t subtype; |
uint8_t subtype; |
uint8_t *frm, *efrm; |
uint8_t *frm, *efrm; |
Line 6596 iwn_fix_channel(struct ieee80211com *ic, |
|
Line 6095 iwn_fix_channel(struct ieee80211com *ic, |
|
subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) |
subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) |
return; |
return; |
|
|
if (sc->sc_flags & IWN_FLAG_SCANNING_5GHZ) { |
|
int chan = le16toh(stat->chan); |
|
if (chan < __arraycount(ic->ic_channels)) |
|
ic->ic_curchan = &ic->ic_channels[chan]; |
|
return; |
|
} |
|
|
|
frm = (uint8_t *)(wh + 1); |
frm = (uint8_t *)(wh + 1); |
efrm = mtod(m, uint8_t *) + m->m_len; |
efrm = mtod(m, uint8_t *) + m->m_len; |
|
|
Line 6618 iwn_fix_channel(struct ieee80211com *ic, |
|
Line 6110 iwn_fix_channel(struct ieee80211com *ic, |
|
} |
} |
} |
} |
|
|
#ifdef notyetMODULE |
|
|
|
MODULE(MODULE_CLASS_DRIVER, if_iwn, "pci"); |
|
|
|
#ifdef _MODULE |
|
#include "ioconf.c" |
|
#endif |
|
|
|
static int |
|
if_iwn_modcmd(modcmd_t cmd, void *data) |
|
{ |
|
int error = 0; |
|
|
|
switch (cmd) { |
|
case MODULE_CMD_INIT: |
|
#ifdef _MODULE |
|
error = config_init_component(cfdriver_ioconf_if_iwn, |
|
cfattach_ioconf_if_iwn, cfdata_ioconf_if_iwn); |
|
#endif |
|
return error; |
|
case MODULE_CMD_FINI: |
|
#ifdef _MODULE |
|
error = config_fini_component(cfdriver_ioconf_if_iwn, |
|
cfattach_ioconf_if_iwn, cfdata_ioconf_if_iwn); |
|
#endif |
|
return error; |
|
case MODULE_CMD_AUTOUNLOAD: |
|
#ifdef _MODULE |
|
/* XXX This is not optional! */ |
|
#endif |
|
return error; |
|
default: |
|
return ENOTTY; |
|
} |
|
} |
|
#endif |
|