Changes since v1:
- Keep the hwrng name as "amd"
LABBE Corentin (5):
hwrng: amd: Fix style problem with blank line
hwrng: amd: use the BIT macro
hwrng: amd: Be consitent with the driver name
hwrng: amd: Remove asm/io.h
hwrng: amd: Rework of the amd768-hwrng driver
drivers/char/hw_random/amd-rng.c | 173 ++++++++++++++++++++++++---------------
1 file changed, 107 insertions(+), 66 deletions(-)
--
2.7.3
The driver name is displayed each time differently.
This patch make use of the same name everywhere.
Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/char/hw_random/amd-rng.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index d0042f5..93157af 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -31,7 +31,7 @@
#include <linux/delay.h>
#include <asm/io.h>
-#define PFX KBUILD_MODNAME ": "
+#define DRV_NAME "AMD768-HWRNG"
/*
* Data for PCI driver interface
@@ -128,8 +128,8 @@ found:
pmbase &= 0x0000FF00;
if (pmbase == 0)
goto out;
- if (!request_region(pmbase + 0xF0, 8, "AMD HWRNG")) {
- dev_err(&pdev->dev, "AMD HWRNG region 0x%x already in use!\n",
+ if (!request_region(pmbase + 0xF0, 8, DRV_NAME)) {
+ dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
pmbase + 0xF0);
err = -EBUSY;
goto out;
@@ -137,11 +137,10 @@ found:
amd_rng.priv = (unsigned long)pmbase;
amd_pdev = pdev;
- pr_info("AMD768 RNG detected\n");
+ pr_info(DRV_NAME " detected\n");
err = hwrng_register(&amd_rng);
if (err) {
- pr_err(PFX "RNG registering failed (%d)\n",
- err);
+ pr_err(DRV_NAME " registering failed (%d)\n", err);
release_region(pmbase + 0xF0, 8);
goto out;
}
--
2.7.3
This patch add usage of the BIT() macro
Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/char/hw_random/amd-rng.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 45b7965..d0042f5 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -78,11 +78,11 @@ static int amd_rng_init(struct hwrng *rng)
u8 rnen;
pci_read_config_byte(amd_pdev, 0x40, &rnen);
- rnen |= (1 << 7); /* RNG on */
+ rnen |= BIT(7); /* RNG on */
pci_write_config_byte(amd_pdev, 0x40, rnen);
pci_read_config_byte(amd_pdev, 0x41, &rnen);
- rnen |= (1 << 7); /* PMIO enable */
+ rnen |= BIT(7); /* PMIO enable */
pci_write_config_byte(amd_pdev, 0x41, rnen);
return 0;
@@ -93,7 +93,7 @@ static void amd_rng_cleanup(struct hwrng *rng)
u8 rnen;
pci_read_config_byte(amd_pdev, 0x40, &rnen);
- rnen &= ~(1 << 7); /* RNG off */
+ rnen &= ~BIT(7); /* RNG off */
pci_write_config_byte(amd_pdev, 0x40, rnen);
}
--
2.7.3
checkpatch complains about <asm/io.h> used instead of linux/io.h.
In fact it is not needed.
This patch remove it, and in the process, alphabetize the other headers.
Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/char/hw_random/amd-rng.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 93157af..de82fe3 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -24,12 +24,11 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/hw_random.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/hw_random.h>
-#include <linux/delay.h>
-#include <asm/io.h>
#define DRV_NAME "AMD768-HWRNG"
--
2.7.3
This patch convert the hwrng interface used by amd768-rng to its new API
by replacing data_read()/data_present() by read().
Furthermore, Instead of having two global variable, it's better to use a
private struct. This will permit to remove amd_pdev variable.
Finally, Instead of accessing hw directly via pmbase, it's better to
access after ioport_map() via ioread32/iowrite32.
Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/char/hw_random/amd-rng.c | 151 +++++++++++++++++++++++++--------------
1 file changed, 99 insertions(+), 52 deletions(-)
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index de82fe3..785bc3e 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -32,6 +32,14 @@
#define DRV_NAME "AMD768-HWRNG"
+#define GEN_CFG_REG1 0x40
+#define GEN_CFG_REG2 0x41
+#define SMIO_SPACEPTR 0x58
+#define RNGDATA 0x00
+#define RNGDONE 0x04
+#define PMBASE_OFFSET 0xF0
+#define PMBASE_SIZE 8
+
/*
* Data for PCI driver interface
*
@@ -39,6 +47,7 @@
* PCI ids via MODULE_DEVICE_TABLE. We do not actually
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
+ * Like i2c-amd756
*/
static const struct pci_device_id pci_tbl[] = {
{ PCI_VDEVICE(AMD, 0x7443), 0, },
@@ -47,112 +56,150 @@ static const struct pci_device_id pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
-static struct pci_dev *amd_pdev;
+struct amd768_priv {
+ void __iomem *iobase;
+ struct pci_dev *pcidev;
+ u32 pmbase;
+};
-static int amd_rng_data_present(struct hwrng *rng, int wait)
+static int amd_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
- u32 pmbase = (u32)rng->priv;
- int data, i;
-
- for (i = 0; i < 20; i++) {
- data = !!(inl(pmbase + 0xF4) & 1);
- if (data || !wait)
- break;
- udelay(10);
+ u32 *data = buf;
+ struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
+ size_t read = 0;
+ /* We will wait at maximum one time per read */
+ int timeout = max / 4 + 1;
+
+ /*
+ * RNG data is available when RNGDONE is set to 1
+ * New random numbers are generated approximately 128 microseconds
+ * after RNGDATA is read
+ */
+ while (read < max) {
+ if (ioread32(priv->iobase + RNGDONE) == 0) {
+ if (wait) {
+ /* Delay given by datasheet */
+ usleep_range(128, 196);
+ if (timeout-- == 0)
+ return read;
+ } else {
+ return 0;
+ }
+ } else {
+ *data = ioread32(priv->iobase + RNGDATA);
+ data++;
+ read += 4;
+ }
}
- return data;
-}
-
-static int amd_rng_data_read(struct hwrng *rng, u32 *data)
-{
- u32 pmbase = (u32)rng->priv;
- *data = inl(pmbase + 0xF0);
-
- return 4;
+ return read;
}
static int amd_rng_init(struct hwrng *rng)
{
u8 rnen;
+ struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
- pci_read_config_byte(amd_pdev, 0x40, &rnen);
+ pci_read_config_byte(priv->pcidev, GEN_CFG_REG1, &rnen);
rnen |= BIT(7); /* RNG on */
- pci_write_config_byte(amd_pdev, 0x40, rnen);
+ pci_write_config_byte(priv->pcidev, GEN_CFG_REG1, rnen);
- pci_read_config_byte(amd_pdev, 0x41, &rnen);
+ pci_read_config_byte(priv->pcidev, GEN_CFG_REG2, &rnen);
rnen |= BIT(7); /* PMIO enable */
- pci_write_config_byte(amd_pdev, 0x41, rnen);
-
+ pci_write_config_byte(priv->pcidev, GEN_CFG_REG2, rnen);
return 0;
}
static void amd_rng_cleanup(struct hwrng *rng)
{
u8 rnen;
+ struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
- pci_read_config_byte(amd_pdev, 0x40, &rnen);
+ pci_read_config_byte(priv->pcidev, GEN_CFG_REG1, &rnen);
rnen &= ~BIT(7); /* RNG off */
- pci_write_config_byte(amd_pdev, 0x40, rnen);
+ pci_write_config_byte(priv->pcidev, GEN_CFG_REG1, rnen);
}
static struct hwrng amd_rng = {
.name = "amd",
+ .read = amd_rng_read,
.init = amd_rng_init,
.cleanup = amd_rng_cleanup,
- .data_present = amd_rng_data_present,
- .data_read = amd_rng_data_read,
};
-static int __init mod_init(void)
+static int mod_init(void)
{
- int err = -ENODEV;
+ int err;
struct pci_dev *pdev = NULL;
const struct pci_device_id *ent;
u32 pmbase;
+ struct amd768_priv *priv;
for_each_pci_dev(pdev) {
ent = pci_match_id(pci_tbl, pdev);
if (ent)
goto found;
}
- /* Device not found. */
- goto out;
-
+ return -ENODEV;
found:
- err = pci_read_config_dword(pdev, 0x58, &pmbase);
+
+ err = pci_read_config_dword(pdev, SMIO_SPACEPTR, &pmbase);
if (err)
- goto out;
- err = -EIO;
+ return err;
+
pmbase &= 0x0000FF00;
- if (pmbase == 0)
- goto out;
- if (!request_region(pmbase + 0xF0, 8, DRV_NAME)) {
- dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
- pmbase + 0xF0);
- err = -EBUSY;
- goto out;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (!request_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE, DRV_NAME)) {
+ pr_err(DRV_NAME "region 0x%x already in use!\n", pmbase);
+ goto err_pmbase;
+ }
+
+ priv->iobase = ioport_map(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+ if (!priv->iobase) {
+ pr_err(DRV_NAME "Cannot map ioport\n");
+ err = -EINVAL;
+ goto err_iomap;
}
- amd_rng.priv = (unsigned long)pmbase;
- amd_pdev = pdev;
+
+ amd_rng.priv = (unsigned long)priv;
+ priv->pmbase = pmbase;
+ priv->pcidev = pdev;
pr_info(DRV_NAME " detected\n");
+
err = hwrng_register(&amd_rng);
if (err) {
- pr_err(DRV_NAME " registering failed (%d)\n", err);
- release_region(pmbase + 0xF0, 8);
- goto out;
+ pr_err(DRV_NAME "Cannot register HWRNG %d\n", err);
+ goto err_hwrng;
}
-out:
+ return 0;
+
+err_hwrng:
+ ioport_unmap(priv->iobase);
+err_iomap:
+ release_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+err_pmbase:
+ kfree(priv);
return err;
}
-static void __exit mod_exit(void)
+static void mod_exit(void)
{
- u32 pmbase = (unsigned long)amd_rng.priv;
+ struct amd768_priv *priv;
+
+ priv = (struct amd768_priv *)amd_rng.priv;
- release_region(pmbase + 0xF0, 8);
hwrng_unregister(&amd_rng);
+
+ ioport_unmap(priv->iobase);
+
+ release_region(priv->pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+
+ kfree(priv);
}
module_init(mod_init);
--
2.7.3
Some blank line are unncessary, and one is missing after declaration.
This patch fix thoses style problems.
Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/char/hw_random/amd-rng.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 48f6a83..45b7965 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -31,10 +31,8 @@
#include <linux/delay.h>
#include <asm/io.h>
-
#define PFX KBUILD_MODNAME ": "
-
/*
* Data for PCI driver interface
*
@@ -52,7 +50,6 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct pci_dev *amd_pdev;
-
static int amd_rng_data_present(struct hwrng *rng, int wait)
{
u32 pmbase = (u32)rng->priv;
@@ -100,7 +97,6 @@ static void amd_rng_cleanup(struct hwrng *rng)
pci_write_config_byte(amd_pdev, 0x40, rnen);
}
-
static struct hwrng amd_rng = {
.name = "amd",
.init = amd_rng_init,
@@ -109,7 +105,6 @@ static struct hwrng amd_rng = {
.data_read = amd_rng_data_read,
};
-
static int __init mod_init(void)
{
int err = -ENODEV;
@@ -157,6 +152,7 @@ out:
static void __exit mod_exit(void)
{
u32 pmbase = (unsigned long)amd_rng.priv;
+
release_region(pmbase + 0xF0, 8);
hwrng_unregister(&amd_rng);
}
--
2.7.3
Hi Corentin,
On Thu, Aug 25, 2016 at 02:16:35PM +0200, LABBE Corentin wrote:
> This patch convert the hwrng interface used by amd768-rng to its new API
> by replacing data_read()/data_present() by read().
>
> Furthermore, Instead of having two global variable, it's better to use a
> private struct. This will permit to remove amd_pdev variable.
>
> Finally, Instead of accessing hw directly via pmbase, it's better to
> access after ioport_map() via ioread32/iowrite32.
I was going to recommend a better $subject line, but now I see why it's
vague. :( I would recommend breaking this patch up into three:
hwrng: amd - Access hardware via ioread32/iowrite32
hwrng: amd - Replace global variable with private struct
hwrng: amd - Convert to new hwrng read() API
thx,
Jason.
On Thu, Aug 25, 2016 at 02:56:38PM +0000, Jason Cooper wrote:
> Hi Corentin,
>
> On Thu, Aug 25, 2016 at 02:16:35PM +0200, LABBE Corentin wrote:
> > This patch convert the hwrng interface used by amd768-rng to its new API
> > by replacing data_read()/data_present() by read().
> >
> > Furthermore, Instead of having two global variable, it's better to use a
> > private struct. This will permit to remove amd_pdev variable.
> >
> > Finally, Instead of accessing hw directly via pmbase, it's better to
> > access after ioport_map() via ioread32/iowrite32.
>
> I was going to recommend a better $subject line, but now I see why it's
> vague. :( I would recommend breaking this patch up into three:
>
> hwrng: amd - Access hardware via ioread32/iowrite32
> hwrng: amd - Replace global variable with private struct
> hwrng: amd - Convert to new hwrng read() API
>
That was my first idea, but believed that it wasnt worth it.
Anyway I will do it.
Regards
LABBE Corentin
Hi Corentin,
On Fri, Aug 26, 2016 at 10:38:02AM +0200, LABBE Corentin wrote:
> On Thu, Aug 25, 2016 at 02:56:38PM +0000, Jason Cooper wrote:
> > On Thu, Aug 25, 2016 at 02:16:35PM +0200, LABBE Corentin wrote:
> > > This patch convert the hwrng interface used by amd768-rng to its new API
> > > by replacing data_read()/data_present() by read().
> > >
> > > Furthermore, Instead of having two global variable, it's better to use a
> > > private struct. This will permit to remove amd_pdev variable.
> > >
> > > Finally, Instead of accessing hw directly via pmbase, it's better to
> > > access after ioport_map() via ioread32/iowrite32.
> >
> > I was going to recommend a better $subject line, but now I see why it's
> > vague. :( I would recommend breaking this patch up into three:
> >
> > hwrng: amd - Access hardware via ioread32/iowrite32
> > hwrng: amd - Replace global variable with private struct
> > hwrng: amd - Convert to new hwrng read() API
> >
>
> That was my first idea, but believed that it wasnt worth it.
When working with crypto/rng code, I'm a firm believer in moving
cautiously and deliberately. :-)
> Anyway I will do it.
Thanks!
thx,
Jason.