AMD Geode GX/LX support
PATCH 6/7 AMD Geode GX/LX support
This patch adds support for the hardware RNG device on the Geode LX processor. As a side note, the LX processor also includes a hardware AES encryption engine, support for which is not included here because I'm not one to increase the kernel source size if it doesn't need to be. If the list believes that this support is interesting to the mainstream kernel, I will push that up as well. Please apply against linux-2.6.13-rc2-mm2.
Signed off by: Jordan Crouse ([email protected])
drivers/char/hw_random.c +73 -1
@@ -1,4 +1,9 @@/* +Added support for the AMD Geode LX RNG +(c) Copyright 2004-2005 Advanced Micro Devices, Inc. + +derived from +Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) (c) Copyright 2003 Red Hat Inc <[email protected]>
@@ -95,6 +100,13 @@ static unsigned int via_data_present (vostatic u32 via_data_read (void );#endif +#ifdef CONFIG_MGEODE_LX +static int __init geode_init (struct pci_dev *dev); +static void geode_cleanup (void ); +static unsigned int geode_data_present (void ); +static u32 geode_data_read (void ); +#endif +struct rng_operations {int (*init) (struct pci_dev *dev);void (*cleanup) (void );
@@ -122,6 +134,9 @@ enum { rng_hw_intel, rng_hw_amd, rng_hw_via, +#ifdef CONFIG_MGEODE_LX + rng_hw_geode, +#endif }; static struct rng_operations rng_vendor_ops[] = {
@@ -139,6 +154,11 @@ static struct rng_operations rng_vendor_ /* rng_hw_via */ { via_init, via_cleanup, via_data_present, via_data_read, 1 }, #endif + +#ifdef CONFIG_MGEODE_LX + /* rng_hw_geode */ + { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 } +#endif }; /*
@@ -159,6 +179,10 @@ static struct pci_device_id rng_pci_tbl[ { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, +#ifdef CONFIG_MGEODE_LX + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode }, +#endif { 0, }, /* terminate list */ };MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
@@ -460,6 +484,54 @@ static void via_cleanup(void) }#endif +#ifdef CONFIG_MGEODE_LX + +/*********************************************************************** +* +* AMD Geode RNG operations +* +*/ + +static void __iomem *geode_rng_base =0x0 ; + +#define GEODE_RNG_DATA_REG 0x50 +#define GEODE_RNG_STATUS_REG 0x54 + +static u32 geode_data_read (void ) { +u32 val; + + val = *((u32 *) (geode_rng_base +GEODE_RNG_DATA_REG )); +return val; +} + +static unsigned int geode_data_present (void ) { +u32 val; + + val = *((u32 *) (geode_rng_base +GEODE_RNG_STATUS_REG )); +return val; +} + +static void geode_cleanup (void ) { +iounmap (geode_rng_base); + geode_rng_base =NULL ; +} + +static int geode_init (struct pci_dev *dev) { +u32 rng_base =pci_resource_start (dev,0 ); +if (!rng_base)return 1 ; + + geode_rng_base =ioremap (rng_base,0x58 ); + +if (geode_rng_base ==NULL ) { + printk(KERN_ERR PFX "Cannot ioremap RNG memory\n"); +return -EBUSY ; + } + + printk(KERN_INFO PFX "Geode RNG registers at %p\n", geode_rng_base); +return 0 ; +} + +#endif /*********************************************************************** *
@@ -574,7 +646,7 @@ static int __init rng_init (void)DPRINTK ("ENTER\n" ); -/* Probe for Intel, AMD RNGs */ +/* Probe for Intel, AMD, Geode RNGs */ for_each_pci_dev (pdev) { ent =pci_match_id (rng_pci_tbl, pdev);if (ent) {
drivers/char/hw_random.c static void via_cleanup(void) · line 512
Quoted 13 lines · Jordan Crouse
drivers/char/hw_random.c +13
-0+static u32 geode_data_read (void ) { +u32 val; + + val = *((u32 *) (geode_rng_base +GEODE_RNG_DATA_REG )); +return val; +} + +static unsigned int geode_data_present (void ) { +u32 val; + + val = *((u32 *) (geode_rng_base +GEODE_RNG_STATUS_REG )); +return val; +}
Yowza.
At least the intel_* routines do this sort of thing to semi-check that the sucker exists:
assert (rng_mem != NULL);
writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);What does your code do if geode_init() manages to fail somehow?
drivers/char/hw_random.c static void via_cleanup(void) · line 512
Quoted 12 lines · Jordan Crouse
drivers/char/hw_random.c +12
-0+u32 val; + + val = *((u32 *) (geode_rng_base +GEODE_RNG_DATA_REG )); +return val; +} + +static unsigned int geode_data_present (void ) { +u32 val; + + val = *((u32 *) (geode_rng_base +GEODE_RNG_STATUS_REG )); +return val; +}
ioremap space is not directly for reference evenif it happens to work currently for this case - use readl
Quoted 2 lines · Jordan Crouse
This patch adds support for the hardware RNG device on the Geode LX processor. As a side note, the LX processor also includes a hardware
Interesting. Wish the mainstream AMD K8 CPUs had one too :)
Quoted 2 lines
AES encryption engine, support for which is not included here because I'm not one to increase the kernel source size if it doesn't need to be.
If it's faster than the i386 assembly version I think you should add it.
drivers/char/hw_random.c static unsigned int via_data_present (vo · line 108
Quoted 6 lines
drivers/char/hw_random.c +6
-0+#ifdef CONFIG_MGEODE_LX +static int __init geode_init (struct pci_dev *dev); +static void geode_cleanup (void ); +static unsigned int geode_data_present (void ); +static u32 geode_data_read (void ); +#endif
Declarations don't need ifdefs.
drivers/char/hw_random.c static void via_cleanup(void) · line 503
Quoted 4 lines
drivers/char/hw_random.c +4
-0+static u32 geode_data_read (void ) { +u32 val; + + val = *((u32 *) (geode_rng_base +GEODE_RNG_DATA_REG ));
This should use readl
drivers/char/hw_random.c static void via_cleanup(void) · line 507
Quoted 4 lines
drivers/char/hw_random.c +4
-0+return val; +} + +static unsigned int geode_data_present (void ) {
The bracket should be on an own line. Further occurrences.
drivers/char/hw_random.c static void via_cleanup(void) · line 520
Quoted 4 lines
drivers/char/hw_random.c +4
-0+} + +static int geode_init (struct pci_dev *dev) { +u32 rng_base =pci_resource_start (dev,0 );
This should be unsigned long
drivers/char/hw_random.c static void via_cleanup(void) · line 523
Quoted 3 lines
drivers/char/hw_random.c +3
-0+if (!rng_base)return 1 ; + + geode_rng_base =ioremap (rng_base,0x58 );
This should be ioremap_nocache()
drivers/char/hw_random.c static void via_cleanup(void) · line 530
Quoted 7 lines
drivers/char/hw_random.c +7
-0+ +if (geode_rng_base ==NULL ) { + printk(KERN_ERR PFX "Cannot ioremap RNG memory\n"); +return -EBUSY ; + } + + printk(KERN_INFO PFX "Geode RNG registers at %p\n", geode_rng_base);
I would advise to not print virtual addresses into the kernel log. They are usually completely useless to the user. Either physical or nothing.
-Andi