void ath_rx99_ctl(struct ath_softc *sc ,int val) { struct ath_hal *ah = sc->sc_ah; if(val && !sc->sc_txrx99.rx99mode) { sc->sc_txrx99.prev_hard_start = sc->sc_dev.hard_start_xmit; sc->sc_txrx99.prev_mgt_start = sc->sc_ic.ic_mgtstart; sc->sc_dev.hard_start_xmit = ath_rx99_hardstart; sc->sc_ic.ic_mgtstart = ath_rx99_mgtstart; /* * Disable interrupts. */ sc->sc_txrx99.imask=sc->sc_imask; sc->sc_imask &= (~(HAL_INT_SWBA | HAL_INT_BMISS)); ath_hal_intrset(ah, sc->sc_imask ); } else { if(!val && sc->sc_txrx99.rx99mode) { sc->sc_dev.hard_start_xmit = sc->sc_txrx99.prev_hard_start; sc->sc_ic.ic_mgtstart = sc->sc_txrx99.prev_mgt_start; sc->sc_txrx99.prev_hard_start = sc->sc_txrx99.prev_mgt_start=NULL; sc->sc_imask |= (sc->sc_txrx99.imask & (HAL_INT_SWBA | HAL_INT_BMISS)); ath_hal_intrset(ah, sc->sc_imask); sc->sc_txrx99.imask=0; } } sc->sc_txrx99.rx99mode=val; }
void enable_beacons(struct ath_softc *sc) { SPECTRAL_DPRINTK(sc, ATH_DEBUG_SPECTRAL2,"Turning ON SWBA and BMISS interrupts before imask = 0x%x\n", ath_hal_intrget(sc->sc_ah)); sc->sc_imask |= (HAL_INT_SWBA | HAL_INT_BMISS); ath_hal_intrset(sc->sc_ah, sc->sc_imask); SPECTRAL_DPRINTK(sc, ATH_DEBUG_SPECTRAL2,"AFTER imask = 0x%x\n", ath_hal_intrget(sc->sc_ah)); }
static void ath_pwrsave_set_state_sync(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; ATH_PWRSAVE_STATE newstate = (sc)->sc_pwrsave.ps_set_state; if(sc->sc_pwrsave.ps_pwrsave_state == newstate) return; if (sc->sc_removed) return; switch (sc->sc_pwrsave.ps_pwrsave_state) { case ATH_PWRSAVE_NETWORK_SLEEP: switch (newstate) { case ATH_PWRSAVE_AWAKE: if (!ATH_PS_ALWAYS_AWAKE(sc)){ ath_hal_setpower(ah, HAL_PM_AWAKE); /* * Must clear RxAbort bit manually if hardware does not support * automatic sleep after waking up for TIM. */ if (! sc->sc_hasautosleep) { u_int32_t imask; ath_hal_setrxabort(ah, 0); /* Disable TIM_TIMER interrupt */ imask = ath_hal_intrget(ah); if ((imask & HAL_INT_TIM_TIMER) || ((imask & HAL_INT_TSFOOR) == 0)) { sc->sc_imask &= ~HAL_INT_TIM_TIMER; imask &= ~HAL_INT_TIM_TIMER; imask |= HAL_INT_TSFOOR; sc->sc_imask |= HAL_INT_TSFOOR; ath_hal_intrset(ah, imask); } } } #if ATH_TX_DUTY_CYCLE if (sc->sc_tx_dc_enable) { u_int32_t duration; /* re-arm tx duty cycle */ DPRINTF(sc, ATH_DEBUG_ANY, "%s: %d=>%d: re-enable quiet time: %u%% active\n", __func__, sc->sc_pwrsave.ps_pwrsave_state, newstate, sc->sc_tx_dc_active_pct); if (sc->sc_opmode == HAL_M_HOSTAP && sc->sc_nbcnvaps != 0) { ath_beacon_config(sc, ATH_BEACON_CONFIG_REASON_RESET, ATH_IF_ID_ANY); }else if (sc->sc_nvaps){ duration = ((100-sc->sc_tx_dc_active_pct)*sc->sc_tx_dc_period)/100; ath_hal_setQuiet(sc->sc_ah, sc->sc_tx_dc_period, duration, 0, AH_TRUE); } } #endif break; case ATH_PWRSAVE_FULL_SLEEP: /* * Stop both receive PCU and DMA before going full sleep to prevent deaf mute. */ ath_hal_setrxabort(ah, 1); ath_hal_stopdmarecv(ah, 0); ath_hal_setpower(ah, HAL_PM_FULL_SLEEP); break; default: break; } break; case ATH_PWRSAVE_AWAKE: switch (newstate) { case ATH_PWRSAVE_NETWORK_SLEEP: if (!ATH_PS_ALWAYS_AWAKE(sc)){ /* * Chips that do not support automatic sleep after waking up to * receive TIM must make sure at least one beacon is received * before reentering network sleep. */ #if ATH_TX_DUTY_CYCLE if (sc->sc_tx_dc_enable) { /* disarm tx duty cycle */ DPRINTF(sc, ATH_DEBUG_ANY, "%s: %d=>%d: disable quiet time: %u%% active\n", __func__, sc->sc_pwrsave.ps_pwrsave_state, newstate, sc->sc_tx_dc_active_pct); ath_hal_setQuiet(sc->sc_ah, 0, 0, 0, AH_FALSE); } #endif if (! sc->sc_hasautosleep) { /* * Do not enter network sleep if no beacon received */ if (! sc->sc_waitbeacon) { u_int32_t imask; /* Enable TIM_TIMER interrupt */ imask = ath_hal_intrget(ah); if (((imask & HAL_INT_TIM_TIMER) == 0) || (imask & HAL_INT_TSFOOR)){ sc->sc_imask |= HAL_INT_TIM_TIMER; imask |= HAL_INT_TIM_TIMER; imask &= ~HAL_INT_TSFOOR; sc->sc_imask &= ~HAL_INT_TSFOOR; ath_hal_intrset(ah, imask); } /* Stop RX state machine */ if (ath_hal_setrxabort(ah, 1)) { ath_hal_setpower(ah, HAL_PM_NETWORK_SLEEP); } } } else { ath_hal_setpower(ah, HAL_PM_NETWORK_SLEEP); } } break; case ATH_PWRSAVE_FULL_SLEEP: /* * Must abort rx prior to full sleep for 2 reasons: * * 1. Hardware does not support automatic sleep (sc_hasautosleep=0) * after waking up for TIM. * 2. WAR for EV68448 - card disappearance. * Ideally, rx would be stopped at a higher level * but the code was removed because it broke RFKILL (see EV66300). * 3. Stop both receive PCU and DMA before going full sleep to prevent deaf mute. */ #if ATH_TX_DUTY_CYCLE if (sc->sc_tx_dc_enable) { /* disarm tx duty cycle */ DPRINTF(sc, ATH_DEBUG_ANY, "%s: %d=>%d: disable quiet time: %u%% active\n", __func__, sc->sc_pwrsave.ps_pwrsave_state, newstate, sc->sc_tx_dc_active_pct); ath_hal_setQuiet(sc->sc_ah, 0, 0, 0, AH_FALSE); } #endif ath_hal_setrxabort(ah, 1); ath_hal_stopdmarecv(ah, 0); ath_hal_setpower(ah, HAL_PM_FULL_SLEEP); break; default: break; } break; case ATH_PWRSAVE_FULL_SLEEP: switch (newstate) { case ATH_PWRSAVE_AWAKE: ath_hal_setpower(ah, HAL_PM_AWAKE); /* * Must clear RxAbort bit manually if hardware does not support * automatic sleep after waking up for TIM. */ if (! sc->sc_hasautosleep) { u_int32_t imask; ath_hal_setrxabort(ah, 0); /* Disable TIM_TIMER interrupt */ imask = ath_hal_intrget(ah); if (imask & HAL_INT_TIM_TIMER) { sc->sc_imask &= ~HAL_INT_TIM_TIMER; ath_hal_intrset(ah, imask & ~HAL_INT_TIM_TIMER); } } #if ATH_TX_DUTY_CYCLE if (sc->sc_tx_dc_enable) { u_int32_t duration; /* re-arm tx duty cycle */ DPRINTF(sc, ATH_DEBUG_ANY, "%s: %d=>%d: re-enable quiet time: %u%% active\n", __func__, sc->sc_pwrsave.ps_pwrsave_state, newstate, sc->sc_tx_dc_active_pct); if (sc->sc_opmode == HAL_M_HOSTAP && sc->sc_nbcnvaps != 0) { ath_beacon_config(sc, ATH_BEACON_CONFIG_REASON_RESET, ATH_IF_ID_ANY); }else if (sc->sc_nvaps){ duration = ((100-sc->sc_tx_dc_active_pct)*sc->sc_tx_dc_period)/100; ath_hal_setQuiet(sc->sc_ah, sc->sc_tx_dc_period, duration, 0, AH_TRUE); } } #endif break; default: break; } default: break; } sc->sc_pwrsave.ps_pwrsave_state = newstate; /* If chip has been put in full sleep, make sure full reset is called */ if (sc->sc_pwrsave.ps_pwrsave_state == ATH_PWRSAVE_FULL_SLEEP) sc->sc_full_reset = 1; }
/* * To enable PHY (radio on) */ int ath_radio_enable(ath_dev_t dev) { struct ath_softc *sc = ATH_DEV_TO_SC(dev); struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; HAL_HT_MACMODE ht_macmode = sc->sc_ieee_ops->cwm_macmode(sc->sc_ieee); if (sc->sc_invalid) return -EIO; #if ATH_RESET_SERIAL ATH_RESET_ACQUIRE_MUTEX(sc); #endif ATH_PS_WAKEUP(sc); ath_pwrsave_awake(sc); /* Turn off PCIE ASPM when card is active */ ath_pcie_pwrsave_enable_on_phystate_change(sc, 0); ATH_USB_TX_STOP(sc->sc_osdev); #if ATH_C3_WAR STOP_C3_WAR_TIMER(sc); #endif #if !ATH_RESET_SERIAL ATH_LOCK_PCI_IRQ(sc); #endif if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, AH_FALSE, &status, sc->sc_scanning)) { printk("%s: unable to reset hardware; hal status %u\n", __func__, status); } #if !ATH_RESET_SERIAL ATH_UNLOCK_PCI_IRQ(sc); #endif ath_update_txpow(sc, sc->tx_power); /* update tx power state */ ath_beacon_config(sc, ATH_BEACON_CONFIG_REASON_RESET, ATH_IF_ID_ANY); /* restart beacons */ ath_hal_intrset(ah, sc->sc_imask); ath_wmi_start_recv(sc); if (ATH_STARTRECV(sc) != 0) { /* restart recv */ printk("%s: unable to start recv logic\n", __func__); } ATH_USB_TX_START(sc->sc_osdev); /* * notify LED module radio has been turned on * This function will access the hw, so we must call it after * the power save function. */ ath_led_enable(&sc->sc_led_control); ATH_PS_SLEEP(sc); #if ATH_RESET_SERIAL ATH_RESET_RELEASE_MUTEX(sc); #endif return 0; }
/* * To disable PHY (radio off) */ int ath_radio_disable(ath_dev_t dev) { struct ath_softc *sc = ATH_DEV_TO_SC(dev); struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; HAL_HT_MACMODE ht_macmode = sc->sc_ieee_ops->cwm_macmode(sc->sc_ieee); if (sc->sc_invalid) return -EIO; #if ATH_RESET_SERIAL ATH_RESET_ACQUIRE_MUTEX(sc); ATH_RESET_LOCK(sc); atomic_inc(&sc->sc_hold_reset); ath_reset_wait_tx_rx_finished(sc); ATH_RESET_UNLOCK(sc); #endif ATH_PS_WAKEUP(sc); /* * notify LED module radio has been turned off * This function will access the hw, so we must call it before * the power save function. */ ath_led_disable(&sc->sc_led_control); ath_hal_intrset(ah, 0); /* disable interrupts */ ath_reset_draintxq(sc, AH_FALSE, 0); /* stop xmit side */ ATH_USB_TX_STOP(sc->sc_osdev); ATH_HTC_DRAINTXQ(sc); /* stop target xmit */ ATH_STOPRECV(sc, 0); /* stop recv side */ ath_flushrecv(sc); /* flush recv queue */ #if ATH_C3_WAR STOP_C3_WAR_TIMER(sc); #endif #if !ATH_RESET_SERIAL ATH_LOCK_PCI_IRQ(sc); #endif if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, AH_FALSE, &status, sc->sc_scanning)) { printk("%s: unable to reset hardware; hal status %u\n", __func__, status); } ATH_HTC_ABORTTXQ(sc); #if !ATH_RESET_SERIAL ATH_UNLOCK_PCI_IRQ(sc); #endif ATH_USB_TX_START(sc->sc_osdev); ath_hal_phydisable(ah); #ifdef ATH_RFKILL if (sc->sc_hasrfkill) { ath_hal_intrset(ah, HAL_INT_GLOBAL | HAL_INT_GPIO); /* Enable interrupt to capture GPIO event */ } #endif /* Turn on PCIE ASPM during RF Silence */ ath_pcie_pwrsave_enable_on_phystate_change(sc, 1); /* * XXX TODO: We should put chip to forced sleep when radio is disabled. */ ath_pwrsave_fullsleep(sc); ATH_PS_SLEEP(sc); #if ATH_RESET_SERIAL atomic_dec(&sc->sc_hold_reset); ATH_RESET_RELEASE_MUTEX(sc); #endif return 0; }
void ath_cont_data(struct ath_softc *sc ,int val,ath_callback ath_draintxq, ath_callback ath_stoprecv) { static struct sk_buff *skb = NULL; struct ieee80211_frame *hdr; static struct ieee80211com *ic; static struct ath_buf *bf,*prev,*first; static struct ath_desc *ds; static struct ath_hal *ah; static STAILQ_HEAD(tpc_buf,ath_buf) tmp_q; static int is_inited=0; struct ath_txq *txq; const HAL_RATE_TABLE *rt; u_int8_t *p; u_int32_t flags, txrate, r,i; u_int16_t hdrlen, framelen, dmalen,delay=0; #define MIN(a,b) ((a) < (b) ? (a) : (b)) if(ath_hal_getdiagstate(sc->sc_ah, 19,0,10,NULL,NULL) == AH_FALSE) { printk("HAL does not support TX99 mode \n"); printk("compile HAL with AH_PRIVATE_DIAG turned on \n"); return; } if(is_inited == 0) { STAILQ_INIT(&tmp_q); is_inited=1; } /* enter CONT_DATA mode */ if (val && skb==NULL) { skb = ath_alloc_skb(4096, 32); if (skb == NULL) goto out; /* build output packet */ hdr = (struct ieee80211_frame *)skb_put(skb, sizeof(*hdr)); IEEE80211_ADDR_COPY(&hdr->i_addr1, test_addr); IEEE80211_ADDR_COPY(&hdr->i_addr2, test_addr); IEEE80211_ADDR_COPY(&hdr->i_addr3, test_addr); hdr->i_dur[0] = 0x0; hdr->i_dur[1] = 0x0; hdr->i_seq[0] = 0x5a; hdr->i_seq[1] = 0x5a; hdr->i_fc[0] = IEEE80211_FC0_TYPE_DATA; hdr->i_fc[1] = 0; hdrlen = sizeof(*hdr); for(r=0; r<2000; ) { p = skb_put(skb, sizeof(PN9Data)); memcpy(p, PN9Data, sizeof(PN9Data)); r += sizeof(PN9Data); } framelen = hdrlen + r + IEEE80211_CRC_LEN; ic = &sc->sc_ic; ah = sc->sc_ah; rt = sc->sc_currates; if (rt==NULL) { printk("no rate table\n"); goto out; } txrate = rt->info[rt->rateCount-1].rateCode; /* send at highest rate */ { int rix; if (sc->sc_txrx99.txrate==0) sc->sc_txrx99.txrate = 6000; for(rix=0; rix<rt->rateCount; rix++) { if (rt->info[rix].rateKbps==sc->sc_txrx99.txrate) { txrate = rt->info[rix].rateCode; printk("txrate set to %dKbps\n", sc->sc_txrx99.txrate); break; } } } ath_draintxq(sc); prev=first=NULL; printk("txpower set to %d\n", sc->sc_txrx99.txpower); /* send 20 frames for the Power Amp to settle down */ for(i=0;i<20;++i) { ATH_TXBUF_LOCK_BH(sc); bf = STAILQ_FIRST(&sc->sc_txbuf); if (bf != NULL) { STAILQ_REMOVE_HEAD(&sc->sc_txbuf,bf_list); } ATH_TXBUF_UNLOCK_BH(sc); if (bf==NULL) { printk("no tx buf\n"); goto out; } if(!i) first=bf; framelen = skb->len + IEEE80211_CRC_LEN; dmalen = skb->len; txq = sc->sc_ac2q[WME_AC_VO]; bf->bf_skbaddr = bus_map_single(sc->sc_bdev, skb->data, framelen, BUS_DMA_TODEVICE); bf->bf_skb = skb; bf->bf_node = 0; flags = HAL_TXDESC_CLRDMASK; ds = bf->bf_desc; if(prev) prev->bf_desc->ds_link = bf->bf_daddr; /* link from prev desc */ ds->ds_data = bf->bf_skbaddr; r = ath_hal_setuptxdesc(ah, ds, framelen, hdrlen, HAL_PKT_TYPE_NORMAL, sc->sc_txrx99.txpower, txrate, /* tx rate */ 1, /* max retries */ HAL_TXKEYIX_INVALID, /* no WEP */ 1, /* select Omni Antenna 0 */ flags, 0, /* rts/cts rate */ 0 /* rts/cts duration */ ); if (r==AH_FALSE) { printk("fail setuptxdesc r(%d)\n", r); goto out; } r = ath_hal_filltxdesc(ah, ds, skb->len, AH_TRUE, AH_TRUE,ds); if (r==AH_FALSE) { printk("fail fill tx desc r(%d)\n", r); goto out; } ath_hal_setupxtxdesc(ah, ds , txrate, 15 /* series 1 */ , txrate, 15 /* series 2 */ , txrate, 15 /* series 3 */ ); /* insert the buffers in to tmp_q */ STAILQ_INSERT_HEAD(&tmp_q,bf,bf_list); prev=bf; } ath_hal_intrset(ah, 0); /* disable interrupts */ //sc->sc_imask = HAL_INT_RX | HAL_INT_TX // | HAL_INT_RXEOL | HAL_INT_RXORN // | HAL_INT_FATAL | HAL_INT_GLOBAL; sc->sc_imask = 0; //ath_hal_intrset(ah, sc->sc_imask); bf->bf_desc->ds_link = 0; r = ath_hal_puttxbuf(ah, txq->axq_qnum, first->bf_daddr); ath_hal_txstart(ah, txq->axq_qnum); while(ath_hal_txprocdesc(ah,bf->bf_desc) == HAL_EINPROGRESS) { udelay(2000); ++delay; } /* sleep for 20ms */ udelay(20000); printk("took %d msec to transmit the 20 frames \n",2*delay); /* start TX99 mode */ ath_stoprecv(sc); /* stop recv side */ bf->bf_desc->ds_link = first->bf_daddr; /* link to self */ ath_hal_getdiagstate(ah, 19,(void *) sc->sc_txrx99.prefetch,9,NULL,NULL); ath_hal_getdiagstate(ah, 19, (void *)txq->axq_qnum, val,NULL,NULL); r = ath_hal_puttxbuf(ah, txq->axq_qnum, first->bf_daddr); ath_hal_txstart(ah, txq->axq_qnum); } /* leave CONT_DATA mode, reset the chip */ if (val==0 && skb) { int j=0; ath_hal_getdiagstate(ah, 19, 0, 0,NULL,NULL); /* insert the buffers back into txbuf list */ ATH_TXBUF_LOCK_BH(sc); bf = STAILQ_FIRST(&tmp_q); while(bf) { bf->bf_skb=NULL; STAILQ_REMOVE_HEAD(&tmp_q,bf_list); STAILQ_INSERT_HEAD(&sc->sc_txbuf,bf,bf_list); bf = STAILQ_FIRST(&tmp_q); ++j; } ATH_TXBUF_UNLOCK_BH(sc); printk("inserted back %d buffers \n",j); ic->ic_reset(ic->ic_dev); skb = NULL; bf = NULL; } if (val==7 && skb) { ath_hal_getdiagstate(ah, 19, ds, 7,NULL,NULL); } sc->sc_txrx99.tx99mode=val; out: return; #undef MIN }