From patchwork Tue Nov 23 18:41:15 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nick Kossifidis X-Patchwork-Id: 350191 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oANIwFUZ004920 for ; Tue, 23 Nov 2010 18:58:34 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756370Ab0KWSlZ (ORCPT ); Tue, 23 Nov 2010 13:41:25 -0500 Received: from mail-ew0-f46.google.com ([209.85.215.46]:53229 "EHLO mail-ew0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756363Ab0KWSlZ (ORCPT ); Tue, 23 Nov 2010 13:41:25 -0500 Received: by ewy5 with SMTP id 5so2636287ewy.19 for ; Tue, 23 Nov 2010 10:41:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:date:from:to:cc:subject :message-id:mail-followup-to:mime-version:content-type :content-disposition:user-agent; bh=okGq8Z7T4oOK8f8BouF/rXenswqA4emJxLQgni+Vchw=; b=TolwlUhtKevsQo1uBbABRv1MgbsxOVQGfLI2QaVyWo3Ow4U1VGRnfpnv5GHzOCJFz/ Q3BYO5qDRAV/M/+HSNOtE579jK73+k2AnirqBoPwRqGtVoFd7lbY+vY55SMmT5yMeey9 TlTQcghoZ5F1D7y0kRMNm7l5RlkcOlTEcm+pA= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=date:from:to:cc:subject:message-id:mail-followup-to:mime-version :content-type:content-disposition:user-agent; b=O2sOqcvc58jVWqjZjL05gdnNUBqcUv/ZOzVqpJIXBRT0+PUs2oh+X/ZaSl0TqL+I7C nPYPTdEZa3ccw1ohh8zu5q+g8EApZ7xZ2Kz4AwydG9Ei3fj8xDFfRJ5p7AVe8jFYC2Vk zbeZdKTKGACckiBMP0xAmXh74m1KnquK5tufA= Received: by 10.213.105.76 with SMTP id s12mr3713432ebo.2.1290537683535; Tue, 23 Nov 2010 10:41:23 -0800 (PST) Received: from localhost ([139.91.73.37]) by mx.google.com with ESMTPS id b52sm6074361eei.1.2010.11.23.10.41.18 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 23 Nov 2010 10:41:20 -0800 (PST) Date: Tue, 23 Nov 2010 20:41:15 +0200 From: Nick Kossifidis To: ath5k-devel@venema.h4ckr.net, linux-wireless@vger.kernel.org Cc: linville@tuxdriver.com, me@bobcopeland.com, mcgrof@gmail.com, jirislaby@gmail.com, nbd@openwrt.org, br1@einfach.org Subject: [PATCH 02/30] ath5k: Add new function to stop rx/tx DMA Message-ID: <20101123184115.GB4303@makis.mantri> Mail-Followup-To: ath5k-devel@lists.ath5k.org, linux-wireless@vger.kernel.org, linville@tuxdriver.com, me@bobcopeland.com, mcgrof@gmail.com, jirislaby@gmail.com, nbd@openwrt.org, br1@einfach.org MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 23 Nov 2010 18:59:04 +0000 (UTC) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 85ff822..629a5ee 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1180,8 +1180,9 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); void ath5k_hw_update_mib_counters(struct ath5k_hw *ah); -/* Init function */ +/* Init/Stop functions */ void ath5k_hw_dma_init(struct ath5k_hw *ah); +int ath5k_hw_dma_stop(struct ath5k_hw *ah); /* EEPROM access functions */ int ath5k_eeprom_init(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index b991b05..ca0467e 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -126,7 +126,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) /* Return if queue is declared inactive */ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; + return -EINVAL; if (ah->ah_version == AR5K_AR5210) { tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); @@ -174,7 +174,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) * * Stop DMA transmit on a specific hw queue and drain queue so we don't * have any pending frames. Returns -EBUSY if we still have pending frames, - * -EINVAL if queue number is out of range. + * -EINVAL if queue number is out of range or inactive. * */ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) @@ -186,7 +186,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) /* Return if queue is declared inactive */ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; + return -EINVAL; if (ah->ah_version == AR5K_AR5210) { tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); @@ -733,3 +733,49 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah) ath5k_hw_set_imr(ah, ah->ah_imr); } + +/** + * ath5k_hw_dma_stop - stop DMA unit + * + * @ah: The &struct ath5k_hw + * + * Stop tx/rx DMA and interrupts. Returns + * -EBUSY if tx or rx dma failed to stop. + * + * XXX: Sometimes DMA unit hangs and we have + * stuck frames on tx queues, only a reset + * can fix that. + */ +int ath5k_hw_dma_stop(struct ath5k_hw *ah) +{ + int i, qmax, err; + err = 0; + + /* Disable interrupts */ + ath5k_hw_set_imr(ah, 0); + + /* Stop rx dma */ + err = ath5k_hw_stop_rx_dma(ah); + if (err) + return err; + + /* Clear any pending interrupts + * and disable tx dma */ + if (ah->ah_version != AR5K_AR5210) { + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); + qmax = AR5K_NUM_TX_QUEUES; + } else { + /* PISR/SISR Not available on 5210 */ + ath5k_hw_reg_read(ah, AR5K_ISR); + qmax = AR5K_NUM_TX_QUEUES_NOQCU; + } + + for (i = 0; i < qmax; i++) { + err = ath5k_hw_stop_tx_dma(ah, i); + /* -EINVAL -> queue inactive */ + if (err != -EINVAL) + return err; + } + + return err; +} diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 9dd5792..4f94a60 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -823,6 +823,14 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, mode = 0; /* + * Stop DMA + * + * Note: If DMA didn't stop continue + * since only a reset will fix it. + */ + ath5k_hw_dma_stop(ah); + + /* * Save some registers before a reset */ /*DCU/Antenna selection not available on 5210*/ @@ -1015,11 +1023,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ ath5k_hw_pcu_init(ah, op_mode, mode); - /* Clear any pending interrupts - * PISR/SISR Not available on 5210 */ - if (ah->ah_version != AR5K_AR5210) - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); - /* * Initialize PHY */