iwlagn: Use iwl_write8() for CSR_INT_COALESCING register
authorBen Cahill <ben.m.cahill@intel.com>
Fri, 20 Nov 2009 20:04:53 +0000 (12:04 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 23 Nov 2009 22:05:30 +0000 (17:05 -0500)
CSR_INT_COALESCING previously had only one, but now has two single-byte fields.
With only one single-byte field (lowest order byte) it was okay to write via
iwl_write32(), but now with two, an iwl_write32() to the lower order field
clobbers the other field (odd-address CSR_INT_PERIODIC_REG, offset 0x5), and an
iwl_write32() to CSR_INT_PERIODIC_REG could clobber the lowest byte of the
next-higher register (CSR_INT, offset 0x8).

Fortunately, no bad side effects have been produced by the iwl_write32()
usage, due to order of execution (low order byte was always written before
higher order byte), and the fact that writing "0" to the low byte of the
next higher register has no effect (only action is when writing "1"s).

Nonetheless, this cleans up the accesses so no bad side effects might occur
in the future, if execution order changes, or more bit fields get added to
CSR_INT_COALESCING.

Add some comments regarding periodic interrupt usage.

Signed-off-by: Ben Cahill <ben.m.cahill@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-rx.c

index e8f405a01e3d50ad364a6fd86125845006a05c4a..a4e8db35a559638bdafadc283c373f97737e9930 100644 (file)
@@ -1266,15 +1266,24 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
                 * 3- update RX shared data to indicate last write index.
                 * 4- send interrupt.
                 * This could lead to RX race, driver could receive RX interrupt
-                * but the shared data changes does not reflect this.
-                * this could lead to RX race, RX periodic will solve this race
+                * but the shared data changes does not reflect this;
+                * periodic interrupt will detect any dangling Rx activity.
                 */
-               iwl_write32(priv, CSR_INT_PERIODIC_REG,
+
+               /* Disable periodic interrupt; we use it as just a one-shot. */
+               iwl_write8(priv, CSR_INT_PERIODIC_REG,
                            CSR_INT_PERIODIC_DIS);
                iwl_rx_handle(priv);
-               /* Only set RX periodic if real RX is received. */
+
+               /*
+                * Enable periodic interrupt in 8 msec only if we received
+                * real RX interrupt (instead of just periodic int), to catch
+                * any dangling Rx interrupt.  If it was just the periodic
+                * interrupt, there was no dangling Rx activity, and no need
+                * to extend the periodic interrupt; one-shot is enough.
+                */
                if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
-                       iwl_write32(priv, CSR_INT_PERIODIC_REG,
+                       iwl_write8(priv, CSR_INT_PERIODIC_REG,
                                    CSR_INT_PERIODIC_ENA);
 
                priv->isr_stats.rx++;
index a2636f4b068f3459c640af699eaaff534d5aa32d..c25cab5d0451f5bd943a7e652d409c1ab9547906 100644 (file)
@@ -255,7 +255,10 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
        /* nic_init */
        spin_lock_irqsave(&priv->lock, flags);
        priv->cfg->ops->lib->apm_ops.init(priv);
-       iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+
+       /* Set interrupt coalescing timer to 512 usecs */
+       iwl_write8(priv, CSR_INT_COALESCING, 512 / 32);
+
        spin_unlock_irqrestore(&priv->lock, flags);
 
        ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
index 68ed82206723fe4bbd5a85bcd21abf8490205477..a7bfae01f19b017e674ca15eee0a50aff8c2411f 100644 (file)
 #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
 #define CSR_HW_IF_CONFIG_REG_PREPARE             (0x08000000) /* WAKE_ME */
 
-#define CSR_INT_PERIODIC_DIS                   (0x00)
-#define CSR_INT_PERIODIC_ENA                   (0xFF)
+#define CSR_INT_PERIODIC_DIS                   (0x00) /* disable periodic int*/
+#define CSR_INT_PERIODIC_ENA                   (0xFF) /* 255*32 usec ~ 8 msec*/
 
 /* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
  * acknowledged (reset) by host writing "1" to flagged bits. */
index cc980d5d57c249bc6ea770361ab40e45b98953d3..6090bc15a6d536ab18c0219740c4a44740974835 100644 (file)
@@ -477,7 +477,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
                           (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
                           (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
 
-       iwl_write32(priv, CSR_INT_COALESCING, 0x40);
+       /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */
+       iwl_write8(priv, CSR_INT_COALESCING, 0x40);
 
        return 0;
 }