|
@@ -1468,6 +1468,109 @@ static int carl9170_register_wps_button(struct ar9170 *ar)
|
|
|
}
|
|
|
#endif /* CONFIG_CARL9170_WPC */
|
|
|
|
|
|
+#ifdef CONFIG_CARL9170_HWRNG
|
|
|
+static int carl9170_rng_get(struct ar9170 *ar)
|
|
|
+{
|
|
|
+
|
|
|
+#define RW (CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32))
|
|
|
+#define RB (CARL9170_MAX_CMD_PAYLOAD_LEN)
|
|
|
+
|
|
|
+ static const __le32 rng_load[RW] = {
|
|
|
+ [0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)};
|
|
|
+
|
|
|
+ u32 buf[RW];
|
|
|
+
|
|
|
+ unsigned int i, off = 0, transfer, count;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN);
|
|
|
+
|
|
|
+ if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized)
|
|
|
+ return -EAGAIN;
|
|
|
+
|
|
|
+ count = ARRAY_SIZE(ar->rng.cache);
|
|
|
+ while (count) {
|
|
|
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
|
|
|
+ RB, (u8 *) rng_load,
|
|
|
+ RB, (u8 *) buf);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ transfer = min_t(unsigned int, count, RW);
|
|
|
+ for (i = 0; i < transfer; i++)
|
|
|
+ ar->rng.cache[off + i] = buf[i];
|
|
|
+
|
|
|
+ off += transfer;
|
|
|
+ count -= transfer;
|
|
|
+ }
|
|
|
+
|
|
|
+ ar->rng.cache_idx = 0;
|
|
|
+
|
|
|
+#undef RW
|
|
|
+#undef RB
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int carl9170_rng_read(struct hwrng *rng, u32 *data)
|
|
|
+{
|
|
|
+ struct ar9170 *ar = (struct ar9170 *)rng->priv;
|
|
|
+ int ret = -EIO;
|
|
|
+
|
|
|
+ mutex_lock(&ar->mutex);
|
|
|
+ if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) {
|
|
|
+ ret = carl9170_rng_get(ar);
|
|
|
+ if (ret) {
|
|
|
+ mutex_unlock(&ar->mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ *data = ar->rng.cache[ar->rng.cache_idx++];
|
|
|
+ mutex_unlock(&ar->mutex);
|
|
|
+
|
|
|
+ return sizeof(u16);
|
|
|
+}
|
|
|
+
|
|
|
+static void carl9170_unregister_hwrng(struct ar9170 *ar)
|
|
|
+{
|
|
|
+ if (ar->rng.initialized) {
|
|
|
+ hwrng_unregister(&ar->rng.rng);
|
|
|
+ ar->rng.initialized = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int carl9170_register_hwrng(struct ar9170 *ar)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name),
|
|
|
+ "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy));
|
|
|
+ ar->rng.rng.name = ar->rng.name;
|
|
|
+ ar->rng.rng.data_read = carl9170_rng_read;
|
|
|
+ ar->rng.rng.priv = (unsigned long)ar;
|
|
|
+
|
|
|
+ if (WARN_ON(ar->rng.initialized))
|
|
|
+ return -EALREADY;
|
|
|
+
|
|
|
+ err = hwrng_register(&ar->rng.rng);
|
|
|
+ if (err) {
|
|
|
+ dev_err(&ar->udev->dev, "Failed to register the random "
|
|
|
+ "number generator (%d)\n", err);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ ar->rng.initialized = true;
|
|
|
+
|
|
|
+ err = carl9170_rng_get(ar);
|
|
|
+ if (err) {
|
|
|
+ carl9170_unregister_hwrng(ar);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif /* CONFIG_CARL9170_HWRNG */
|
|
|
+
|
|
|
static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
|
|
|
struct survey_info *survey)
|
|
|
{
|
|
@@ -1878,6 +1981,12 @@ int carl9170_register(struct ar9170 *ar)
|
|
|
goto err_unreg;
|
|
|
#endif /* CONFIG_CARL9170_WPC */
|
|
|
|
|
|
+#ifdef CONFIG_CARL9170_HWRNG
|
|
|
+ err = carl9170_register_hwrng(ar);
|
|
|
+ if (err)
|
|
|
+ goto err_unreg;
|
|
|
+#endif /* CONFIG_CARL9170_HWRNG */
|
|
|
+
|
|
|
dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n",
|
|
|
wiphy_name(ar->hw->wiphy));
|
|
|
|
|
@@ -1910,6 +2019,10 @@ void carl9170_unregister(struct ar9170 *ar)
|
|
|
}
|
|
|
#endif /* CONFIG_CARL9170_WPC */
|
|
|
|
|
|
+#ifdef CONFIG_CARL9170_HWRNG
|
|
|
+ carl9170_unregister_hwrng(ar);
|
|
|
+#endif /* CONFIG_CARL9170_HWRNG */
|
|
|
+
|
|
|
carl9170_cancel_worker(ar);
|
|
|
cancel_work_sync(&ar->restart_work);
|
|
|
|