aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/pci-calgary_64.c85
-rw-r--r--include/linux/crash_dump.h8
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);
167static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev); 168static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
168static void calioc2_tce_cache_blast(struct iommu_table *tbl); 169static void calioc2_tce_cache_blast(struct iommu_table *tbl);
169static void calioc2_dump_error_regs(struct iommu_table *tbl); 170static void calioc2_dump_error_regs(struct iommu_table *tbl);
171static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl);
172static void get_tce_space_from_tar(void);
170 173
171static struct cal_chipset_ops calgary_chip_ops = { 174static 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 */
1358static 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 */
1375static 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
1342void __init detect_calgary(void) 1408void __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
25static inline int is_kdump_kernel(void)
26{
27 return (elfcorehdr_addr != ELFCORE_ADDR_MAX) ? 1 : 0;
28}
29#else /* !CONFIG_CRASH_DUMP */
30static inline int is_kdump_kernel(void) { return 0; }
25#endif /* CONFIG_CRASH_DUMP */ 31#endif /* CONFIG_CRASH_DUMP */
32
33extern unsigned long saved_max_pfn;
26#endif /* LINUX_CRASHDUMP_H */ 34#endif /* LINUX_CRASHDUMP_H */