Showing error 855

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/mtd/maps/amd76xrom.c
Line in file: 327
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2011-11-07 22:40:13 UTC


Source:

  1/*
  2 * amd76xrom.c
  3 *
  4 * Normal mappings of chips in physical memory
  5 */
  6
  7#include <linux/module.h>
  8#include <linux/types.h>
  9#include <linux/kernel.h>
 10#include <linux/init.h>
 11#include <asm/io.h>
 12#include <linux/mtd/mtd.h>
 13#include <linux/mtd/map.h>
 14#include <linux/mtd/cfi.h>
 15#include <linux/mtd/flashchip.h>
 16#include <linux/pci.h>
 17#include <linux/pci_ids.h>
 18#include <linux/list.h>
 19
 20
 21#define xstr(s) str(s)
 22#define str(s) #s
 23#define MOD_NAME xstr(KBUILD_BASENAME)
 24
 25#define ADDRESS_NAME_LEN 18
 26
 27#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
 28
 29struct amd76xrom_window {
 30        void __iomem *virt;
 31        unsigned long phys;
 32        unsigned long size;
 33        struct list_head maps;
 34        struct resource rsrc;
 35        struct pci_dev *pdev;
 36};
 37
 38struct amd76xrom_map_info {
 39        struct list_head list;
 40        struct map_info map;
 41        struct mtd_info *mtd;
 42        struct resource rsrc;
 43        char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
 44};
 45
 46/* The 2 bits controlling the window size are often set to allow reading
 47 * the BIOS, but too small to allow writing, since the lock registers are
 48 * 4MiB lower in the address space than the data.
 49 *
 50 * This is intended to prevent flashing the bios, perhaps accidentally.
 51 *
 52 * This parameter allows the normal driver to over-ride the BIOS settings.
 53 *
 54 * The bits are 6 and 7.  If both bits are set, it is a 5MiB window.
 55 * If only the 7 Bit is set, it is a 4MiB window.  Otherwise, a
 56 * 64KiB window.
 57 *
 58 */
 59static uint win_size_bits;
 60module_param(win_size_bits, uint, 0);
 61MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x43 byte, normally set by BIOS.");
 62
 63static struct amd76xrom_window amd76xrom_window = {
 64        .maps = LIST_HEAD_INIT(amd76xrom_window.maps),
 65};
 66
 67static void amd76xrom_cleanup(struct amd76xrom_window *window)
 68{
 69        struct amd76xrom_map_info *map, *scratch;
 70        u8 byte;
 71
 72        if (window->pdev) {
 73                /* Disable writes through the rom window */
 74                pci_read_config_byte(window->pdev, 0x40, &byte);
 75                pci_write_config_byte(window->pdev, 0x40, byte & ~1);
 76                pci_dev_put(window->pdev);
 77        }
 78
 79        /* Free all of the mtd devices */
 80        list_for_each_entry_safe(map, scratch, &window->maps, list) {
 81                if (map->rsrc.parent) {
 82                        release_resource(&map->rsrc);
 83                }
 84                del_mtd_device(map->mtd);
 85                map_destroy(map->mtd);
 86                list_del(&map->list);
 87                kfree(map);
 88        }
 89        if (window->rsrc.parent)
 90                release_resource(&window->rsrc);
 91
 92        if (window->virt) {
 93                iounmap(window->virt);
 94                window->virt = NULL;
 95                window->phys = 0;
 96                window->size = 0;
 97                window->pdev = NULL;
 98        }
 99}
