0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/slab.h>
0013 #include <asm/io.h>
0014 #include <linux/mtd/mtd.h>
0015 #include <linux/mtd/map.h>
0016 #include <linux/mtd/cfi.h>
0017 #include <linux/mtd/flashchip.h>
0018 #include <linux/pci.h>
0019 #include <linux/pci_ids.h>
0020 #include <linux/list.h>
0021
0022
0023 #define xstr(s) str(s)
0024 #define str(s) #s
0025 #define MOD_NAME xstr(KBUILD_BASENAME)
0026
0027 #define ADDRESS_NAME_LEN 18
0028
0029 #define ROM_PROBE_STEP_SIZE (64*1024)
0030
0031 struct amd76xrom_window {
0032 void __iomem *virt;
0033 unsigned long phys;
0034 unsigned long size;
0035 struct list_head maps;
0036 struct resource rsrc;
0037 struct pci_dev *pdev;
0038 };
0039
0040 struct amd76xrom_map_info {
0041 struct list_head list;
0042 struct map_info map;
0043 struct mtd_info *mtd;
0044 struct resource rsrc;
0045 char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
0046 };
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 static uint win_size_bits;
0062 module_param(win_size_bits, uint, 0);
0063 MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x43 byte, normally set by BIOS.");
0064
0065 static struct amd76xrom_window amd76xrom_window = {
0066 .maps = LIST_HEAD_INIT(amd76xrom_window.maps),
0067 };
0068
0069 static void amd76xrom_cleanup(struct amd76xrom_window *window)
0070 {
0071 struct amd76xrom_map_info *map, *scratch;
0072 u8 byte;
0073
0074 if (window->pdev) {
0075
0076 pci_read_config_byte(window->pdev, 0x40, &byte);
0077 pci_write_config_byte(window->pdev, 0x40, byte & ~1);
0078 pci_dev_put(window->pdev);
0079 }
0080
0081
0082 list_for_each_entry_safe(map, scratch, &window->maps, list) {
0083 if (map->rsrc.parent) {
0084 release_resource(&map->rsrc);
0085 }
0086 mtd_device_unregister(map->mtd);
0087 map_destroy(map->mtd);
0088 list_del(&map->list);
0089 kfree(map);
0090 }
0091 if (window->rsrc.parent)
0092 release_resource(&window->rsrc);
0093
0094 if (window->virt) {
0095 iounmap(window->virt);
0096 window->virt = NULL;
0097 window->phys = 0;
0098 window->size = 0;
0099 window->pdev = NULL;
0100 }
0101 }
0102
0103
0104 static int amd76xrom_init_one(struct pci_dev *pdev,
0105 const struct pci_device_id *ent)
0106 {
0107 static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
0108 u8 byte;
0109 struct amd76xrom_window *window = &amd76xrom_window;
0110 struct amd76xrom_map_info *map = NULL;
0111 unsigned long map_top;
0112
0113
0114 window->pdev = pdev;
0115
0116
0117
0118
0119
0120
0121
0122
0123 pci_read_config_byte(pdev, 0x43, &byte);
0124 pci_write_config_byte(pdev, 0x43, byte | win_size_bits );
0125
0126
0127 pci_read_config_byte(pdev, 0x43, &byte);
0128 if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
0129 window->phys = 0xffb00000;
0130 }
0131 else if ((byte & (1<<7)) == (1<<7)) {
0132 window->phys = 0xffc00000;
0133 }
0134 else {
0135 window->phys = 0xffff0000;
0136 }
0137 window->size = 0xffffffffUL - window->phys + 1UL;
0138
0139
0140
0141
0142
0143
0144
0145
0146 window->rsrc.name = MOD_NAME;
0147 window->rsrc.start = window->phys;
0148 window->rsrc.end = window->phys + window->size - 1;
0149 window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0150 if (request_resource(&iomem_resource, &window->rsrc)) {
0151 window->rsrc.parent = NULL;
0152 printk(KERN_ERR MOD_NAME
0153 " %s(): Unable to register resource %pR - kernel bug?\n",
0154 __func__, &window->rsrc);
0155 return -EBUSY;
0156 }
0157
0158
0159
0160 pci_read_config_byte(pdev, 0x40, &byte);
0161 pci_write_config_byte(pdev, 0x40, byte | 1);
0162
0163
0164
0165
0166 window->virt = ioremap(window->phys, window->size);
0167 if (!window->virt) {
0168 printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
0169 window->phys, window->size);
0170 goto out;
0171 }
0172
0173
0174 map_top = window->phys;
0175 #if 1
0176
0177
0178
0179
0180 if (map_top < 0xffc00000) {
0181 map_top = 0xffc00000;
0182 }
0183 #endif
0184
0185 while((map_top - 1) < 0xffffffffUL) {
0186 struct cfi_private *cfi;
0187 unsigned long offset;
0188 int i;
0189
0190 if (!map) {
0191 map = kmalloc(sizeof(*map), GFP_KERNEL);
0192 if (!map)
0193 goto out;
0194 }
0195 memset(map, 0, sizeof(*map));
0196 INIT_LIST_HEAD(&map->list);
0197 map->map.name = map->map_name;
0198 map->map.phys = map_top;
0199 offset = map_top - window->phys;
0200 map->map.virt = (void __iomem *)
0201 (((unsigned long)(window->virt)) + offset);
0202 map->map.size = 0xffffffffUL - map_top + 1UL;
0203
0204 sprintf(map->map_name, "%s @%08Lx",
0205 MOD_NAME, (unsigned long long)map->map.phys);
0206
0207
0208 for(map->map.bankwidth = 32; map->map.bankwidth;
0209 map->map.bankwidth >>= 1)
0210 {
0211 char **probe_type;
0212
0213 if (!map_bankwidth_supported(map->map.bankwidth))
0214 continue;
0215
0216
0217 simple_map_init(&map->map);
0218
0219
0220 probe_type = rom_probe_types;
0221 for(; *probe_type; probe_type++) {
0222 map->mtd = do_map_probe(*probe_type, &map->map);
0223 if (map->mtd)
0224 goto found;
0225 }
0226 }
0227 map_top += ROM_PROBE_STEP_SIZE;
0228 continue;
0229 found:
0230
0231 if (map->mtd->size > map->map.size) {
0232 printk(KERN_WARNING MOD_NAME
0233 " rom(%llu) larger than window(%lu). fixing...\n",
0234 (unsigned long long)map->mtd->size, map->map.size);
0235 map->mtd->size = map->map.size;
0236 }
0237 if (window->rsrc.parent) {
0238
0239
0240
0241
0242
0243 map->rsrc.name = map->map_name;
0244 map->rsrc.start = map->map.phys;
0245 map->rsrc.end = map->map.phys + map->mtd->size - 1;
0246 map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0247 if (request_resource(&window->rsrc, &map->rsrc)) {
0248 printk(KERN_ERR MOD_NAME
0249 ": cannot reserve MTD resource\n");
0250 map->rsrc.parent = NULL;
0251 }
0252 }
0253
0254
0255 map->map.virt = window->virt;
0256 map->map.phys = window->phys;
0257 cfi = map->map.fldrv_priv;
0258 for(i = 0; i < cfi->numchips; i++) {
0259 cfi->chips[i].start += offset;
0260 }
0261
0262
0263 map->mtd->owner = THIS_MODULE;
0264 if (mtd_device_register(map->mtd, NULL, 0)) {
0265 map_destroy(map->mtd);
0266 map->mtd = NULL;
0267 goto out;
0268 }
0269
0270
0271
0272 map_top += map->mtd->size;
0273
0274
0275 list_add(&map->list, &window->maps);
0276 map = NULL;
0277 }
0278
0279 out:
0280
0281 kfree(map);
0282
0283 if (list_empty(&window->maps)) {
0284 amd76xrom_cleanup(window);
0285 return -ENODEV;
0286 }
0287 return 0;
0288 }
0289
0290
0291 static void amd76xrom_remove_one(struct pci_dev *pdev)
0292 {
0293 struct amd76xrom_window *window = &amd76xrom_window;
0294
0295 amd76xrom_cleanup(window);
0296 }
0297
0298 static const struct pci_device_id amd76xrom_pci_tbl[] = {
0299 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,
0300 PCI_ANY_ID, PCI_ANY_ID, },
0301 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,
0302 PCI_ANY_ID, PCI_ANY_ID, },
0303 { PCI_VENDOR_ID_AMD, 0x7468 },
0304 { 0, }
0305 };
0306
0307 MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
0308
0309 #if 0
0310 static struct pci_driver amd76xrom_driver = {
0311 .name = MOD_NAME,
0312 .id_table = amd76xrom_pci_tbl,
0313 .probe = amd76xrom_init_one,
0314 .remove = amd76xrom_remove_one,
0315 };
0316 #endif
0317
0318 static int __init init_amd76xrom(void)
0319 {
0320 struct pci_dev *pdev;
0321 const struct pci_device_id *id;
0322 pdev = NULL;
0323 for(id = amd76xrom_pci_tbl; id->vendor; id++) {
0324 pdev = pci_get_device(id->vendor, id->device, NULL);
0325 if (pdev) {
0326 break;
0327 }
0328 }
0329 if (pdev) {
0330 return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
0331 }
0332 return -ENXIO;
0333 #if 0
0334 return pci_register_driver(&amd76xrom_driver);
0335 #endif
0336 }
0337
0338 static void __exit cleanup_amd76xrom(void)
0339 {
0340 amd76xrom_remove_one(amd76xrom_window.pdev);
0341 }
0342
0343 module_init(init_amd76xrom);
0344 module_exit(cleanup_amd76xrom);
0345
0346 MODULE_LICENSE("GPL");
0347 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
0348 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");