diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2011-08-15 14:09:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-24 14:41:42 -0400 |
commit | 00044f17afd36bf6397b9a2a12f242a057449e9a (patch) | |
tree | 5b216a3fa13357b352bebd28272e0698380a2b54 /drivers/net/wireless/ath/carl9170/main.c | |
parent | acf1771221f2877ab5d36487930cd6a2ecaa73e6 (diff) |
carl9170: export HW random number generator
All AR9170 hardware have a 16-Bit random number generator.
The documentation claims the values are suitable for
"security keys".
The "throughput" is around 320Kibit/s. It's slow, but it
does work without introducing any special offload
firmware commands.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/carl9170/main.c')
-rw-r--r-- | drivers/net/wireless/ath/carl9170/main.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 85cb1bdebaaa..782b8f3ae58f 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -1468,6 +1468,109 @@ static int carl9170_register_wps_button(struct ar9170 *ar) | |||
1468 | } | 1468 | } |
1469 | #endif /* CONFIG_CARL9170_WPC */ | 1469 | #endif /* CONFIG_CARL9170_WPC */ |
1470 | 1470 | ||
1471 | #ifdef CONFIG_CARL9170_HWRNG | ||
1472 | static int carl9170_rng_get(struct ar9170 *ar) | ||
1473 | { | ||
1474 | |||
1475 | #define RW (CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32)) | ||
1476 | #define RB (CARL9170_MAX_CMD_PAYLOAD_LEN) | ||
1477 | |||
1478 | static const __le32 rng_load[RW] = { | ||
1479 | [0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)}; | ||
1480 | |||
1481 | u32 buf[RW]; | ||
1482 | |||
1483 | unsigned int i, off = 0, transfer, count; | ||
1484 | int err; | ||
1485 | |||
1486 | BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN); | ||
1487 | |||
1488 | if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized) | ||
1489 | return -EAGAIN; | ||
1490 | |||
1491 | count = ARRAY_SIZE(ar->rng.cache); | ||
1492 | while (count) { | ||
1493 | err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG, | ||
1494 | RB, (u8 *) rng_load, | ||
1495 | RB, (u8 *) buf); | ||
1496 | if (err) | ||
1497 | return err; | ||
1498 | |||
1499 | transfer = min_t(unsigned int, count, RW); | ||
1500 | for (i = 0; i < transfer; i++) | ||
1501 | ar->rng.cache[off + i] = buf[i]; | ||
1502 | |||
1503 | off += transfer; | ||
1504 | count -= transfer; | ||
1505 | } | ||
1506 | |||
1507 | ar->rng.cache_idx = 0; | ||
1508 | |||
1509 | #undef RW | ||
1510 | #undef RB | ||
1511 | return 0; | ||
1512 | } | ||
1513 | |||
1514 | static int carl9170_rng_read(struct hwrng *rng, u32 *data) | ||
1515 | { | ||
1516 | struct ar9170 *ar = (struct ar9170 *)rng->priv; | ||
1517 | int ret = -EIO; | ||
1518 | |||
1519 | mutex_lock(&ar->mutex); | ||
1520 | if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) { | ||
1521 | ret = carl9170_rng_get(ar); | ||
1522 | if (ret) { | ||
1523 | mutex_unlock(&ar->mutex); | ||
1524 | return ret; | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1528 | *data = ar->rng.cache[ar->rng.cache_idx++]; | ||
1529 | mutex_unlock(&ar->mutex); | ||
1530 | |||
1531 | return sizeof(u16); | ||
1532 | } | ||
1533 | |||
1534 | static void carl9170_unregister_hwrng(struct ar9170 *ar) | ||
1535 | { | ||
1536 | if (ar->rng.initialized) { | ||
1537 | hwrng_unregister(&ar->rng.rng); | ||
1538 | ar->rng.initialized = false; | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1542 | static int carl9170_register_hwrng(struct ar9170 *ar) | ||
1543 | { | ||
1544 | int err; | ||
1545 | |||
1546 | snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name), | ||
1547 | "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy)); | ||
1548 | ar->rng.rng.name = ar->rng.name; | ||
1549 | ar->rng.rng.data_read = carl9170_rng_read; | ||
1550 | ar->rng.rng.priv = (unsigned long)ar; | ||
1551 | |||
1552 | if (WARN_ON(ar->rng.initialized)) | ||
1553 | return -EALREADY; | ||
1554 | |||
1555 | err = hwrng_register(&ar->rng.rng); | ||
1556 | if (err) { | ||
1557 | dev_err(&ar->udev->dev, "Failed to register the random " | ||
1558 | "number generator (%d)\n", err); | ||
1559 | return err; | ||
1560 | } | ||
1561 | |||
1562 | ar->rng.initialized = true; | ||
1563 | |||
1564 | err = carl9170_rng_get(ar); | ||
1565 | if (err) { | ||
1566 | carl9170_unregister_hwrng(ar); | ||
1567 | return err; | ||
1568 | } | ||
1569 | |||
1570 | return 0; | ||
1571 | } | ||
1572 | #endif /* CONFIG_CARL9170_HWRNG */ | ||
1573 | |||
1471 | static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, | 1574 | static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, |
1472 | struct survey_info *survey) | 1575 | struct survey_info *survey) |
1473 | { | 1576 | { |
@@ -1878,6 +1981,12 @@ int carl9170_register(struct ar9170 *ar) | |||
1878 | goto err_unreg; | 1981 | goto err_unreg; |
1879 | #endif /* CONFIG_CARL9170_WPC */ | 1982 | #endif /* CONFIG_CARL9170_WPC */ |
1880 | 1983 | ||
1984 | #ifdef CONFIG_CARL9170_HWRNG | ||
1985 | err = carl9170_register_hwrng(ar); | ||
1986 | if (err) | ||
1987 | goto err_unreg; | ||
1988 | #endif /* CONFIG_CARL9170_HWRNG */ | ||
1989 | |||
1881 | dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n", | 1990 | dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n", |
1882 | wiphy_name(ar->hw->wiphy)); | 1991 | wiphy_name(ar->hw->wiphy)); |
1883 | 1992 | ||
@@ -1910,6 +2019,10 @@ void carl9170_unregister(struct ar9170 *ar) | |||
1910 | } | 2019 | } |
1911 | #endif /* CONFIG_CARL9170_WPC */ | 2020 | #endif /* CONFIG_CARL9170_WPC */ |
1912 | 2021 | ||
2022 | #ifdef CONFIG_CARL9170_HWRNG | ||
2023 | carl9170_unregister_hwrng(ar); | ||
2024 | #endif /* CONFIG_CARL9170_HWRNG */ | ||
2025 | |||
1913 | carl9170_cancel_worker(ar); | 2026 | carl9170_cancel_worker(ar); |
1914 | cancel_work_sync(&ar->restart_work); | 2027 | cancel_work_sync(&ar->restart_work); |
1915 | 2028 | ||