diff options
-rw-r--r-- | arch/x86/kernel/pci-calgary_64.c | 85 | ||||
-rw-r--r-- | include/linux/crash_dump.h | 8 |
2 files changed, 87 insertions, 6 deletions
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 151f2d171f7c..19e7fc7c2c4f 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <linux/crash_dump.h> | ||
32 | #include <linux/dma-mapping.h> | 33 | #include <linux/dma-mapping.h> |
33 | #include <linux/bitops.h> | 34 | #include <linux/bitops.h> |
34 | #include <linux/pci_ids.h> | 35 | #include <linux/pci_ids.h> |
@@ -167,6 +168,8 @@ static void calgary_dump_error_regs(struct iommu_table *tbl); | |||
167 | static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev); | 168 | static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev); |
168 | static void calioc2_tce_cache_blast(struct iommu_table *tbl); | 169 | static void calioc2_tce_cache_blast(struct iommu_table *tbl); |
169 | static void calioc2_dump_error_regs(struct iommu_table *tbl); | 170 | static void calioc2_dump_error_regs(struct iommu_table *tbl); |
171 | static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl); | ||
172 | static void get_tce_space_from_tar(void); | ||
170 | 173 | ||
171 | static struct cal_chipset_ops calgary_chip_ops = { | 174 | static struct cal_chipset_ops calgary_chip_ops = { |
172 | .handle_quirks = calgary_handle_quirks, | 175 | .handle_quirks = calgary_handle_quirks, |
@@ -830,7 +833,11 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar) | |||
830 | 833 | ||
831 | tbl = pci_iommu(dev->bus); | 834 | tbl = pci_iommu(dev->bus); |
832 | tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space; | 835 | tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space; |
833 | tce_free(tbl, 0, tbl->it_size); | 836 | |
837 | if (is_kdump_kernel()) | ||
838 | calgary_init_bitmap_from_tce_table(tbl); | ||
839 | else | ||
840 | tce_free(tbl, 0, tbl->it_size); | ||
834 | 841 | ||
835 | if (is_calgary(dev->device)) | 842 | if (is_calgary(dev->device)) |
836 | tbl->chip_ops = &calgary_chip_ops; | 843 | tbl->chip_ops = &calgary_chip_ops; |
@@ -1209,6 +1216,10 @@ static int __init calgary_init(void) | |||
1209 | if (ret) | 1216 | if (ret) |
1210 | return ret; | 1217 | return ret; |
1211 | 1218 | ||
1219 | /* Purely for kdump kernel case */ | ||
1220 | if (is_kdump_kernel()) | ||
1221 | get_tce_space_from_tar(); | ||
1222 | |||
1212 | do { | 1223 | do { |
1213 | dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev); | 1224 | dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev); |
1214 | if (!dev) | 1225 | if (!dev) |
@@ -1339,6 +1350,61 @@ static int __init calgary_bus_has_devices(int bus, unsigned short pci_dev) | |||
1339 | return (val != 0xffffffff); | 1350 | return (val != 0xffffffff); |
1340 | } | 1351 | } |
1341 | 1352 | ||
1353 | /* | ||
1354 | * calgary_init_bitmap_from_tce_table(): | ||
1355 | * Funtion for kdump case. In the second/kdump kernel initialize | ||
1356 | * the bitmap based on the tce table entries obtained from first kernel | ||
1357 | */ | ||
1358 | static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl) | ||
1359 | { | ||
1360 | u64 *tp; | ||
1361 | unsigned int index; | ||
1362 | tp = ((u64 *)tbl->it_base); | ||
1363 | for (index = 0 ; index < tbl->it_size; index++) { | ||
1364 | if (*tp != 0x0) | ||
1365 | set_bit(index, tbl->it_map); | ||
1366 | tp++; | ||
1367 | } | ||
1368 | } | ||
1369 | |||
1370 | /* | ||
1371 | * get_tce_space_from_tar(): | ||
1372 | * Function for kdump case. Get the tce tables from first kernel | ||
1373 | * by reading the contents of the base adress register of calgary iommu | ||
1374 | */ | ||
1375 | static void get_tce_space_from_tar() | ||
1376 | { | ||
1377 | int bus; | ||
1378 | void __iomem *target; | ||
1379 | unsigned long tce_space; | ||
1380 | |||
1381 | for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) { | ||
1382 | struct calgary_bus_info *info = &bus_info[bus]; | ||
1383 | unsigned short pci_device; | ||
1384 | u32 val; | ||
1385 | |||
1386 | val = read_pci_config(bus, 0, 0, 0); | ||
1387 | pci_device = (val & 0xFFFF0000) >> 16; | ||
1388 | |||
1389 | if (!is_cal_pci_dev(pci_device)) | ||
1390 | continue; | ||
1391 | if (info->translation_disabled) | ||
1392 | continue; | ||
1393 | |||
1394 | if (calgary_bus_has_devices(bus, pci_device) || | ||
1395 | translate_empty_slots) { | ||
1396 | target = calgary_reg(bus_info[bus].bbar, | ||
1397 | tar_offset(bus)); | ||
1398 | tce_space = be64_to_cpu(readq(target)); | ||
1399 | tce_space = tce_space & TAR_SW_BITS; | ||
1400 | |||
1401 | tce_space = tce_space & (~specified_table_size); | ||
1402 | info->tce_space = (u64 *)__va(tce_space); | ||
1403 | } | ||
1404 | } | ||
1405 | return; | ||
1406 | } | ||
1407 | |||
1342 | void __init detect_calgary(void) | 1408 | void __init detect_calgary(void) |
1343 | { | 1409 | { |
1344 | int bus; | 1410 | int bus; |
@@ -1394,7 +1460,8 @@ void __init detect_calgary(void) | |||
1394 | return; | 1460 | return; |
1395 | } | 1461 | } |
1396 | 1462 | ||
1397 | specified_table_size = determine_tce_table_size(max_pfn * PAGE_SIZE); | 1463 | specified_table_size = determine_tce_table_size((is_kdump_kernel() ? |
1464 | saved_max_pfn : max_pfn) * PAGE_SIZE); | ||
1398 | 1465 | ||
1399 | for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) { | 1466 | for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) { |
1400 | struct calgary_bus_info *info = &bus_info[bus]; | 1467 | struct calgary_bus_info *info = &bus_info[bus]; |
@@ -1412,10 +1479,16 @@ void __init detect_calgary(void) | |||
1412 | 1479 | ||
1413 | if (calgary_bus_has_devices(bus, pci_device) || | 1480 | if (calgary_bus_has_devices(bus, pci_device) || |
1414 | translate_empty_slots) { | 1481 | translate_empty_slots) { |
1415 | tbl = alloc_tce_table(); | 1482 | /* |
1416 | if (!tbl) | 1483 | * If it is kdump kernel, find and use tce tables |
1417 | goto cleanup; | 1484 | * from first kernel, else allocate tce tables here |
1418 | info->tce_space = tbl; | 1485 | */ |
1486 | if (!is_kdump_kernel()) { | ||
1487 | tbl = alloc_tce_table(); | ||
1488 | if (!tbl) | ||
1489 | goto cleanup; | ||
1490 | info->tce_space = tbl; | ||
1491 | } | ||
1419 | calgary_found = 1; | 1492 | calgary_found = 1; |
1420 | } | 1493 | } |
1421 | } | 1494 | } |
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h index 22c7ac5cd80c..6cd39a927e1f 100644 --- a/include/linux/crash_dump.h +++ b/include/linux/crash_dump.h | |||
@@ -22,5 +22,13 @@ extern struct proc_dir_entry *proc_vmcore; | |||
22 | 22 | ||
23 | #define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x)) | 23 | #define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x)) |
24 | 24 | ||
25 | static inline int is_kdump_kernel(void) | ||
26 | { | ||
27 | return (elfcorehdr_addr != ELFCORE_ADDR_MAX) ? 1 : 0; | ||
28 | } | ||
29 | #else /* !CONFIG_CRASH_DUMP */ | ||
30 | static inline int is_kdump_kernel(void) { return 0; } | ||
25 | #endif /* CONFIG_CRASH_DUMP */ | 31 | #endif /* CONFIG_CRASH_DUMP */ |
32 | |||
33 | extern unsigned long saved_max_pfn; | ||
26 | #endif /* LINUX_CRASHDUMP_H */ | 34 | #endif /* LINUX_CRASHDUMP_H */ |