ezusb_read_ltv() is always invoked via the ->read_ltv() callback. This callback is mostly invoked under orinoco_lock() which disables BH. There are a few invocations during probe which occur in preemptible context via: ezusb_probe() -> orinoco_init() -> determine_fw_capabilities() Extend `hermes_ops' with the ->read_ltv_pr callback which is implemented with the same callback like ->read_ltv on `hermes_ops_local'. On `ezusb_ops' ->read_ltv is used for callbacks under the lock which need to poll. The new ->read_ltv_pr() is used in the preemptible context in which it is possible to wait for the completion. Provide HERMES_READ_RECORD_PR() and hermes_read_wordrec_pr() which behave like their non _pr equivalents and invoke ->read_ltv_pr(). This removes the last user of ezusb_req_ctx_wait() and can now be removed. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- .../net/wireless/intersil/orinoco/hermes.c | 1 + .../net/wireless/intersil/orinoco/hermes.h | 15 ++++++ drivers/net/wireless/intersil/orinoco/hw.c | 32 ++++++------ .../wireless/intersil/orinoco/orinoco_usb.c | 49 ++++++++----------- 4 files changed, 52 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/intersil/orinoco/hermes.c b/drivers/net/wireless/intersil/orinoco/hermes.c index 43790fbea0e00..6d4b7f64efcf5 100644 --- a/drivers/net/wireless/intersil/orinoco/hermes.c +++ b/drivers/net/wireless/intersil/orinoco/hermes.c @@ -763,6 +763,7 @@ static const struct hermes_ops hermes_ops_local = { .init_cmd_wait = hermes_doicmd_wait, .allocate = hermes_allocate, .read_ltv = hermes_read_ltv, + .read_ltv_pr = hermes_read_ltv, .write_ltv = hermes_write_ltv, .bap_pread = hermes_bap_pread, .bap_pwrite = hermes_bap_pwrite, diff --git a/drivers/net/wireless/intersil/orinoco/hermes.h b/drivers/net/wireless/intersil/orinoco/hermes.h index 9f668185b7d28..3dc561a5cb7ae 100644 --- a/drivers/net/wireless/intersil/orinoco/hermes.h +++ b/drivers/net/wireless/intersil/orinoco/hermes.h @@ -386,6 +386,8 @@ struct hermes_ops { int (*allocate)(struct hermes *hw, u16 size, u16 *fid); int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen, u16 *length, void *buf); + int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid, + unsigned buflen, u16 *length, void *buf); int (*write_ltv)(struct hermes *hw, int bap, u16 rid, u16 length, const void *value); int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len, @@ -494,6 +496,8 @@ static inline void hermes_clear_words(struct hermes *hw, int off, #define HERMES_READ_RECORD(hw, bap, rid, buf) \ (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) +#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \ + (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ (hw->ops->write_ltv((hw), (bap), (rid), \ HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf))) @@ -509,6 +513,17 @@ static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid, return err; } +static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid, + u16 *word) +{ + __le16 rec; + int err; + + err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec); + *word = le16_to_cpu(rec); + return err; +} + static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid, u16 word) { diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c index 61af5a28f269f..2c7adb4be1003 100644 --- a/drivers/net/wireless/intersil/orinoco/hw.c +++ b/drivers/net/wireless/intersil/orinoco/hw.c @@ -78,7 +78,7 @@ int determine_fw_capabilities(struct orinoco_private *priv, char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2))); /* Get the hardware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); + err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id); if (err) { dev_err(dev, "Cannot read hardware identity: error %d\n", err); @@ -101,7 +101,7 @@ int determine_fw_capabilities(struct orinoco_private *priv, priv->firmware_type = determine_firmware_type(&nic_id); /* Get the firmware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); + err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { dev_err(dev, "Cannot read station identity: error %d\n", err); @@ -177,7 +177,7 @@ int determine_fw_capabilities(struct orinoco_private *priv, /* 3Com MAC : 00:50:DA:* */ memset(tmp, 0, sizeof(tmp)); /* Get the Symbol firmware version */ - err = hw->ops->read_ltv(hw, USER_BAP, + err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_SECONDARYVERSION_SYMBOL, SYMBOL_MAX_VER_LEN, NULL, &tmp); if (err) { @@ -286,7 +286,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) u16 reclen; /* Get the MAC address */ - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev_addr); if (err) { dev_warn(dev, "Failed to read MAC address!\n"); @@ -296,7 +296,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) dev_dbg(dev, "MAC address %pM\n", dev_addr); /* Get the station name */ - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { dev_err(dev, "failed to read station name\n"); @@ -312,7 +312,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) dev_dbg(dev, "Station name \"%s\"\n", priv->nick); /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST, &priv->channel_mask); if (err) { dev_err(dev, "Failed to read channel list!\n"); @@ -320,13 +320,13 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) } /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &priv->ap_density); if (err || priv->ap_density < 1 || priv->ap_density > 3) priv->has_sensitivity = 0; /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, &priv->rts_thresh); if (err) { dev_err(dev, "Failed to read RTS threshold!\n"); @@ -335,11 +335,11 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) /* Get initial fragmentation settings */ if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFMWOROBUST_AGERE, &priv->mwo_robust); else - err = hermes_read_wordrec(hw, USER_BAP, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { @@ -351,7 +351,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) if (priv->has_pm) { priv->pm_on = 0; priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFMAXSLEEPDURATION, &priv->pm_period); if (err) { @@ -359,7 +359,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) "period!\n"); goto out; } - err = hermes_read_wordrec(hw, USER_BAP, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &priv->pm_timeout); if (err) { @@ -371,7 +371,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) /* Preamble setup */ if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, &priv->preamble); if (err) { @@ -381,21 +381,21 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) } /* Retry settings */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, &priv->short_retry_limit); if (err) { dev_err(dev, "Failed to read short retry limit\n"); goto out; } - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, &priv->long_retry_limit); if (err) { dev_err(dev, "Failed to read long retry limit\n"); goto out; } - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, &priv->retry_lifetime); if (err) { dev_err(dev, "Failed to read max retry lifetime\n"); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 4c60b48214637..dd31929261ab9 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -667,32 +667,6 @@ static void ezusb_request_in_callback(struct ezusb_priv *upriv, typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *); -static void ezusb_req_ctx_wait(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - switch (ctx->state) { - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_REQ_COMPLETE: - case EZUSB_CTX_RESP_RECEIVED: - if (in_softirq()) { - /* If we get called from a timer, timeout timers don't - * get the chance to run themselves. So we make sure - * that we don't sleep for ever */ - int msecs = DEF_TIMEOUT * (1000 / HZ); - - while (!try_wait_for_completion(&ctx->done) && msecs--) - udelay(1000); - } else { - wait_for_completion(&ctx->done); - } - break; - default: - /* Done or failed - nothing to wait for */ - break; - } -} - static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv, struct request_context *ctx) { @@ -1032,8 +1006,10 @@ static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid, ezusb_req_ctx_wait_poll); } -static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) +static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, + unsigned bufsize, u16 *length, void *buf, + ezusb_ctx_wait ezusb_ctx_wait_func) + { struct ezusb_priv *upriv = hw->priv; struct request_context *ctx; @@ -1046,7 +1022,21 @@ static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, return -ENOMEM; return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL, - buf, bufsize, length, ezusb_req_ctx_wait); + buf, bufsize, length, ezusb_req_ctx_wait_poll); +} + +static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, + unsigned bufsize, u16 *length, void *buf) +{ + return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, + ezusb_req_ctx_wait_poll); +} + +static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid, + unsigned bufsize, u16 *length, void *buf) +{ + return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, + ezusb_req_ctx_wait_compl); } static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1, @@ -1586,6 +1576,7 @@ static const struct hermes_ops ezusb_ops = { .init_cmd_wait = ezusb_doicmd_wait, .allocate = ezusb_allocate, .read_ltv = ezusb_read_ltv, + .read_ltv_pr = ezusb_read_ltv_preempt, .write_ltv = ezusb_write_ltv, .bap_pread = ezusb_bap_pread, .read_pda = ezusb_read_pda, -- 2.29.2