int wsm_release_tx_buffer(struct cw1200_common *priv, int count)
{ int ret = 0; int hw_bufs_used = priv->hw_bufs_used;
priv->hw_bufs_used -= count; if (WARN_ON(priv->hw_bufs_used < 0))
ret = -1; elseif (hw_bufs_used >= priv->wsm_caps.input_buffers)
ret = 1; if (!priv->hw_bufs_used)
wake_up(&priv->bh_evt_wq); return ret;
}
staticint cw1200_bh_read_ctrl_reg(struct cw1200_common *priv,
u16 *ctrl_reg)
{ int ret;
ret = cw1200_reg_read_16(priv,
ST90TDS_CONTROL_REG_ID, ctrl_reg); if (ret) {
ret = cw1200_reg_read_16(priv,
ST90TDS_CONTROL_REG_ID, ctrl_reg); if (ret)
pr_err("[BH] Failed to read control register.\n");
}
return ret;
}
staticint cw1200_device_wakeup(struct cw1200_common *priv)
{
u16 ctrl_reg; int ret;
pr_debug("[BH] Device wakeup.\n");
/* First, set the dpll register */
ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID,
cw1200_dpll_from_clk(priv->hw_refclk)); if (WARN_ON(ret)) return ret;
/* To force the device to be always-on, the host sets WLAN_UP to 1 */
ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID,
ST90TDS_CONT_WUP_BIT); if (WARN_ON(ret)) return ret;
ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg); if (WARN_ON(ret)) return ret;
/* If the device returns WLAN_RDY as 1, the device is active and will * remain active.
*/ if (ctrl_reg & ST90TDS_CONT_RDY_BIT) {
pr_debug("[BH] Device awake.\n"); return 1;
}
return 0;
}
/* Must be called from BH thraed. */ void cw1200_enable_powersave(struct cw1200_common *priv, bool enable)
{
pr_debug("[BH] Powerave is %s.\n",
enable ? "enabled" : "disabled");
priv->powersave_enabled = enable;
}
/* Did an error occur? */ if ((status < 0 && status != -ERESTARTSYS) ||
term || priv->bh_error) { break;
} if (!status) { /* wait_event timed out */ unsignedlong timestamp = jiffies; long timeout; int pending = 0; int i;
/* Check to see if we have any outstanding frames */ if (priv->hw_bufs_used && (!rx || !tx)) {
wiphy_warn(priv->hw->wiphy, "Missed interrupt? (%d frames outstanding)\n",
priv->hw_bufs_used);
rx = 1;
/* Get a timestamp of "oldest" frame */ for (i = 0; i < 4; ++i)
pending += cw1200_queue_get_xmit_timestamp(
&priv->tx_queue[i],
×tamp,
priv->pending_frame_id);
/* Check if frame transmission is timed out. * Add an extra second with respect to possible * interrupt loss.
*/
timeout = timestamp +
WSM_CMD_LAST_CHANCE_TIMEOUT +
1 * HZ -
jiffies;
/* And terminate BH thread if the frame is "stuck" */ if (pending && timeout < 0) {
wiphy_warn(priv->hw->wiphy, "Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n",
priv->hw_bufs_used, pending,
timestamp, jiffies); break;
}
} elseif (!priv->device_can_sleep &&
!atomic_read(&priv->recent_scan)) {
pr_debug("[BH] Device wakedown. Timeout.\n");
cw1200_reg_write_16(priv,
ST90TDS_CONTROL_REG_ID, 0);
priv->device_can_sleep = true;
} goto done;
} elseif (suspend) {
pr_debug("[BH] Device suspend.\n"); if (priv->powersave_enabled) {
pr_debug("[BH] Device wakedown. Suspend.\n");
cw1200_reg_write_16(priv,
ST90TDS_CONTROL_REG_ID, 0);
priv->device_can_sleep = true;
}
atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED);
wake_up(&priv->bh_evt_wq);
status = wait_event_interruptible(priv->bh_wq,
CW1200_BH_RESUME == atomic_read(&priv->bh_suspend)); if (status < 0) {
wiphy_err(priv->hw->wiphy, "Failed to wait for resume: %ld.\n",
status); break;
}
pr_debug("[BH] Device resume.\n");
atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
wake_up(&priv->bh_evt_wq);
atomic_inc(&priv->bh_rx); goto done;
}
rx:
tx += pending_tx;
pending_tx = 0;
if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) break;
/* Don't bother trying to rx unless we have data to read */ if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); if (ret < 0) break; /* Double up here if there's more data.. */ if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); if (ret < 0) break;
}
}
if (!tx_allowed) { /* Buffers full. Ensure we process tx * after we handle rx..
*/
pending_tx = tx; goto done_rx;
}
ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst); if (ret < 0) break; if (ret > 0) /* More to transmit */
tx = ret;
/* Re-read ctrl reg */ if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) break;
}
done_rx: if (priv->bh_error) break; if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) goto rx; if (tx) goto tx;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.