Re: [RFC] [Patch] calgary iommu: Use the first kernel's tce tablesin kdump

From: Chandru
Date: Mon Mar 10 2008 - 09:20:41 EST


Chandru wrote:
Hi Muli,

I have tried to work with CCR ,CSR, CSMR, CSAR, CFGRW, GBRERRM registers but have been unable to make calgary generate an exception upon error condition. In alloc_tce_table() , I am setting WRITE_ONLY access permission bit to tce entries but it isn't helping. Would you kindly let me know how we can make calgary to generate an exception in error conditions ?.

Thanks,
Chandru


Hello Andrew,

Could you pls consider the attached patch for inclusion in mainline.

Thanks,
Chandru

Signed-off-by: Chandru S <chandru@xxxxxxxxxx>
---

--- arch/x86/kernel/pci-calgary_64.c.orig 2008-03-10 15:54:08.000000000 +0530
+++ arch/x86/kernel/pci-calgary_64.c 2008-03-10 16:34:20.000000000 +0530
@@ -36,6 +36,7 @@
#include <linux/delay.h>
#include <linux/scatterlist.h>
#include <linux/iommu-helper.h>
+#include <linux/crash_dump.h>
#include <asm/gart.h>
#include <asm/calgary.h>
#include <asm/tce.h>
@@ -166,6 +167,8 @@ static void calgary_dump_error_regs(stru
static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
static void calioc2_tce_cache_blast(struct iommu_table *tbl);
static void calioc2_dump_error_regs(struct iommu_table *tbl);
+static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl);
+static void grab_tce_space_from_tar(void);

static struct cal_chipset_ops calgary_chip_ops = {
.handle_quirks = calgary_handle_quirks,
@@ -828,7 +831,11 @@ static int __init calgary_setup_tar(stru

tbl = pci_iommu(dev->bus);
tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
- tce_free(tbl, 0, tbl->it_size);
+
+ if (is_kdump_kernel())
+ calgary_init_bitmap_from_tce_table(tbl);
+ else
+ tce_free(tbl, 0, tbl->it_size);

if (is_calgary(dev->device))
tbl->chip_ops = &calgary_chip_ops;
@@ -1186,6 +1193,9 @@ static int __init calgary_locate_bbars(v
}
}

+ if (is_kdump_kernel())
+ grab_tce_space_from_tar();
+
return 0;

error:
@@ -1276,6 +1286,24 @@ static inline int __init determine_tce_t
return ret;
}

+/*
+ * calgary_init_bitmap_from_tce_table():
+ * Funtion for kdump case. In the second/kdump kernel initialize
+ * the bitmap based on the tce table entries obtained from first kernel
+ */
+static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl)
+{
+ u64 *tp;
+ unsigned int index;
+ tp = ((u64 *)tbl->it_base);
+ for (index = 0 ; index < tbl->it_size; index++) {
+ if (*tp != 0x0)
+ set_bit(index, tbl->it_map);
+
+ tp++;
+ }
+}
+
static int __init build_detail_arrays(void)
{
unsigned long ptr;
@@ -1338,12 +1366,52 @@ static int __init calgary_bus_has_device
return (val != 0xffffffff);
}

+/*
+ * grab_tce_space_from_tar():
+ * Function for kdump case. Grab the tce tables from first kernel
+ * by reading the contents of the base adress register of calgary iommu
+ */
+static void grab_tce_space_from_tar()
+{
+ int bus;
+ void __iomem *target;
+ unsigned long tce_space;
+
+ for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
+ struct calgary_bus_info *info = &bus_info[bus];
+ unsigned short pci_device;
+ u32 val;
+
+ val = read_pci_config(bus, 0, 0, 0);
+ pci_device = (val & 0xFFFF0000) >> 16;
+
+ if (!is_cal_pci_dev(pci_device))
+ continue;
+
+ if (info->translation_disabled)
+ continue;
+
+ if (calgary_bus_has_devices(bus, pci_device) ||
+ translate_empty_slots) {
+ target = calgary_reg(bus_info[bus].bbar,
+ tar_offset(bus));
+ tce_space = be64_to_cpu(readq(target));
+ tce_space = tce_space & TAR_SW_BITS;
+
+ BUG_ON(specified_table_size > TCE_TABLE_SIZE_8M);
+
+ tce_space = tce_space & (~specified_table_size);
+ info->tce_space = (u64 *)__va(tce_space);
+ }
+ }
+}
+
void __init detect_calgary(void)
{
int bus;
void *tbl;
int calgary_found = 0;
- unsigned long ptr;
+ unsigned long ptr, max_pfn;
unsigned int offset, prev_offset;
int ret;

@@ -1393,7 +1461,8 @@ void __init detect_calgary(void)
return;
}

- specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
+ max_pfn = is_kdump_kernel() ? saved_max_pfn : end_pfn ;
+ specified_table_size = determine_tce_table_size(max_pfn * PAGE_SIZE);

for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
struct calgary_bus_info *info = &bus_info[bus];
@@ -1411,10 +1480,16 @@ void __init detect_calgary(void)

if (calgary_bus_has_devices(bus, pci_device) ||
translate_empty_slots) {
- tbl = alloc_tce_table();
- if (!tbl)
- goto cleanup;
- info->tce_space = tbl;
+ /*
+ * If this is a kdump kernel find and use
+ * the tce tables from first kernel
+ */
+ if (!is_kdump_kernel()) {
+ tbl = alloc_tce_table();
+ if (!tbl)
+ goto cleanup;
+ info->tce_space = tbl;
+ }
calgary_found = 1;
}
}
--- include/linux/crash_dump.h.orig 2008-03-10 15:54:33.000000000 +0530
+++ include/linux/crash_dump.h 2008-03-10 16:30:12.000000000 +0530
@@ -21,6 +21,13 @@ extern struct proc_dir_entry *proc_vmcor
#endif

#define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x))
+extern unsigned long saved_max_pfn;
+static inline int is_kdump_kernel(void)
+{
+ return (elfcorehdr_addr != ELFCORE_ADDR_MAX) ? 1 : 0 ;
+}
+#else /* !CONFIG_CRASH_DUMP */
+static inline is_kdump_kernel(void) { return 0; }

#endif /* CONFIG_CRASH_DUMP */
#endif /* LINUX_CRASHDUMP_H */


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/