419 lines · c
1/*2 * RNG driver for Intel RNGs3 *4 * Copyright 2005 (c) MontaVista Software, Inc.5 *6 * with the majority of the code coming from:7 *8 * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)9 * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>10 *11 * derived from12 *13 * Hardware driver for the AMD 768 Random Number Generator (RNG)14 * (c) Copyright 2001 Red Hat Inc15 *16 * derived from17 *18 * Hardware driver for Intel i810 Random Number Generator (RNG)19 * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>20 * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>21 *22 * This file is licensed under the terms of the GNU General Public23 * License version 2. This program is licensed "as is" without any24 * warranty of any kind, whether express or implied.25 */26 27#include <linux/hw_random.h>28#include <linux/io.h>29#include <linux/kernel.h>30#include <linux/module.h>31#include <linux/pci.h>32#include <linux/stop_machine.h>33#include <linux/delay.h>34#include <linux/slab.h>35 36 37#define PFX KBUILD_MODNAME ": "38 39/*40 * RNG registers41 */42#define INTEL_RNG_HW_STATUS 043#define INTEL_RNG_PRESENT 0x4044#define INTEL_RNG_ENABLED 0x0145#define INTEL_RNG_STATUS 146#define INTEL_RNG_DATA_PRESENT 0x0147#define INTEL_RNG_DATA 248 49/*50 * Magic address at which Intel PCI bridges locate the RNG51 */52#define INTEL_RNG_ADDR 0xFFBC015F53#define INTEL_RNG_ADDR_LEN 354 55/*56 * LPC bridge PCI config space registers57 */58#define FWH_DEC_EN1_REG_OLD 0xe359#define FWH_DEC_EN1_REG_NEW 0xd9 /* high byte of 16-bit register */60#define FWH_F8_EN_MASK 0x8061 62#define BIOS_CNTL_REG_OLD 0x4e63#define BIOS_CNTL_REG_NEW 0xdc64#define BIOS_CNTL_WRITE_ENABLE_MASK 0x0165#define BIOS_CNTL_LOCK_ENABLE_MASK 0x0266 67/*68 * Magic address at which Intel Firmware Hubs get accessed69 */70#define INTEL_FWH_ADDR 0xffff000071#define INTEL_FWH_ADDR_LEN 272 73/*74 * Intel Firmware Hub command codes (write to any address inside the device)75 */76#define INTEL_FWH_RESET_CMD 0xff /* aka READ_ARRAY */77#define INTEL_FWH_READ_ID_CMD 0x9078 79/*80 * Intel Firmware Hub Read ID command result addresses81 */82#define INTEL_FWH_MANUFACTURER_CODE_ADDRESS 0x00000083#define INTEL_FWH_DEVICE_CODE_ADDRESS 0x00000184 85/*86 * Intel Firmware Hub Read ID command result values87 */88#define INTEL_FWH_MANUFACTURER_CODE 0x8989#define INTEL_FWH_DEVICE_CODE_8M 0xac90#define INTEL_FWH_DEVICE_CODE_4M 0xad91 92/*93 * Data for PCI driver interface94 *95 * This data only exists for exporting the supported96 * PCI ids via MODULE_DEVICE_TABLE. We do not actually97 * register a pci_driver, because someone else might one day98 * want to register another driver on the same PCI id.99 */100static const struct pci_device_id pci_tbl[] = {101/* AA102 { PCI_DEVICE(0x8086, 0x2418) }, */103 { PCI_DEVICE(0x8086, 0x2410) }, /* AA */104/* AB105 { PCI_DEVICE(0x8086, 0x2428) }, */106 { PCI_DEVICE(0x8086, 0x2420) }, /* AB */107/* ??108 { PCI_DEVICE(0x8086, 0x2430) }, */109/* BAM, CAM, DBM, FBM, GxM110 { PCI_DEVICE(0x8086, 0x2448) }, */111 { PCI_DEVICE(0x8086, 0x244c) }, /* BAM */112 { PCI_DEVICE(0x8086, 0x248c) }, /* CAM */113 { PCI_DEVICE(0x8086, 0x24cc) }, /* DBM */114 { PCI_DEVICE(0x8086, 0x2641) }, /* FBM */115 { PCI_DEVICE(0x8086, 0x27b9) }, /* GxM */116 { PCI_DEVICE(0x8086, 0x27bd) }, /* GxM DH */117/* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx118 { PCI_DEVICE(0x8086, 0x244e) }, */119 { PCI_DEVICE(0x8086, 0x2440) }, /* BA */120 { PCI_DEVICE(0x8086, 0x2480) }, /* CA */121 { PCI_DEVICE(0x8086, 0x24c0) }, /* DB */122 { PCI_DEVICE(0x8086, 0x24d0) }, /* Ex */123 { PCI_DEVICE(0x8086, 0x25a1) }, /* 6300 */124 { PCI_DEVICE(0x8086, 0x2640) }, /* Fx */125 { PCI_DEVICE(0x8086, 0x2670) }, /* 631x/632x */126 { PCI_DEVICE(0x8086, 0x2671) }, /* 631x/632x */127 { PCI_DEVICE(0x8086, 0x2672) }, /* 631x/632x */128 { PCI_DEVICE(0x8086, 0x2673) }, /* 631x/632x */129 { PCI_DEVICE(0x8086, 0x2674) }, /* 631x/632x */130 { PCI_DEVICE(0x8086, 0x2675) }, /* 631x/632x */131 { PCI_DEVICE(0x8086, 0x2676) }, /* 631x/632x */132 { PCI_DEVICE(0x8086, 0x2677) }, /* 631x/632x */133 { PCI_DEVICE(0x8086, 0x2678) }, /* 631x/632x */134 { PCI_DEVICE(0x8086, 0x2679) }, /* 631x/632x */135 { PCI_DEVICE(0x8086, 0x267a) }, /* 631x/632x */136 { PCI_DEVICE(0x8086, 0x267b) }, /* 631x/632x */137 { PCI_DEVICE(0x8086, 0x267c) }, /* 631x/632x */138 { PCI_DEVICE(0x8086, 0x267d) }, /* 631x/632x */139 { PCI_DEVICE(0x8086, 0x267e) }, /* 631x/632x */140 { PCI_DEVICE(0x8086, 0x267f) }, /* 631x/632x */141 { PCI_DEVICE(0x8086, 0x27b8) }, /* Gx */142/* E143 { PCI_DEVICE(0x8086, 0x245e) }, */144 { PCI_DEVICE(0x8086, 0x2450) }, /* E */145 { 0, }, /* terminate list */146};147MODULE_DEVICE_TABLE(pci, pci_tbl);148 149static __initdata int no_fwh_detect;150module_param(no_fwh_detect, int, 0);151MODULE_PARM_DESC(no_fwh_detect, "Skip FWH detection:\n"152 " positive value - skip if FWH space locked read-only\n"153 " negative value - skip always");154 155static inline u8 hwstatus_get(void __iomem *mem)156{157 return readb(mem + INTEL_RNG_HW_STATUS);158}159 160static inline u8 hwstatus_set(void __iomem *mem,161 u8 hw_status)162{163 writeb(hw_status, mem + INTEL_RNG_HW_STATUS);164 return hwstatus_get(mem);165}166 167static int intel_rng_data_present(struct hwrng *rng, int wait)168{169 void __iomem *mem = (void __iomem *)rng->priv;170 int data, i;171 172 for (i = 0; i < 20; i++) {173 data = !!(readb(mem + INTEL_RNG_STATUS) &174 INTEL_RNG_DATA_PRESENT);175 if (data || !wait)176 break;177 udelay(10);178 }179 return data;180}181 182static int intel_rng_data_read(struct hwrng *rng, u32 *data)183{184 void __iomem *mem = (void __iomem *)rng->priv;185 186 *data = readb(mem + INTEL_RNG_DATA);187 188 return 1;189}190 191static int intel_rng_init(struct hwrng *rng)192{193 void __iomem *mem = (void __iomem *)rng->priv;194 u8 hw_status;195 int err = -EIO;196 197 hw_status = hwstatus_get(mem);198 /* turn RNG h/w on, if it's off */199 if ((hw_status & INTEL_RNG_ENABLED) == 0)200 hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED);201 if ((hw_status & INTEL_RNG_ENABLED) == 0) {202 pr_err(PFX "cannot enable RNG, aborting\n");203 goto out;204 }205 err = 0;206out:207 return err;208}209 210static void intel_rng_cleanup(struct hwrng *rng)211{212 void __iomem *mem = (void __iomem *)rng->priv;213 u8 hw_status;214 215 hw_status = hwstatus_get(mem);216 if (hw_status & INTEL_RNG_ENABLED)217 hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED);218 else219 pr_warn(PFX "unusual: RNG already disabled\n");220}221 222 223static struct hwrng intel_rng = {224 .name = "intel",225 .init = intel_rng_init,226 .cleanup = intel_rng_cleanup,227 .data_present = intel_rng_data_present,228 .data_read = intel_rng_data_read,229};230 231struct intel_rng_hw {232 struct pci_dev *dev;233 void __iomem *mem;234 u8 bios_cntl_off;235 u8 bios_cntl_val;236 u8 fwh_dec_en1_off;237 u8 fwh_dec_en1_val;238};239 240static int __init intel_rng_hw_init(void *_intel_rng_hw)241{242 struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;243 u8 mfc, dvc;244 245 /* interrupts disabled in stop_machine call */246 247 if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))248 pci_write_config_byte(intel_rng_hw->dev,249 intel_rng_hw->fwh_dec_en1_off,250 intel_rng_hw->fwh_dec_en1_val |251 FWH_F8_EN_MASK);252 if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))253 pci_write_config_byte(intel_rng_hw->dev,254 intel_rng_hw->bios_cntl_off,255 intel_rng_hw->bios_cntl_val |256 BIOS_CNTL_WRITE_ENABLE_MASK);257 258 writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);259 writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem);260 mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);261 dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS);262 writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);263 264 if (!(intel_rng_hw->bios_cntl_val &265 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))266 pci_write_config_byte(intel_rng_hw->dev,267 intel_rng_hw->bios_cntl_off,268 intel_rng_hw->bios_cntl_val);269 if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))270 pci_write_config_byte(intel_rng_hw->dev,271 intel_rng_hw->fwh_dec_en1_off,272 intel_rng_hw->fwh_dec_en1_val);273 274 if (mfc != INTEL_FWH_MANUFACTURER_CODE ||275 (dvc != INTEL_FWH_DEVICE_CODE_8M &&276 dvc != INTEL_FWH_DEVICE_CODE_4M)) {277 pr_notice(PFX "FWH not detected\n");278 return -ENODEV;279 }280 281 return 0;282}283 284static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,285 struct pci_dev *dev)286{287 intel_rng_hw->bios_cntl_val = 0xff;288 intel_rng_hw->fwh_dec_en1_val = 0xff;289 intel_rng_hw->dev = dev;290 291 /* Check for Intel 82802 */292 if (dev->device < 0x2640) {293 intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;294 intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD;295 } else {296 intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;297 intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW;298 }299 300 pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off,301 &intel_rng_hw->fwh_dec_en1_val);302 pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off,303 &intel_rng_hw->bios_cntl_val);304 305 if ((intel_rng_hw->bios_cntl_val &306 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))307 == BIOS_CNTL_LOCK_ENABLE_MASK) {308 static __initdata /*const*/ char warning[] =309PFX "Firmware space is locked read-only. If you can't or\n"310PFX "don't want to disable this in firmware setup, and if\n"311PFX "you are certain that your system has a functional\n"312PFX "RNG, try using the 'no_fwh_detect' option.\n";313 314 if (no_fwh_detect)315 return -ENODEV;316 pr_warn("%s", warning);317 return -EBUSY;318 }319 320 intel_rng_hw->mem = ioremap(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);321 if (intel_rng_hw->mem == NULL)322 return -EBUSY;323 324 return 0;325}326 327 328static int __init intel_rng_mod_init(void)329{330 int err = -ENODEV;331 int i;332 struct pci_dev *dev = NULL;333 void __iomem *mem;334 u8 hw_status;335 struct intel_rng_hw *intel_rng_hw;336 337 for (i = 0; !dev && pci_tbl[i].vendor; ++i)338 dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device,339 NULL);340 341 if (!dev)342 goto out; /* Device not found. */343 344 if (no_fwh_detect < 0) {345 pci_dev_put(dev);346 goto fwh_done;347 }348 349 intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL);350 if (!intel_rng_hw) {351 pci_dev_put(dev);352 goto out;353 }354 355 err = intel_init_hw_struct(intel_rng_hw, dev);356 if (err) {357 pci_dev_put(dev);358 kfree(intel_rng_hw);359 if (err == -ENODEV)360 goto fwh_done;361 goto out;362 }363 364 /*365 * Since the BIOS code/data is going to disappear from its normal366 * location with the Read ID command, all activity on the system367 * must be stopped until the state is back to normal.368 *369 * Use stop_machine because IPIs can be blocked by disabling370 * interrupts.371 */372 err = stop_machine(intel_rng_hw_init, intel_rng_hw, NULL);373 pci_dev_put(dev);374 iounmap(intel_rng_hw->mem);375 kfree(intel_rng_hw);376 if (err)377 goto out;378 379fwh_done:380 err = -ENOMEM;381 mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);382 if (!mem)383 goto out;384 intel_rng.priv = (unsigned long)mem;385 386 /* Check for Random Number Generator */387 err = -ENODEV;388 hw_status = hwstatus_get(mem);389 if ((hw_status & INTEL_RNG_PRESENT) == 0) {390 iounmap(mem);391 goto out;392 }393 394 pr_info("Intel 82802 RNG detected\n");395 err = hwrng_register(&intel_rng);396 if (err) {397 pr_err(PFX "RNG registering failed (%d)\n",398 err);399 iounmap(mem);400 }401out:402 return err;403 404}405 406static void __exit intel_rng_mod_exit(void)407{408 void __iomem *mem = (void __iomem *)intel_rng.priv;409 410 hwrng_unregister(&intel_rng);411 iounmap(mem);412}413 414module_init(intel_rng_mod_init);415module_exit(intel_rng_mod_exit);416 417MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets");418MODULE_LICENSE("GPL");419