Skip to content

Commit

Permalink
ath9k_htc: Implement multiple register write support
Browse files Browse the repository at this point in the history
This patch adds support for writing multiple registers
in a single USB command.

Specific calls from the HW code that performs multiple
register writes would be modified to make use of this
in subsequent patches.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Sujith authored and John W. Linville committed Apr 16, 2010
1 parent 50f5631 commit 4a22fe1
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 4 deletions.
104 changes: 100 additions & 4 deletions drivers/net/wireless/ath/ath9k/htc_drv_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
ath9k_hw_regulatory(priv->ah));
}

static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
Expand All @@ -235,7 +235,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
return be32_to_cpu(val);
}

static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
Expand All @@ -257,9 +257,105 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
}
}

static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
u32 rsp_status;
int r;

mutex_lock(&priv->wmi->multi_write_mutex);

/* Store the register/value */
priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
cpu_to_be32(reg_offset);
priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
cpu_to_be32(val);

priv->wmi->multi_write_idx++;

/* If the buffer is full, send it out. */
if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
(u8 *) &priv->wmi->multi_write,
sizeof(struct register_write) * priv->wmi->multi_write_idx,
(u8 *) &rsp_status, sizeof(rsp_status),
100);
if (unlikely(r)) {
ath_print(common, ATH_DBG_WMI,
"REGISTER WRITE FAILED, multi len: %d\n",
priv->wmi->multi_write_idx);
}
priv->wmi->multi_write_idx = 0;
}

mutex_unlock(&priv->wmi->multi_write_mutex);
}

static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;

if (atomic_read(&priv->wmi->mwrite_cnt))
ath9k_regwrite_buffer(hw_priv, val, reg_offset);
else
ath9k_regwrite_single(hw_priv, val, reg_offset);
}

static void ath9k_enable_regwrite_buffer(void *hw_priv)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;

atomic_inc(&priv->wmi->mwrite_cnt);
}

static void ath9k_disable_regwrite_buffer(void *hw_priv)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;

atomic_dec(&priv->wmi->mwrite_cnt);
}

static void ath9k_regwrite_flush(void *hw_priv)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
u32 rsp_status;
int r;

mutex_lock(&priv->wmi->multi_write_mutex);

if (priv->wmi->multi_write_idx) {
r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
(u8 *) &priv->wmi->multi_write,
sizeof(struct register_write) * priv->wmi->multi_write_idx,
(u8 *) &rsp_status, sizeof(rsp_status),
100);
if (unlikely(r)) {
ath_print(common, ATH_DBG_WMI,
"REGISTER WRITE FAILED, multi len: %d\n",
priv->wmi->multi_write_idx);
}
priv->wmi->multi_write_idx = 0;
}

mutex_unlock(&priv->wmi->multi_write_mutex);
}

static const struct ath_ops ath9k_common_ops = {
.read = ath9k_ioread32,
.write = ath9k_iowrite32,
.read = ath9k_regread,
.write = ath9k_regwrite,
.enable_write_buffer = ath9k_enable_regwrite_buffer,
.disable_write_buffer = ath9k_disable_regwrite_buffer,
.write_flush = ath9k_regwrite_flush,
};

static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath9k/wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
wmi->drv_priv = priv;
wmi->stopped = false;
mutex_init(&wmi->op_mutex);
mutex_init(&wmi->multi_write_mutex);
init_completion(&wmi->cmd_wait);

return wmi;
Expand Down
12 changes: 12 additions & 0 deletions drivers/net/wireless/ath/ath9k/wmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ enum wmi_event_id {
WMI_TXRATE_EVENTID,
};

#define MAX_CMD_NUMBER 62

struct register_write {
u32 reg;
u32 val;
};

struct wmi {
struct ath9k_htc_priv *drv_priv;
struct htc_target *htc;
Expand All @@ -97,6 +104,11 @@ struct wmi {

struct sk_buff *wmi_skb;
spinlock_t wmi_lock;

atomic_t mwrite_cnt;
struct register_write multi_write[MAX_CMD_NUMBER];
u32 multi_write_idx;
struct mutex multi_write_mutex;
};

struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
Expand Down

0 comments on commit 4a22fe1

Please sign in to comment.