1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2c9c2877dSHelge Deller /* 3c9c2877dSHelge Deller * Page Deallocation Table (PDT) support 4c9c2877dSHelge Deller * 554ac8fcbSHelge Deller * The Page Deallocation Table (PDT) is maintained by firmware and holds a 654ac8fcbSHelge Deller * list of memory addresses in which memory errors were detected. 754ac8fcbSHelge Deller * The list contains both single-bit (correctable) and double-bit 854ac8fcbSHelge Deller * (uncorrectable) errors. 9c9c2877dSHelge Deller * 10c9c2877dSHelge Deller * Copyright 2017 by Helge Deller <deller@gmx.de> 11c9c2877dSHelge Deller * 1254ac8fcbSHelge Deller * possible future enhancements: 1354ac8fcbSHelge Deller * - add userspace interface via procfs or sysfs to clear PDT 14c9c2877dSHelge Deller */ 15c9c2877dSHelge Deller 16c9c2877dSHelge Deller #include <linux/memblock.h> 17c9c2877dSHelge Deller #include <linux/seq_file.h> 1854ac8fcbSHelge Deller #include <linux/kthread.h> 19*954b41beSHelge Deller #include <linux/proc_fs.h> 20ea697648SHelge Deller #include <linux/initrd.h> 2165fddcfcSMike Rapoport #include <linux/pgtable.h> 22d027122dSNaoya Horiguchi #include <linux/mm.h> 23c9c2877dSHelge Deller 24c9c2877dSHelge Deller #include <asm/pdc.h> 25c9c2877dSHelge Deller #include <asm/pdcpat.h> 26c9c2877dSHelge Deller #include <asm/sections.h> 27c4551d1bSHelge Deller #include <asm/pgtable.h> 28c9c2877dSHelge Deller 29c9c2877dSHelge Deller enum pdt_access_type { 30c9c2877dSHelge Deller PDT_NONE, 31c9c2877dSHelge Deller PDT_PDC, 32c9c2877dSHelge Deller PDT_PAT_NEW, 3354ac8fcbSHelge Deller PDT_PAT_CELL 34c9c2877dSHelge Deller }; 35c9c2877dSHelge Deller 36c9c2877dSHelge Deller static enum pdt_access_type pdt_type; 37c9c2877dSHelge Deller 3854ac8fcbSHelge Deller /* PDT poll interval: 1 minute if errors, 5 minutes if everything OK. */ 3954ac8fcbSHelge Deller #define PDT_POLL_INTERVAL_DEFAULT (5*60*HZ) 4054ac8fcbSHelge Deller #define PDT_POLL_INTERVAL_SHORT (1*60*HZ) 4154ac8fcbSHelge Deller static unsigned long pdt_poll_interval = PDT_POLL_INTERVAL_DEFAULT; 4254ac8fcbSHelge Deller 43c9c2877dSHelge Deller /* global PDT status information */ 44c9c2877dSHelge Deller static struct pdc_mem_retinfo pdt_status; 45c9c2877dSHelge Deller 46c9c2877dSHelge Deller #define MAX_PDT_TABLE_SIZE PAGE_SIZE 47c9c2877dSHelge Deller #define MAX_PDT_ENTRIES (MAX_PDT_TABLE_SIZE / sizeof(unsigned long)) 48c9c2877dSHelge Deller static unsigned long pdt_entry[MAX_PDT_ENTRIES] __page_aligned_bss; 49c9c2877dSHelge Deller 5054ac8fcbSHelge Deller /* 5154ac8fcbSHelge Deller * Constants for the pdt_entry format: 5254ac8fcbSHelge Deller * A pdt_entry holds the physical address in bits 0-57, bits 58-61 are 5354ac8fcbSHelge Deller * reserved, bit 62 is the perm bit and bit 63 is the error_type bit. 5454ac8fcbSHelge Deller * The perm bit indicates whether the error have been verified as a permanent 5554ac8fcbSHelge Deller * error (value of 1) or has not been verified, and may be transient (value 5654ac8fcbSHelge Deller * of 0). The error_type bit indicates whether the error is a single bit error 5754ac8fcbSHelge Deller * (value of 1) or a multiple bit error. 5854ac8fcbSHelge Deller * On non-PAT machines phys_addr is encoded in bits 0-59 and error_type in bit 5954ac8fcbSHelge Deller * 63. Those machines don't provide the perm bit. 6054ac8fcbSHelge Deller */ 6154ac8fcbSHelge Deller 6254ac8fcbSHelge Deller #define PDT_ADDR_PHYS_MASK (pdt_type != PDT_PDC ? ~0x3f : ~0x0f) 6354ac8fcbSHelge Deller #define PDT_ADDR_PERM_ERR (pdt_type != PDT_PDC ? 2UL : 0UL) 6454ac8fcbSHelge Deller #define PDT_ADDR_SINGLE_ERR 1UL 65c9c2877dSHelge Deller 66c9c2877dSHelge Deller /* report PDT entries via /proc/meminfo */ 67c9c2877dSHelge Deller void arch_report_meminfo(struct seq_file *m) 68c9c2877dSHelge Deller { 69c9c2877dSHelge Deller if (pdt_type == PDT_NONE) 70c9c2877dSHelge Deller return; 71c9c2877dSHelge Deller 72c9c2877dSHelge Deller seq_printf(m, "PDT_max_entries: %7lu\n", 73c9c2877dSHelge Deller pdt_status.pdt_size); 74c9c2877dSHelge Deller seq_printf(m, "PDT_cur_entries: %7lu\n", 75c9c2877dSHelge Deller pdt_status.pdt_entries); 76c9c2877dSHelge Deller } 77c9c2877dSHelge Deller 7854ac8fcbSHelge Deller static int get_info_pat_new(void) 7954ac8fcbSHelge Deller { 8054ac8fcbSHelge Deller struct pdc_pat_mem_retinfo pat_rinfo; 8154ac8fcbSHelge Deller int ret; 8254ac8fcbSHelge Deller 8354ac8fcbSHelge Deller /* newer PAT machines like C8000 report info for all cells */ 8454ac8fcbSHelge Deller if (is_pdc_pat()) 8554ac8fcbSHelge Deller ret = pdc_pat_mem_pdt_info(&pat_rinfo); 8654ac8fcbSHelge Deller else 8754ac8fcbSHelge Deller return PDC_BAD_PROC; 8854ac8fcbSHelge Deller 8954ac8fcbSHelge Deller pdt_status.pdt_size = pat_rinfo.max_pdt_entries; 9054ac8fcbSHelge Deller pdt_status.pdt_entries = pat_rinfo.current_pdt_entries; 9154ac8fcbSHelge Deller pdt_status.pdt_status = 0; 9254ac8fcbSHelge Deller pdt_status.first_dbe_loc = pat_rinfo.first_dbe_loc; 9354ac8fcbSHelge Deller pdt_status.good_mem = pat_rinfo.good_mem; 9454ac8fcbSHelge Deller 9554ac8fcbSHelge Deller return ret; 9654ac8fcbSHelge Deller } 9754ac8fcbSHelge Deller 9854ac8fcbSHelge Deller static int get_info_pat_cell(void) 9954ac8fcbSHelge Deller { 10054ac8fcbSHelge Deller struct pdc_pat_mem_cell_pdt_retinfo cell_rinfo; 10154ac8fcbSHelge Deller int ret; 10254ac8fcbSHelge Deller 10354ac8fcbSHelge Deller /* older PAT machines like rp5470 report cell info only */ 10454ac8fcbSHelge Deller if (is_pdc_pat()) 10554ac8fcbSHelge Deller ret = pdc_pat_mem_pdt_cell_info(&cell_rinfo, parisc_cell_num); 10654ac8fcbSHelge Deller else 10754ac8fcbSHelge Deller return PDC_BAD_PROC; 10854ac8fcbSHelge Deller 10954ac8fcbSHelge Deller pdt_status.pdt_size = cell_rinfo.max_pdt_entries; 11054ac8fcbSHelge Deller pdt_status.pdt_entries = cell_rinfo.current_pdt_entries; 11154ac8fcbSHelge Deller pdt_status.pdt_status = 0; 11254ac8fcbSHelge Deller pdt_status.first_dbe_loc = cell_rinfo.first_dbe_loc; 11354ac8fcbSHelge Deller pdt_status.good_mem = cell_rinfo.good_mem; 11454ac8fcbSHelge Deller 11554ac8fcbSHelge Deller return ret; 11654ac8fcbSHelge Deller } 11754ac8fcbSHelge Deller 11854ac8fcbSHelge Deller static void report_mem_err(unsigned long pde) 11954ac8fcbSHelge Deller { 12054ac8fcbSHelge Deller struct pdc_pat_mem_phys_mem_location loc; 12154ac8fcbSHelge Deller unsigned long addr; 12254ac8fcbSHelge Deller char dimm_txt[32]; 12354ac8fcbSHelge Deller 12454ac8fcbSHelge Deller addr = pde & PDT_ADDR_PHYS_MASK; 12554ac8fcbSHelge Deller 12654ac8fcbSHelge Deller /* show DIMM slot description on PAT machines */ 12754ac8fcbSHelge Deller if (is_pdc_pat()) { 12854ac8fcbSHelge Deller pdc_pat_mem_get_dimm_phys_location(&loc, addr); 12954ac8fcbSHelge Deller sprintf(dimm_txt, "DIMM slot %02x, ", loc.dimm_slot); 13054ac8fcbSHelge Deller } else 13154ac8fcbSHelge Deller dimm_txt[0] = 0; 13254ac8fcbSHelge Deller 13354ac8fcbSHelge Deller pr_warn("PDT: BAD MEMORY at 0x%08lx, %s%s%s-bit error.\n", 13454ac8fcbSHelge Deller addr, dimm_txt, 13554ac8fcbSHelge Deller pde & PDT_ADDR_PERM_ERR ? "permanent ":"", 13654ac8fcbSHelge Deller pde & PDT_ADDR_SINGLE_ERR ? "single":"multi"); 13754ac8fcbSHelge Deller } 13854ac8fcbSHelge Deller 13954ac8fcbSHelge Deller 140c9c2877dSHelge Deller /* 141c9c2877dSHelge Deller * pdc_pdt_init() 142c9c2877dSHelge Deller * 143c9c2877dSHelge Deller * Initialize kernel PDT structures, read initial PDT table from firmware, 144c9c2877dSHelge Deller * report all current PDT entries and mark bad memory with memblock_reserve() 145c9c2877dSHelge Deller * to avoid that the kernel will use broken memory areas. 146c9c2877dSHelge Deller * 147c9c2877dSHelge Deller */ 148c9c2877dSHelge Deller void __init pdc_pdt_init(void) 149c9c2877dSHelge Deller { 150c9c2877dSHelge Deller int ret, i; 151c9c2877dSHelge Deller unsigned long entries; 152c9c2877dSHelge Deller struct pdc_mem_read_pdt pdt_read_ret; 153c9c2877dSHelge Deller 154c9c2877dSHelge Deller pdt_type = PDT_PAT_NEW; 15554ac8fcbSHelge Deller ret = get_info_pat_new(); 15654ac8fcbSHelge Deller 15754ac8fcbSHelge Deller if (ret != PDC_OK) { 15854ac8fcbSHelge Deller pdt_type = PDT_PAT_CELL; 15954ac8fcbSHelge Deller ret = get_info_pat_cell(); 16054ac8fcbSHelge Deller } 16154ac8fcbSHelge Deller 16254ac8fcbSHelge Deller if (ret != PDC_OK) { 163c9c2877dSHelge Deller pdt_type = PDT_PDC; 16454ac8fcbSHelge Deller /* non-PAT machines provide the standard PDC call */ 165c9c2877dSHelge Deller ret = pdc_mem_pdt_info(&pdt_status); 166c9c2877dSHelge Deller } 167c9c2877dSHelge Deller 168c9c2877dSHelge Deller if (ret != PDC_OK) { 169c9c2877dSHelge Deller pdt_type = PDT_NONE; 170c9c2877dSHelge Deller pr_info("PDT: Firmware does not provide any page deallocation" 171c9c2877dSHelge Deller " information.\n"); 172c9c2877dSHelge Deller return; 173c9c2877dSHelge Deller } 174c9c2877dSHelge Deller 175c9c2877dSHelge Deller entries = pdt_status.pdt_entries; 17654ac8fcbSHelge Deller if (WARN_ON(entries > MAX_PDT_ENTRIES)) 17754ac8fcbSHelge Deller entries = pdt_status.pdt_entries = MAX_PDT_ENTRIES; 178c9c2877dSHelge Deller 17954ac8fcbSHelge Deller pr_info("PDT: type %s, size %lu, entries %lu, status %lu, dbe_loc 0x%lx," 18054ac8fcbSHelge Deller " good_mem %lu MB\n", 18154ac8fcbSHelge Deller pdt_type == PDT_PDC ? __stringify(PDT_PDC) : 18254ac8fcbSHelge Deller pdt_type == PDT_PAT_CELL ? __stringify(PDT_PAT_CELL) 18354ac8fcbSHelge Deller : __stringify(PDT_PAT_NEW), 184c9c2877dSHelge Deller pdt_status.pdt_size, pdt_status.pdt_entries, 185c9c2877dSHelge Deller pdt_status.pdt_status, pdt_status.first_dbe_loc, 18654ac8fcbSHelge Deller pdt_status.good_mem / 1024 / 1024); 187c9c2877dSHelge Deller 188c9c2877dSHelge Deller if (entries == 0) { 189c9c2877dSHelge Deller pr_info("PDT: Firmware reports all memory OK.\n"); 190c9c2877dSHelge Deller return; 191c9c2877dSHelge Deller } 192c9c2877dSHelge Deller 193c9c2877dSHelge Deller if (pdt_status.first_dbe_loc && 194c9c2877dSHelge Deller pdt_status.first_dbe_loc <= __pa((unsigned long)&_end)) 195c9c2877dSHelge Deller pr_crit("CRITICAL: Bad memory inside kernel image memory area!\n"); 196c9c2877dSHelge Deller 197c9c2877dSHelge Deller pr_warn("PDT: Firmware reports %lu entries of faulty memory:\n", 198c9c2877dSHelge Deller entries); 199c9c2877dSHelge Deller 200c9c2877dSHelge Deller if (pdt_type == PDT_PDC) 201c9c2877dSHelge Deller ret = pdc_mem_pdt_read_entries(&pdt_read_ret, pdt_entry); 202c9c2877dSHelge Deller else { 203c9c2877dSHelge Deller #ifdef CONFIG_64BIT 204c9c2877dSHelge Deller struct pdc_pat_mem_read_pd_retinfo pat_pret; 205c9c2877dSHelge Deller 20654ac8fcbSHelge Deller if (pdt_type == PDT_PAT_CELL) 207c9c2877dSHelge Deller ret = pdc_pat_mem_read_cell_pdt(&pat_pret, pdt_entry, 208c9c2877dSHelge Deller MAX_PDT_ENTRIES); 20954ac8fcbSHelge Deller else 210c9c2877dSHelge Deller ret = pdc_pat_mem_read_pd_pdt(&pat_pret, pdt_entry, 211c9c2877dSHelge Deller MAX_PDT_TABLE_SIZE, 0); 212c9c2877dSHelge Deller #else 213c9c2877dSHelge Deller ret = PDC_BAD_PROC; 214c9c2877dSHelge Deller #endif 215c9c2877dSHelge Deller } 216c9c2877dSHelge Deller 217c9c2877dSHelge Deller if (ret != PDC_OK) { 218c9c2877dSHelge Deller pdt_type = PDT_NONE; 21954ac8fcbSHelge Deller pr_warn("PDT: Get PDT entries failed with %d\n", ret); 220c9c2877dSHelge Deller return; 221c9c2877dSHelge Deller } 222c9c2877dSHelge Deller 223c9c2877dSHelge Deller for (i = 0; i < pdt_status.pdt_entries; i++) { 224ea697648SHelge Deller unsigned long addr; 225ea697648SHelge Deller 22654ac8fcbSHelge Deller report_mem_err(pdt_entry[i]); 227c9c2877dSHelge Deller 228ea697648SHelge Deller addr = pdt_entry[i] & PDT_ADDR_PHYS_MASK; 229ea697648SHelge Deller if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && 230ea697648SHelge Deller addr >= initrd_start && addr < initrd_end) 231ea697648SHelge Deller pr_crit("CRITICAL: initrd possibly broken " 232ea697648SHelge Deller "due to bad memory!\n"); 233ea697648SHelge Deller 234c9c2877dSHelge Deller /* mark memory page bad */ 235c9c2877dSHelge Deller memblock_reserve(pdt_entry[i] & PAGE_MASK, PAGE_SIZE); 236a46c9304SNaoya Horiguchi num_poisoned_pages_inc(addr >> PAGE_SHIFT); 237c9c2877dSHelge Deller } 238c9c2877dSHelge Deller } 23954ac8fcbSHelge Deller 24054ac8fcbSHelge Deller 24154ac8fcbSHelge Deller /* 24254ac8fcbSHelge Deller * This is the PDT kernel thread main loop. 24354ac8fcbSHelge Deller */ 24454ac8fcbSHelge Deller 24554ac8fcbSHelge Deller static int pdt_mainloop(void *unused) 24654ac8fcbSHelge Deller { 24754ac8fcbSHelge Deller struct pdc_mem_read_pdt pdt_read_ret; 24854ac8fcbSHelge Deller struct pdc_pat_mem_read_pd_retinfo pat_pret __maybe_unused; 24954ac8fcbSHelge Deller unsigned long old_num_entries; 25054ac8fcbSHelge Deller unsigned long *bad_mem_ptr; 25154ac8fcbSHelge Deller int num, ret; 25254ac8fcbSHelge Deller 25354ac8fcbSHelge Deller for (;;) { 25454ac8fcbSHelge Deller set_current_state(TASK_INTERRUPTIBLE); 25554ac8fcbSHelge Deller 25654ac8fcbSHelge Deller old_num_entries = pdt_status.pdt_entries; 25754ac8fcbSHelge Deller 25854ac8fcbSHelge Deller schedule_timeout(pdt_poll_interval); 25954ac8fcbSHelge Deller if (kthread_should_stop()) 26054ac8fcbSHelge Deller break; 26154ac8fcbSHelge Deller 26254ac8fcbSHelge Deller /* Do we have new PDT entries? */ 26354ac8fcbSHelge Deller switch (pdt_type) { 26454ac8fcbSHelge Deller case PDT_PAT_NEW: 26554ac8fcbSHelge Deller ret = get_info_pat_new(); 26654ac8fcbSHelge Deller break; 26754ac8fcbSHelge Deller case PDT_PAT_CELL: 26854ac8fcbSHelge Deller ret = get_info_pat_cell(); 26954ac8fcbSHelge Deller break; 27054ac8fcbSHelge Deller default: 27154ac8fcbSHelge Deller ret = pdc_mem_pdt_info(&pdt_status); 27254ac8fcbSHelge Deller break; 27354ac8fcbSHelge Deller } 27454ac8fcbSHelge Deller 27554ac8fcbSHelge Deller if (ret != PDC_OK) { 27654ac8fcbSHelge Deller pr_warn("PDT: unexpected failure %d\n", ret); 27754ac8fcbSHelge Deller return -EINVAL; 27854ac8fcbSHelge Deller } 27954ac8fcbSHelge Deller 28054ac8fcbSHelge Deller /* if no new PDT entries, just wait again */ 28154ac8fcbSHelge Deller num = pdt_status.pdt_entries - old_num_entries; 28254ac8fcbSHelge Deller if (num <= 0) 28354ac8fcbSHelge Deller continue; 28454ac8fcbSHelge Deller 28554ac8fcbSHelge Deller /* decrease poll interval in case we found memory errors */ 28654ac8fcbSHelge Deller if (pdt_status.pdt_entries && 28754ac8fcbSHelge Deller pdt_poll_interval == PDT_POLL_INTERVAL_DEFAULT) 28854ac8fcbSHelge Deller pdt_poll_interval = PDT_POLL_INTERVAL_SHORT; 28954ac8fcbSHelge Deller 29054ac8fcbSHelge Deller /* limit entries to get */ 29154ac8fcbSHelge Deller if (num > MAX_PDT_ENTRIES) { 29254ac8fcbSHelge Deller num = MAX_PDT_ENTRIES; 29354ac8fcbSHelge Deller pdt_status.pdt_entries = old_num_entries + num; 29454ac8fcbSHelge Deller } 29554ac8fcbSHelge Deller 29654ac8fcbSHelge Deller /* get new entries */ 29754ac8fcbSHelge Deller switch (pdt_type) { 29854ac8fcbSHelge Deller #ifdef CONFIG_64BIT 29954ac8fcbSHelge Deller case PDT_PAT_CELL: 30054ac8fcbSHelge Deller if (pdt_status.pdt_entries > MAX_PDT_ENTRIES) { 30154ac8fcbSHelge Deller pr_crit("PDT: too many entries.\n"); 30254ac8fcbSHelge Deller return -ENOMEM; 30354ac8fcbSHelge Deller } 30454ac8fcbSHelge Deller ret = pdc_pat_mem_read_cell_pdt(&pat_pret, pdt_entry, 30554ac8fcbSHelge Deller MAX_PDT_ENTRIES); 30654ac8fcbSHelge Deller bad_mem_ptr = &pdt_entry[old_num_entries]; 30754ac8fcbSHelge Deller break; 30854ac8fcbSHelge Deller case PDT_PAT_NEW: 30954ac8fcbSHelge Deller ret = pdc_pat_mem_read_pd_pdt(&pat_pret, 31054ac8fcbSHelge Deller pdt_entry, 31154ac8fcbSHelge Deller num * sizeof(unsigned long), 31254ac8fcbSHelge Deller old_num_entries * sizeof(unsigned long)); 31354ac8fcbSHelge Deller bad_mem_ptr = &pdt_entry[0]; 31454ac8fcbSHelge Deller break; 31554ac8fcbSHelge Deller #endif 31654ac8fcbSHelge Deller default: 31754ac8fcbSHelge Deller ret = pdc_mem_pdt_read_entries(&pdt_read_ret, 31854ac8fcbSHelge Deller pdt_entry); 31954ac8fcbSHelge Deller bad_mem_ptr = &pdt_entry[old_num_entries]; 32054ac8fcbSHelge Deller break; 32154ac8fcbSHelge Deller } 32254ac8fcbSHelge Deller 32354ac8fcbSHelge Deller /* report and mark memory broken */ 32454ac8fcbSHelge Deller while (num--) { 32554ac8fcbSHelge Deller unsigned long pde = *bad_mem_ptr++; 32654ac8fcbSHelge Deller 32754ac8fcbSHelge Deller report_mem_err(pde); 32854ac8fcbSHelge Deller 32954ac8fcbSHelge Deller #ifdef CONFIG_MEMORY_FAILURE 33054ac8fcbSHelge Deller if ((pde & PDT_ADDR_PERM_ERR) || 33154ac8fcbSHelge Deller ((pde & PDT_ADDR_SINGLE_ERR) == 0)) 33283b57531SEric W. Biederman memory_failure(pde >> PAGE_SHIFT, 0); 33354ac8fcbSHelge Deller else 33436257d55SHelge Deller soft_offline_page(pde >> PAGE_SHIFT, 0); 33554ac8fcbSHelge Deller #else 33654ac8fcbSHelge Deller pr_crit("PDT: memory error at 0x%lx ignored.\n" 33754ac8fcbSHelge Deller "Rebuild kernel with CONFIG_MEMORY_FAILURE=y " 33854ac8fcbSHelge Deller "for real handling.\n", 33954ac8fcbSHelge Deller pde & PDT_ADDR_PHYS_MASK); 34054ac8fcbSHelge Deller #endif 34154ac8fcbSHelge Deller 34254ac8fcbSHelge Deller } 34354ac8fcbSHelge Deller } 34454ac8fcbSHelge Deller 34554ac8fcbSHelge Deller return 0; 34654ac8fcbSHelge Deller } 34754ac8fcbSHelge Deller 34854ac8fcbSHelge Deller 34954ac8fcbSHelge Deller static int __init pdt_initcall(void) 35054ac8fcbSHelge Deller { 35154ac8fcbSHelge Deller struct task_struct *kpdtd_task; 35254ac8fcbSHelge Deller 35354ac8fcbSHelge Deller if (pdt_type == PDT_NONE) 35454ac8fcbSHelge Deller return -ENODEV; 35554ac8fcbSHelge Deller 356d1fbab7eSCai Huoqing kpdtd_task = kthread_run(pdt_mainloop, NULL, "kpdtd"); 35754ac8fcbSHelge Deller if (IS_ERR(kpdtd_task)) 35854ac8fcbSHelge Deller return PTR_ERR(kpdtd_task); 35954ac8fcbSHelge Deller 36054ac8fcbSHelge Deller return 0; 36154ac8fcbSHelge Deller } 36254ac8fcbSHelge Deller 36354ac8fcbSHelge Deller late_initcall(pdt_initcall); 364