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