100
101
102static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
103        const struct pci_device_id *ent)
104{
105        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
106        u8 byte;
107        struct amd76xrom_window *window = &amd76xrom_window;
108        struct amd76xrom_map_info *map = NULL;
109        unsigned long map_top;
110
111        /* Remember the pci dev I find the window in - already have a ref */
112        window->pdev = pdev;
113
114        /* Enable the selected rom window.  This is often incorrectly
115         * set up by the BIOS, and the 4MiB offset for the lock registers
116         * requires the full 5MiB of window space.
117         *
118         * This 'write, then read' approach leaves the bits for
119         * other uses of the hardware info.
120         */
121        pci_read_config_byte(pdev, 0x43, &byte);
122        pci_write_config_byte(pdev, 0x43, byte | win_size_bits );
123
124        /* Assume the rom window is properly setup, and find it's size */
125        pci_read_config_byte(pdev, 0x43, &byte);
126        if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
127                window->phys = 0xffb00000; /* 5MiB */
128        }
129        else if ((byte & (1<<7)) == (1<<7)) {
130                window->phys = 0xffc00000; /* 4MiB */
131        }
132        else {
133                window->phys = 0xffff0000; /* 64KiB */
134        }
135        window->size = 0xffffffffUL - window->phys + 1UL;
136
137        /*
138         * Try to reserve the window mem region.  If this fails then
139         * it is likely due to a fragment of the window being
140         * "reseved" by the BIOS.  In the case that the
141         * request_mem_region() fails then once the rom size is
142         * discovered we will try to reserve the unreserved fragment.
143         */
144        window->rsrc.name = MOD_NAME;
145        window->rsrc.start = window->phys;
146        window->rsrc.end   = window->phys + window->size - 1;
147        window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
148        if (request_resource(&iomem_resource, &window->rsrc)) {
149                window->rsrc.parent = NULL;
150                printk(KERN_ERR MOD_NAME
151                        " %s(): Unable to register resource"
152                        " 0x%.16llx-0x%.16llx - kernel bug?\n",
153                        __func__,
154                        (unsigned long long)window->rsrc.start,
155                        (unsigned long long)window->rsrc.end);
156        }
157
158
159        /* Enable writes through the rom window */
160        pci_read_config_byte(pdev, 0x40, &byte);
161        pci_write_config_byte(pdev, 0x40, byte | 1);
162
163        /* FIXME handle registers 0x80 - 0x8C the bios region locks */
164
165        /* For write accesses caches are useless */
166        window->virt = ioremap_nocache(window->phys, window->size);
167        if (!window->virt) {
168                printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
169                        window->phys, window->size);
170                goto out;
171        }
172
173        /* Get the first address to look for an rom chip at */
174        map_top = window->phys;
175#if 1
176        /* The probe sequence run over the firmware hub lock
177         * registers sets them to 0x7 (no access).
178         * Probe at most the last 4M of the address space.
179         */
180        if (map_top < 0xffc00000) {
181                map_top = 0xffc00000;
182        }
183#endif
184        /* Loop  through and look for rom chips */
185        while((map_top - 1) < 0xffffffffUL) {
186                struct cfi_private *cfi;
187                unsigned long offset;
188                int i;
189
190                if (!map) {
191                        map = kmalloc(sizeof(*map), GFP_KERNEL);
192                }
193                if (!map) {
194                        printk(KERN_ERR MOD_NAME ": kmalloc failed");
195                        goto out;
196                }
197                memset(map, 0, sizeof(*map));
198                INIT_LIST_HEAD(&map->list);
199                map->map.name = map->map_name;
200                map->map.phys = map_top;
201                offset = map_top - window->phys;
202                map->map.virt = (void __iomem *)
203                        (((unsigned long)(window->virt)) + offset);
204                map->map.size = 0xffffffffUL - map_top + 1UL;
205                /* Set the name of the map to the address I am trying */
206                sprintf(map->map_name, "%s @%08Lx",
207                        MOD_NAME, (unsigned long long)map->map.phys);
208
209                /* There is no generic VPP support */
210                for(map->map.bankwidth = 32; map->map.bankwidth;
211                        map->map.bankwidth >>= 1)
212                {
213                        char **probe_type;
214                        /* Skip bankwidths that are not supported */
215                        if (!map_bankwidth_supported(map->map.bankwidth))
216                                continue;
217
218                        /* Setup the map methods */
219                        simple_map_init(&map->map);
220
221                        /* Try all of the probe methods */
222                        probe_type = rom_probe_types;
223                        for(; *probe_type; probe_type++) {
224                                map->mtd = do_map_probe(*probe_type, &map->map);
225                                if (map->mtd)
226                                        goto found;
227                        }
228                }
229                map_top += ROM_PROBE_STEP_SIZE;
230                continue;
231        found:
232                /* Trim the size if we are larger than the map */
233                if (map->mtd->size > map->map.size) {
234                        printk(KERN_WARNING MOD_NAME
235                                " rom(%u) larger than window(%lu). fixing...\n",
236                                map->mtd->size, map->map.size);
237                        map->mtd->size = map->map.size;
238                }
239                if (window->rsrc.parent) {
240                        /*
241                         * Registering the MTD device in iomem may not be possible
242                         * if there is a BIOS "reserved" and BUSY range.  If this
243                         * fails then continue anyway.
244                         */
245                        map->rsrc.name  = map->map_name;
246                        map->rsrc.start = map->map.phys;
247                        map->rsrc.end   = map->map.phys + map->mtd->size - 1;
248                        map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
249                        if (request_resource(&window->rsrc, &map->rsrc)) {
250                                printk(KERN_ERR MOD_NAME
251                                        ": cannot reserve MTD resource\n");
252                                map->rsrc.parent = NULL;
253                        }
254                }
255
256                /* Make the whole region visible in the map */
257                map->map.virt = window->virt;
258                map->map.phys = window->phys;
259                cfi = map->map.fldrv_priv;
260                for(i = 0; i < cfi->numchips; i++) {
261                        cfi->chips[i].start += offset;
262                }
263
264                /* Now that the mtd devices is complete claim and export it */
265                map->mtd->owner = THIS_MODULE;
266                if (add_mtd_device(map->mtd)) {
267                        map_destroy(map->mtd);
268                        map->mtd = NULL;
269                        goto out;
270                }
271
272
273                /* Calculate the new value of map_top */
274                map_top += map->mtd->size;
275
276                /* File away the map structure */
277                list_add(&map->list, &window->maps);
278                map = NULL;
279        }
280
281 out:
282        /* Free any left over map structures */
283        kfree(map);
284        /* See if I have any map structures */
285        if (list_empty(&window->maps)) {
286                amd76xrom_cleanup(window);
287                return -ENODEV;
288        }
289        return 0;
290}
291
292
293static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
294{
295        struct amd76xrom_window *window = &amd76xrom_window;
296
297        amd76xrom_cleanup(window);
298}
299
300static struct pci_device_id amd76xrom_pci_tbl[] = {
301        { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,
302                PCI_ANY_ID, PCI_ANY_ID, },
303        { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,
304                PCI_ANY_ID, PCI_ANY_ID, },
305        { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
306        { 0, }
307};
308
309MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
310
311#if 0
312static struct pci_driver amd76xrom_driver = {
313        .name =                MOD_NAME,
314        .id_table =        amd76xrom_pci_tbl,
315        .probe =        amd76xrom_init_one,
316        .remove =        amd76xrom_remove_one,
317};
318#endif
319
320static int __init init_amd76xrom(void)
321{
322        struct pci_dev *pdev;
323        struct pci_device_id *id;
324        pdev = NULL;
325        for(id = amd76xrom_pci_tbl; id->vendor; id++) {
326                pdev = pci_get_device(id->vendor, id->device, NULL);
327                if (pdev) {
328                        break;
329                }
330        }
331        if (pdev) {
332                return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
333        }
334        return -ENXIO;
335#if 0
336        return pci_register_driver(&amd76xrom_driver);
337#endif
338}
339
340static void __exit cleanup_amd76xrom(void)
341{
342        amd76xrom_remove_one(amd76xrom_window.pdev);
343}
344
345module_init(init_amd76xrom);
346module_exit(cleanup_amd76xrom);
347
348MODULE_LICENSE("GPL");
349MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
350MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
351