109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
229175778SLew Glendenning /*
329175778SLew Glendenning * esb2rom.c
429175778SLew Glendenning *
529175778SLew Glendenning * Normal mappings of flash chips in physical memory
629175778SLew Glendenning * through the Intel ESB2 Southbridge.
729175778SLew Glendenning *
829175778SLew Glendenning * This was derived from ichxrom.c in May 2006 by
929175778SLew Glendenning * Lew Glendenning <lglendenning@lnxi.com>
1029175778SLew Glendenning *
1129175778SLew Glendenning * Eric Biederman, of course, was a major help in this effort.
1229175778SLew Glendenning */
1329175778SLew Glendenning
1429175778SLew Glendenning #include <linux/module.h>
1529175778SLew Glendenning #include <linux/types.h>
1629175778SLew Glendenning #include <linux/kernel.h>
1729175778SLew Glendenning #include <linux/init.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
1929175778SLew Glendenning #include <asm/io.h>
2029175778SLew Glendenning #include <linux/mtd/mtd.h>
2129175778SLew Glendenning #include <linux/mtd/map.h>
2229175778SLew Glendenning #include <linux/mtd/cfi.h>
2329175778SLew Glendenning #include <linux/mtd/flashchip.h>
2429175778SLew Glendenning #include <linux/pci.h>
2529175778SLew Glendenning #include <linux/pci_ids.h>
2629175778SLew Glendenning #include <linux/list.h>
2729175778SLew Glendenning
2829175778SLew Glendenning #define MOD_NAME KBUILD_BASENAME
2929175778SLew Glendenning
3029175778SLew Glendenning #define ADDRESS_NAME_LEN 18
3129175778SLew Glendenning
3229175778SLew Glendenning #define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
3329175778SLew Glendenning
3429175778SLew Glendenning #define BIOS_CNTL 0xDC
3529175778SLew Glendenning #define BIOS_LOCK_ENABLE 0x02
3629175778SLew Glendenning #define BIOS_WRITE_ENABLE 0x01
3729175778SLew Glendenning
3829175778SLew Glendenning /* This became a 16-bit register, and EN2 has disappeared */
3929175778SLew Glendenning #define FWH_DEC_EN1 0xD8
4029175778SLew Glendenning #define FWH_F8_EN 0x8000
4129175778SLew Glendenning #define FWH_F0_EN 0x4000
4229175778SLew Glendenning #define FWH_E8_EN 0x2000
4329175778SLew Glendenning #define FWH_E0_EN 0x1000
4429175778SLew Glendenning #define FWH_D8_EN 0x0800
4529175778SLew Glendenning #define FWH_D0_EN 0x0400
4629175778SLew Glendenning #define FWH_C8_EN 0x0200
4729175778SLew Glendenning #define FWH_C0_EN 0x0100
4829175778SLew Glendenning #define FWH_LEGACY_F_EN 0x0080
4929175778SLew Glendenning #define FWH_LEGACY_E_EN 0x0040
5029175778SLew Glendenning /* reserved 0x0020 and 0x0010 */
5129175778SLew Glendenning #define FWH_70_EN 0x0008
5229175778SLew Glendenning #define FWH_60_EN 0x0004
5329175778SLew Glendenning #define FWH_50_EN 0x0002
5429175778SLew Glendenning #define FWH_40_EN 0x0001
5529175778SLew Glendenning
5629175778SLew Glendenning /* these are 32-bit values */
5729175778SLew Glendenning #define FWH_SEL1 0xD0
5829175778SLew Glendenning #define FWH_SEL2 0xD4
5929175778SLew Glendenning
6029175778SLew Glendenning #define FWH_8MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
6129175778SLew Glendenning FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
6229175778SLew Glendenning FWH_70_EN | FWH_60_EN | FWH_50_EN | FWH_40_EN)
6329175778SLew Glendenning
6429175778SLew Glendenning #define FWH_7MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
6529175778SLew Glendenning FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
6629175778SLew Glendenning FWH_70_EN | FWH_60_EN | FWH_50_EN)
6729175778SLew Glendenning
6829175778SLew Glendenning #define FWH_6MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
6929175778SLew Glendenning FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
7029175778SLew Glendenning FWH_70_EN | FWH_60_EN)
7129175778SLew Glendenning
7229175778SLew Glendenning #define FWH_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
7329175778SLew Glendenning FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
7429175778SLew Glendenning FWH_70_EN)
7529175778SLew Glendenning
7629175778SLew Glendenning #define FWH_4MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
7729175778SLew Glendenning FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN)
7829175778SLew Glendenning
7929175778SLew Glendenning #define FWH_3_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
8029175778SLew Glendenning FWH_D8_EN | FWH_D0_EN | FWH_C8_EN)
8129175778SLew Glendenning
8229175778SLew Glendenning #define FWH_3MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
8329175778SLew Glendenning FWH_D8_EN | FWH_D0_EN)
8429175778SLew Glendenning
8529175778SLew Glendenning #define FWH_2_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
8629175778SLew Glendenning FWH_D8_EN)
8729175778SLew Glendenning
8829175778SLew Glendenning #define FWH_2MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN)
8929175778SLew Glendenning
9029175778SLew Glendenning #define FWH_1_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN)
9129175778SLew Glendenning
9229175778SLew Glendenning #define FWH_1MiB (FWH_F8_EN | FWH_F0_EN)
9329175778SLew Glendenning
9429175778SLew Glendenning #define FWH_0_5MiB (FWH_F8_EN)
9529175778SLew Glendenning
9629175778SLew Glendenning
9729175778SLew Glendenning struct esb2rom_window {
9829175778SLew Glendenning void __iomem* virt;
9929175778SLew Glendenning unsigned long phys;
10029175778SLew Glendenning unsigned long size;
10129175778SLew Glendenning struct list_head maps;
10229175778SLew Glendenning struct resource rsrc;
10329175778SLew Glendenning struct pci_dev *pdev;
10429175778SLew Glendenning };
10529175778SLew Glendenning
10629175778SLew Glendenning struct esb2rom_map_info {
10729175778SLew Glendenning struct list_head list;
10829175778SLew Glendenning struct map_info map;
10929175778SLew Glendenning struct mtd_info *mtd;
11029175778SLew Glendenning struct resource rsrc;
11129175778SLew Glendenning char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
11229175778SLew Glendenning };
11329175778SLew Glendenning
11429175778SLew Glendenning static struct esb2rom_window esb2rom_window = {
11529175778SLew Glendenning .maps = LIST_HEAD_INIT(esb2rom_window.maps),
11629175778SLew Glendenning };
11729175778SLew Glendenning
esb2rom_cleanup(struct esb2rom_window * window)11829175778SLew Glendenning static void esb2rom_cleanup(struct esb2rom_window *window)
11929175778SLew Glendenning {
12029175778SLew Glendenning struct esb2rom_map_info *map, *scratch;
12129175778SLew Glendenning u8 byte;
12229175778SLew Glendenning
12329175778SLew Glendenning /* Disable writes through the rom window */
12429175778SLew Glendenning pci_read_config_byte(window->pdev, BIOS_CNTL, &byte);
12529175778SLew Glendenning pci_write_config_byte(window->pdev, BIOS_CNTL,
12629175778SLew Glendenning byte & ~BIOS_WRITE_ENABLE);
12729175778SLew Glendenning
12829175778SLew Glendenning /* Free all of the mtd devices */
12929175778SLew Glendenning list_for_each_entry_safe(map, scratch, &window->maps, list) {
13029175778SLew Glendenning if (map->rsrc.parent)
13129175778SLew Glendenning release_resource(&map->rsrc);
132ee0e87b1SJamie Iles mtd_device_unregister(map->mtd);
13329175778SLew Glendenning map_destroy(map->mtd);
13429175778SLew Glendenning list_del(&map->list);
13529175778SLew Glendenning kfree(map);
13629175778SLew Glendenning }
13729175778SLew Glendenning if (window->rsrc.parent)
13829175778SLew Glendenning release_resource(&window->rsrc);
13929175778SLew Glendenning if (window->virt) {
14029175778SLew Glendenning iounmap(window->virt);
14129175778SLew Glendenning window->virt = NULL;
14229175778SLew Glendenning window->phys = 0;
14329175778SLew Glendenning window->size = 0;
14429175778SLew Glendenning }
145c7438d02SAlan Cox pci_dev_put(window->pdev);
14629175778SLew Glendenning }
14729175778SLew Glendenning
esb2rom_init_one(struct pci_dev * pdev,const struct pci_device_id * ent)148e4106a7cSJulia Lawall static int __init esb2rom_init_one(struct pci_dev *pdev,
14929175778SLew Glendenning const struct pci_device_id *ent)
15029175778SLew Glendenning {
15129175778SLew Glendenning static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
15229175778SLew Glendenning struct esb2rom_window *window = &esb2rom_window;
15329175778SLew Glendenning struct esb2rom_map_info *map = NULL;
15429175778SLew Glendenning unsigned long map_top;
15529175778SLew Glendenning u8 byte;
15629175778SLew Glendenning u16 word;
15729175778SLew Glendenning
15829175778SLew Glendenning /* For now I just handle the ecb2 and I assume there
15929175778SLew Glendenning * are not a lot of resources up at the top of the address
16029175778SLew Glendenning * space. It is possible to handle other devices in the
16129175778SLew Glendenning * top 16MiB but it is very painful. Also since
16229175778SLew Glendenning * you can only really attach a FWH to an ICHX there
16329175778SLew Glendenning * a number of simplifications you can make.
16429175778SLew Glendenning *
16529175778SLew Glendenning * Also you can page firmware hubs if an 8MiB window isn't enough
16629175778SLew Glendenning * but don't currently handle that case either.
16729175778SLew Glendenning */
168c7438d02SAlan Cox window->pdev = pci_dev_get(pdev);
16929175778SLew Glendenning
17029175778SLew Glendenning /* RLG: experiment 2. Force the window registers to the widest values */
17129175778SLew Glendenning
17229175778SLew Glendenning /*
17329175778SLew Glendenning pci_read_config_word(pdev, FWH_DEC_EN1, &word);
17429175778SLew Glendenning printk(KERN_DEBUG "Original FWH_DEC_EN1 : %x\n", word);
17529175778SLew Glendenning pci_write_config_byte(pdev, FWH_DEC_EN1, 0xff);
17629175778SLew Glendenning pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
17729175778SLew Glendenning printk(KERN_DEBUG "New FWH_DEC_EN1 : %x\n", byte);
17829175778SLew Glendenning
17929175778SLew Glendenning pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
18029175778SLew Glendenning printk(KERN_DEBUG "Original FWH_DEC_EN2 : %x\n", byte);
18129175778SLew Glendenning pci_write_config_byte(pdev, FWH_DEC_EN2, 0x0f);
18229175778SLew Glendenning pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
18329175778SLew Glendenning printk(KERN_DEBUG "New FWH_DEC_EN2 : %x\n", byte);
18429175778SLew Glendenning */
18529175778SLew Glendenning
18629175778SLew Glendenning /* Find a region continuous to the end of the ROM window */
18729175778SLew Glendenning window->phys = 0;
18829175778SLew Glendenning pci_read_config_word(pdev, FWH_DEC_EN1, &word);
189dc164bbbSCyrill Gorcunov printk(KERN_DEBUG "pci_read_config_word : %x\n", word);
19029175778SLew Glendenning
19129175778SLew Glendenning if ((word & FWH_8MiB) == FWH_8MiB)
19229175778SLew Glendenning window->phys = 0xff400000;
19329175778SLew Glendenning else if ((word & FWH_7MiB) == FWH_7MiB)
19429175778SLew Glendenning window->phys = 0xff500000;
19529175778SLew Glendenning else if ((word & FWH_6MiB) == FWH_6MiB)
19629175778SLew Glendenning window->phys = 0xff600000;
19729175778SLew Glendenning else if ((word & FWH_5MiB) == FWH_5MiB)
19829175778SLew Glendenning window->phys = 0xFF700000;
19929175778SLew Glendenning else if ((word & FWH_4MiB) == FWH_4MiB)
20029175778SLew Glendenning window->phys = 0xffc00000;
20129175778SLew Glendenning else if ((word & FWH_3_5MiB) == FWH_3_5MiB)
20229175778SLew Glendenning window->phys = 0xffc80000;
20329175778SLew Glendenning else if ((word & FWH_3MiB) == FWH_3MiB)
20429175778SLew Glendenning window->phys = 0xffd00000;
20529175778SLew Glendenning else if ((word & FWH_2_5MiB) == FWH_2_5MiB)
20629175778SLew Glendenning window->phys = 0xffd80000;
20729175778SLew Glendenning else if ((word & FWH_2MiB) == FWH_2MiB)
20829175778SLew Glendenning window->phys = 0xffe00000;
20929175778SLew Glendenning else if ((word & FWH_1_5MiB) == FWH_1_5MiB)
21029175778SLew Glendenning window->phys = 0xffe80000;
21129175778SLew Glendenning else if ((word & FWH_1MiB) == FWH_1MiB)
21229175778SLew Glendenning window->phys = 0xfff00000;
21329175778SLew Glendenning else if ((word & FWH_0_5MiB) == FWH_0_5MiB)
21429175778SLew Glendenning window->phys = 0xfff80000;
21529175778SLew Glendenning
216dc164bbbSCyrill Gorcunov if (window->phys == 0) {
217dc164bbbSCyrill Gorcunov printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
218dc164bbbSCyrill Gorcunov goto out;
219dc164bbbSCyrill Gorcunov }
220dc164bbbSCyrill Gorcunov
22129175778SLew Glendenning /* reserved 0x0020 and 0x0010 */
22229175778SLew Glendenning window->phys -= 0x400000UL;
22329175778SLew Glendenning window->size = (0xffffffffUL - window->phys) + 1UL;
22429175778SLew Glendenning
22529175778SLew Glendenning /* Enable writes through the rom window */
22629175778SLew Glendenning pci_read_config_byte(pdev, BIOS_CNTL, &byte);
22729175778SLew Glendenning if (!(byte & BIOS_WRITE_ENABLE) && (byte & (BIOS_LOCK_ENABLE))) {
22829175778SLew Glendenning /* The BIOS will generate an error if I enable
22929175778SLew Glendenning * this device, so don't even try.
23029175778SLew Glendenning */
23129175778SLew Glendenning printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
23229175778SLew Glendenning goto out;
23329175778SLew Glendenning }
23429175778SLew Glendenning pci_write_config_byte(pdev, BIOS_CNTL, byte | BIOS_WRITE_ENABLE);
23529175778SLew Glendenning
23629175778SLew Glendenning /*
23729175778SLew Glendenning * Try to reserve the window mem region. If this fails then
23801d0afddSGeert Uytterhoeven * it is likely due to the window being "reserved" by the BIOS.
23929175778SLew Glendenning */
24029175778SLew Glendenning window->rsrc.name = MOD_NAME;
24129175778SLew Glendenning window->rsrc.start = window->phys;
24229175778SLew Glendenning window->rsrc.end = window->phys + window->size - 1;
24329175778SLew Glendenning window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
24429175778SLew Glendenning if (request_resource(&iomem_resource, &window->rsrc)) {
24529175778SLew Glendenning window->rsrc.parent = NULL;
246f9a5279cSJoe Perches printk(KERN_DEBUG MOD_NAME ": "
247f9a5279cSJoe Perches "%s(): Unable to register resource %pR - kernel bug?\n",
248f9a5279cSJoe Perches __func__, &window->rsrc);
24929175778SLew Glendenning }
25029175778SLew Glendenning
25129175778SLew Glendenning /* Map the firmware hub into my address space. */
2524bdc0d67SChristoph Hellwig window->virt = ioremap(window->phys, window->size);
25329175778SLew Glendenning if (!window->virt) {
25429175778SLew Glendenning printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
25529175778SLew Glendenning window->phys, window->size);
25629175778SLew Glendenning goto out;
25729175778SLew Glendenning }
25829175778SLew Glendenning
25929175778SLew Glendenning /* Get the first address to look for an rom chip at */
26029175778SLew Glendenning map_top = window->phys;
26129175778SLew Glendenning if ((window->phys & 0x3fffff) != 0) {
26229175778SLew Glendenning /* if not aligned on 4MiB, look 4MiB lower in address space */
26329175778SLew Glendenning map_top = window->phys + 0x400000;
26429175778SLew Glendenning }
26529175778SLew Glendenning #if 1
26629175778SLew Glendenning /* The probe sequence run over the firmware hub lock
26729175778SLew Glendenning * registers sets them to 0x7 (no access).
26829175778SLew Glendenning * (Insane hardware design, but most copied Intel's.)
26929175778SLew Glendenning * ==> Probe at most the last 4M of the address space.
27029175778SLew Glendenning */
27129175778SLew Glendenning if (map_top < 0xffc00000)
27229175778SLew Glendenning map_top = 0xffc00000;
27329175778SLew Glendenning #endif
27429175778SLew Glendenning /* Loop through and look for rom chips */
27529175778SLew Glendenning while ((map_top - 1) < 0xffffffffUL) {
27629175778SLew Glendenning struct cfi_private *cfi;
27729175778SLew Glendenning unsigned long offset;
27829175778SLew Glendenning int i;
27929175778SLew Glendenning
28029175778SLew Glendenning if (!map) {
281*bb89d137SZhen Lei map = kmalloc(sizeof(*map), GFP_KERNEL);
282*bb89d137SZhen Lei if (!map)
28329175778SLew Glendenning goto out;
28429175778SLew Glendenning }
28529175778SLew Glendenning memset(map, 0, sizeof(*map));
28629175778SLew Glendenning INIT_LIST_HEAD(&map->list);
28729175778SLew Glendenning map->map.name = map->map_name;
28829175778SLew Glendenning map->map.phys = map_top;
28929175778SLew Glendenning offset = map_top - window->phys;
29029175778SLew Glendenning map->map.virt = (void __iomem *)
29129175778SLew Glendenning (((unsigned long)(window->virt)) + offset);
29229175778SLew Glendenning map->map.size = 0xffffffffUL - map_top + 1UL;
29329175778SLew Glendenning /* Set the name of the map to the address I am trying */
2945ad0fdc6SAndrew Morton sprintf(map->map_name, "%s @%08Lx",
2955ad0fdc6SAndrew Morton MOD_NAME, (unsigned long long)map->map.phys);
29629175778SLew Glendenning
29729175778SLew Glendenning /* Firmware hubs only use vpp when being programmed
29829175778SLew Glendenning * in a factory setting. So in-place programming
29929175778SLew Glendenning * needs to use a different method.
30029175778SLew Glendenning */
30129175778SLew Glendenning for(map->map.bankwidth = 32; map->map.bankwidth;
30229175778SLew Glendenning map->map.bankwidth >>= 1) {
30329175778SLew Glendenning char **probe_type;
30429175778SLew Glendenning /* Skip bankwidths that are not supported */
30529175778SLew Glendenning if (!map_bankwidth_supported(map->map.bankwidth))
30629175778SLew Glendenning continue;
30729175778SLew Glendenning
30829175778SLew Glendenning /* Setup the map methods */
30929175778SLew Glendenning simple_map_init(&map->map);
31029175778SLew Glendenning
31129175778SLew Glendenning /* Try all of the probe methods */
31229175778SLew Glendenning probe_type = rom_probe_types;
31329175778SLew Glendenning for(; *probe_type; probe_type++) {
31429175778SLew Glendenning map->mtd = do_map_probe(*probe_type, &map->map);
31529175778SLew Glendenning if (map->mtd)
31629175778SLew Glendenning goto found;
31729175778SLew Glendenning }
31829175778SLew Glendenning }
31929175778SLew Glendenning map_top += ROM_PROBE_STEP_SIZE;
32029175778SLew Glendenning continue;
32129175778SLew Glendenning found:
32229175778SLew Glendenning /* Trim the size if we are larger than the map */
32329175778SLew Glendenning if (map->mtd->size > map->map.size) {
32429175778SLew Glendenning printk(KERN_WARNING MOD_NAME
32569423d99SAdrian Hunter " rom(%llu) larger than window(%lu). fixing...\n",
32669423d99SAdrian Hunter (unsigned long long)map->mtd->size, map->map.size);
32729175778SLew Glendenning map->mtd->size = map->map.size;
32829175778SLew Glendenning }
32929175778SLew Glendenning if (window->rsrc.parent) {
33029175778SLew Glendenning /*
33129175778SLew Glendenning * Registering the MTD device in iomem may not be possible
33229175778SLew Glendenning * if there is a BIOS "reserved" and BUSY range. If this
33329175778SLew Glendenning * fails then continue anyway.
33429175778SLew Glendenning */
33529175778SLew Glendenning map->rsrc.name = map->map_name;
33629175778SLew Glendenning map->rsrc.start = map->map.phys;
33729175778SLew Glendenning map->rsrc.end = map->map.phys + map->mtd->size - 1;
33829175778SLew Glendenning map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
33929175778SLew Glendenning if (request_resource(&window->rsrc, &map->rsrc)) {
34029175778SLew Glendenning printk(KERN_ERR MOD_NAME
34129175778SLew Glendenning ": cannot reserve MTD resource\n");
34229175778SLew Glendenning map->rsrc.parent = NULL;
34329175778SLew Glendenning }
34429175778SLew Glendenning }
34529175778SLew Glendenning
34629175778SLew Glendenning /* Make the whole region visible in the map */
34729175778SLew Glendenning map->map.virt = window->virt;
34829175778SLew Glendenning map->map.phys = window->phys;
34929175778SLew Glendenning cfi = map->map.fldrv_priv;
35029175778SLew Glendenning for(i = 0; i < cfi->numchips; i++)
35129175778SLew Glendenning cfi->chips[i].start += offset;
35229175778SLew Glendenning
35329175778SLew Glendenning /* Now that the mtd devices is complete claim and export it */
35429175778SLew Glendenning map->mtd->owner = THIS_MODULE;
355ee0e87b1SJamie Iles if (mtd_device_register(map->mtd, NULL, 0)) {
35629175778SLew Glendenning map_destroy(map->mtd);
35729175778SLew Glendenning map->mtd = NULL;
35829175778SLew Glendenning goto out;
35929175778SLew Glendenning }
36029175778SLew Glendenning
36129175778SLew Glendenning /* Calculate the new value of map_top */
36229175778SLew Glendenning map_top += map->mtd->size;
36329175778SLew Glendenning
36429175778SLew Glendenning /* File away the map structure */
36529175778SLew Glendenning list_add(&map->list, &window->maps);
36629175778SLew Glendenning map = NULL;
36729175778SLew Glendenning }
36829175778SLew Glendenning
36929175778SLew Glendenning out:
37029175778SLew Glendenning /* Free any left over map structures */
37129175778SLew Glendenning kfree(map);
37229175778SLew Glendenning
37329175778SLew Glendenning /* See if I have any map structures */
37429175778SLew Glendenning if (list_empty(&window->maps)) {
37529175778SLew Glendenning esb2rom_cleanup(window);
37629175778SLew Glendenning return -ENODEV;
37729175778SLew Glendenning }
37829175778SLew Glendenning return 0;
37929175778SLew Glendenning }
38029175778SLew Glendenning
esb2rom_remove_one(struct pci_dev * pdev)381810b7e06SBill Pemberton static void esb2rom_remove_one(struct pci_dev *pdev)
38229175778SLew Glendenning {
38329175778SLew Glendenning struct esb2rom_window *window = &esb2rom_window;
38429175778SLew Glendenning esb2rom_cleanup(window);
38529175778SLew Glendenning }
38629175778SLew Glendenning
38701cac4d2SArvind Yadav static const struct pci_device_id esb2rom_pci_tbl[] = {
38829175778SLew Glendenning { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
38929175778SLew Glendenning PCI_ANY_ID, PCI_ANY_ID, },
39029175778SLew Glendenning { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
39129175778SLew Glendenning PCI_ANY_ID, PCI_ANY_ID, },
39229175778SLew Glendenning { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
39329175778SLew Glendenning PCI_ANY_ID, PCI_ANY_ID, },
39429175778SLew Glendenning { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
39529175778SLew Glendenning PCI_ANY_ID, PCI_ANY_ID, },
39629175778SLew Glendenning { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
39729175778SLew Glendenning PCI_ANY_ID, PCI_ANY_ID, },
39829175778SLew Glendenning { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
39929175778SLew Glendenning PCI_ANY_ID, PCI_ANY_ID, },
40029175778SLew Glendenning { 0, },
40129175778SLew Glendenning };
40229175778SLew Glendenning
40329175778SLew Glendenning #if 0
40429175778SLew Glendenning MODULE_DEVICE_TABLE(pci, esb2rom_pci_tbl);
40529175778SLew Glendenning
40629175778SLew Glendenning static struct pci_driver esb2rom_driver = {
40729175778SLew Glendenning .name = MOD_NAME,
40829175778SLew Glendenning .id_table = esb2rom_pci_tbl,
40929175778SLew Glendenning .probe = esb2rom_init_one,
41029175778SLew Glendenning .remove = esb2rom_remove_one,
41129175778SLew Glendenning };
41229175778SLew Glendenning #endif
41329175778SLew Glendenning
init_esb2rom(void)41429175778SLew Glendenning static int __init init_esb2rom(void)
41529175778SLew Glendenning {
41629175778SLew Glendenning struct pci_dev *pdev;
41701cac4d2SArvind Yadav const struct pci_device_id *id;
41829175778SLew Glendenning int retVal;
41929175778SLew Glendenning
42029175778SLew Glendenning pdev = NULL;
42129175778SLew Glendenning for (id = esb2rom_pci_tbl; id->vendor; id++) {
42229175778SLew Glendenning printk(KERN_DEBUG "device id = %x\n", id->device);
423c7438d02SAlan Cox pdev = pci_get_device(id->vendor, id->device, NULL);
42429175778SLew Glendenning if (pdev) {
42529175778SLew Glendenning printk(KERN_DEBUG "matched device = %x\n", id->device);
42629175778SLew Glendenning break;
42729175778SLew Glendenning }
42829175778SLew Glendenning }
42929175778SLew Glendenning if (pdev) {
43029175778SLew Glendenning printk(KERN_DEBUG "matched device id %x\n", id->device);
43129175778SLew Glendenning retVal = esb2rom_init_one(pdev, &esb2rom_pci_tbl[0]);
432c7438d02SAlan Cox pci_dev_put(pdev);
43329175778SLew Glendenning printk(KERN_DEBUG "retVal = %d\n", retVal);
43429175778SLew Glendenning return retVal;
43529175778SLew Glendenning }
43629175778SLew Glendenning return -ENXIO;
43729175778SLew Glendenning #if 0
43829175778SLew Glendenning return pci_register_driver(&esb2rom_driver);
43929175778SLew Glendenning #endif
44029175778SLew Glendenning }
44129175778SLew Glendenning
cleanup_esb2rom(void)44229175778SLew Glendenning static void __exit cleanup_esb2rom(void)
44329175778SLew Glendenning {
44429175778SLew Glendenning esb2rom_remove_one(esb2rom_window.pdev);
44529175778SLew Glendenning }
44629175778SLew Glendenning
44729175778SLew Glendenning module_init(init_esb2rom);
44829175778SLew Glendenning module_exit(cleanup_esb2rom);
44929175778SLew Glendenning
45029175778SLew Glendenning MODULE_LICENSE("GPL");
45129175778SLew Glendenning MODULE_AUTHOR("Lew Glendenning <lglendenning@lnxi.com>");
45229175778SLew Glendenning MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ESB2 southbridge");
453