^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ichxrom.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Normal mappings of chips in physical memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mtd/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mtd/cfi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/mtd/flashchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/pci_ids.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define xstr(s) str(s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define str(s) #s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define MOD_NAME xstr(KBUILD_BASENAME)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define ADDRESS_NAME_LEN 18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define BIOS_CNTL 0x4e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define FWH_DEC_EN1 0xE3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define FWH_DEC_EN2 0xF0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define FWH_SEL1 0xE8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define FWH_SEL2 0xEE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct ichxrom_window {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) void __iomem* virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned long phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct list_head maps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct resource rsrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct pci_dev *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct ichxrom_map_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct map_info map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct resource rsrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static struct ichxrom_window ichxrom_window = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .maps = LIST_HEAD_INIT(ichxrom_window.maps),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static void ichxrom_cleanup(struct ichxrom_window *window)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct ichxrom_map_info *map, *scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) u16 word;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Disable writes through the rom window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) pci_dev_put(window->pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* Free all of the mtd devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) list_for_each_entry_safe(map, scratch, &window->maps, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (map->rsrc.parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) release_resource(&map->rsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) mtd_device_unregister(map->mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) map_destroy(map->mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) list_del(&map->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) kfree(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (window->rsrc.parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) release_resource(&window->rsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (window->virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) iounmap(window->virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) window->virt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) window->phys = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) window->size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) window->pdev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int __init ichxrom_init_one(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) const struct pci_device_id *ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct ichxrom_window *window = &ichxrom_window;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct ichxrom_map_info *map = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned long map_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u8 byte;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) u16 word;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* For now I just handle the ichx and I assume there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * are not a lot of resources up at the top of the address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * space. It is possible to handle other devices in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * top 16MB but it is very painful. Also since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * you can only really attach a FWH to an ICHX there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * a number of simplifications you can make.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * Also you can page firmware hubs if an 8MB window isn't enough
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * but don't currently handle that case either.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) window->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* Find a region continuous to the end of the ROM window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) window->phys = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (byte == 0xff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) window->phys = 0xffc00000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if ((byte & 0x0f) == 0x0f) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) window->phys = 0xff400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) else if ((byte & 0x0e) == 0x0e) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) window->phys = 0xff500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) else if ((byte & 0x0c) == 0x0c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) window->phys = 0xff600000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) else if ((byte & 0x08) == 0x08) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) window->phys = 0xff700000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) else if ((byte & 0xfe) == 0xfe) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) window->phys = 0xffc80000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) else if ((byte & 0xfc) == 0xfc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) window->phys = 0xffd00000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) else if ((byte & 0xf8) == 0xf8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) window->phys = 0xffd80000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) else if ((byte & 0xf0) == 0xf0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) window->phys = 0xffe00000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) else if ((byte & 0xe0) == 0xe0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) window->phys = 0xffe80000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) else if ((byte & 0xc0) == 0xc0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) window->phys = 0xfff00000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) else if ((byte & 0x80) == 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) window->phys = 0xfff80000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (window->phys == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) window->phys -= 0x400000UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) window->size = (0xffffffffUL - window->phys) + 1UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* Enable writes through the rom window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) pci_read_config_word(pdev, BIOS_CNTL, &word);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (!(word & 1) && (word & (1<<1))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* The BIOS will generate an error if I enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * this device, so don't even try.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) pci_write_config_word(pdev, BIOS_CNTL, word | 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * Try to reserve the window mem region. If this fails then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * it is likely due to the window being "reserved" by the BIOS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) window->rsrc.name = MOD_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) window->rsrc.start = window->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) window->rsrc.end = window->phys + window->size - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (request_resource(&iomem_resource, &window->rsrc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) window->rsrc.parent = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) printk(KERN_DEBUG MOD_NAME ": "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) "%s(): Unable to register resource %pR - kernel bug?\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) __func__, &window->rsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* Map the firmware hub into my address space. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) window->virt = ioremap(window->phys, window->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (!window->virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) window->phys, window->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /* Get the first address to look for an rom chip at */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) map_top = window->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if ((window->phys & 0x3fffff) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) map_top = window->phys + 0x400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) #if 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /* The probe sequence run over the firmware hub lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * registers sets them to 0x7 (no access).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * Probe at most the last 4M of the address space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (map_top < 0xffc00000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) map_top = 0xffc00000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* Loop through and look for rom chips */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) while((map_top - 1) < 0xffffffffUL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct cfi_private *cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (!map) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) map = kmalloc(sizeof(*map), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (!map) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) printk(KERN_ERR MOD_NAME ": kmalloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) memset(map, 0, sizeof(*map));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) INIT_LIST_HEAD(&map->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) map->map.name = map->map_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) map->map.phys = map_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) offset = map_top - window->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) map->map.virt = (void __iomem *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) (((unsigned long)(window->virt)) + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) map->map.size = 0xffffffffUL - map_top + 1UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) /* Set the name of the map to the address I am trying */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) sprintf(map->map_name, "%s @%08Lx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) MOD_NAME, (unsigned long long)map->map.phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /* Firmware hubs only use vpp when being programmed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * in a factory setting. So in-place programming
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * needs to use a different method.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) for(map->map.bankwidth = 32; map->map.bankwidth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) map->map.bankwidth >>= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) char **probe_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /* Skip bankwidths that are not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (!map_bankwidth_supported(map->map.bankwidth))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* Setup the map methods */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) simple_map_init(&map->map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /* Try all of the probe methods */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) probe_type = rom_probe_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) for(; *probe_type; probe_type++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) map->mtd = do_map_probe(*probe_type, &map->map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (map->mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) goto found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) map_top += ROM_PROBE_STEP_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) found:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* Trim the size if we are larger than the map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (map->mtd->size > map->map.size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) printk(KERN_WARNING MOD_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) " rom(%llu) larger than window(%lu). fixing...\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) (unsigned long long)map->mtd->size, map->map.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) map->mtd->size = map->map.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (window->rsrc.parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * Registering the MTD device in iomem may not be possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) * if there is a BIOS "reserved" and BUSY range. If this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * fails then continue anyway.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) map->rsrc.name = map->map_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) map->rsrc.start = map->map.phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) map->rsrc.end = map->map.phys + map->mtd->size - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (request_resource(&window->rsrc, &map->rsrc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) printk(KERN_ERR MOD_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) ": cannot reserve MTD resource\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) map->rsrc.parent = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /* Make the whole region visible in the map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) map->map.virt = window->virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) map->map.phys = window->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) cfi = map->map.fldrv_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) for(i = 0; i < cfi->numchips; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) cfi->chips[i].start += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* Now that the mtd devices is complete claim and export it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) map->mtd->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (mtd_device_register(map->mtd, NULL, 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) map_destroy(map->mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) map->mtd = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /* Calculate the new value of map_top */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) map_top += map->mtd->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /* File away the map structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) list_add(&map->list, &window->maps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) map = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /* Free any left over map structures */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) kfree(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /* See if I have any map structures */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (list_empty(&window->maps)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) ichxrom_cleanup(window);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static void ichxrom_remove_one(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) struct ichxrom_window *window = &ichxrom_window;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) ichxrom_cleanup(window);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static const struct pci_device_id ichxrom_pci_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) PCI_ANY_ID, PCI_ANY_ID, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) PCI_ANY_ID, PCI_ANY_ID, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) PCI_ANY_ID, PCI_ANY_ID, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) PCI_ANY_ID, PCI_ANY_ID, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) PCI_ANY_ID, PCI_ANY_ID, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) { 0, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static struct pci_driver ichxrom_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) .name = MOD_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) .id_table = ichxrom_pci_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) .probe = ichxrom_init_one,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) .remove = ichxrom_remove_one,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static int __init init_ichxrom(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct pci_dev *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) const struct pci_device_id *id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) pdev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) for (id = ichxrom_pci_tbl; id->vendor; id++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) pdev = pci_get_device(id->vendor, id->device, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (pdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (pdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return pci_register_driver(&ichxrom_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static void __exit cleanup_ichxrom(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) ichxrom_remove_one(ichxrom_window.pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) module_init(init_ichxrom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) module_exit(cleanup_ichxrom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge");