Showing error 847

User: Jiri Slaby
Error type: Resource Leak
Error type description: The code omits to put the resource to the system for reuse
File location: drivers/char/hw_random/intel-rng.c
Line in file: 336
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2011-11-07 22:40:13 UTC


Source:

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