~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/parisc/kernel/pdt.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/parisc/kernel/pdt.c (Version linux-6.12-rc7) and /arch/m68k/kernel/pdt.c (Version linux-6.4.16)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 /*                                                
  3  *    Page Deallocation Table (PDT) support       
  4  *                                                
  5  *    The Page Deallocation Table (PDT) is mai    
  6  *    list of memory addresses in which memory    
  7  *    The list contains both single-bit (corre    
  8  *    (uncorrectable) errors.                     
  9  *                                                
 10  *    Copyright 2017 by Helge Deller <deller@g    
 11  *                                                
 12  *    possible future enhancements:               
 13  *    - add userspace interface via procfs or     
 14  */                                               
 15                                                   
 16 #include <linux/memblock.h>                       
 17 #include <linux/seq_file.h>                       
 18 #include <linux/kthread.h>                        
 19 #include <linux/proc_fs.h>                        
 20 #include <linux/initrd.h>                         
 21 #include <linux/pgtable.h>                        
 22 #include <linux/mm.h>                             
 23                                                   
 24 #include <asm/pdc.h>                              
 25 #include <asm/pdcpat.h>                           
 26 #include <asm/sections.h>                         
 27 #include <asm/pgtable.h>                          
 28                                                   
 29 enum pdt_access_type {                            
 30         PDT_NONE,                                 
 31         PDT_PDC,                                  
 32         PDT_PAT_NEW,                              
 33         PDT_PAT_CELL                              
 34 };                                                
 35                                                   
 36 static enum pdt_access_type pdt_type;             
 37                                                   
 38 /* PDT poll interval: 1 minute if errors, 5 mi    
 39 #define PDT_POLL_INTERVAL_DEFAULT       (5*60*    
 40 #define PDT_POLL_INTERVAL_SHORT         (1*60*    
 41 static unsigned long pdt_poll_interval = PDT_P    
 42                                                   
 43 /* global PDT status information */               
 44 static struct pdc_mem_retinfo pdt_status;         
 45                                                   
 46 #define MAX_PDT_TABLE_SIZE      PAGE_SIZE         
 47 #define MAX_PDT_ENTRIES         (MAX_PDT_TABLE    
 48 static unsigned long pdt_entry[MAX_PDT_ENTRIES    
 49                                                   
 50 /*                                                
 51  * Constants for the pdt_entry format:            
 52  * A pdt_entry holds the physical address in b    
 53  * reserved, bit 62 is the perm bit and bit 63    
 54  * The perm bit indicates whether the error ha    
 55  * error (value of 1) or has not been verified    
 56  * of 0). The error_type bit indicates whether    
 57  * (value of 1) or a multiple bit error.          
 58  * On non-PAT machines phys_addr is encoded in    
 59  * 63. Those machines don't provide the perm b    
 60  */                                               
 61                                                   
 62 #define PDT_ADDR_PHYS_MASK      (pdt_type != P    
 63 #define PDT_ADDR_PERM_ERR       (pdt_type != P    
 64 #define PDT_ADDR_SINGLE_ERR     1UL               
 65                                                   
 66 /* report PDT entries via /proc/meminfo */        
 67 void arch_report_meminfo(struct seq_file *m)      
 68 {                                                 
 69         if (pdt_type == PDT_NONE)                 
 70                 return;                           
 71                                                   
 72         seq_printf(m, "PDT_max_entries: %7lu\n    
 73                         pdt_status.pdt_size);     
 74         seq_printf(m, "PDT_cur_entries: %7lu\n    
 75                         pdt_status.pdt_entries    
 76 }                                                 
 77                                                   
 78 static int get_info_pat_new(void)                 
 79 {                                                 
 80         struct pdc_pat_mem_retinfo pat_rinfo;     
 81         int ret;                                  
 82                                                   
 83         /* newer PAT machines like C8000 repor    
 84         if (is_pdc_pat())                         
 85                 ret = pdc_pat_mem_pdt_info(&pa    
 86         else                                      
 87                 return PDC_BAD_PROC;              
 88                                                   
 89         pdt_status.pdt_size = pat_rinfo.max_pd    
 90         pdt_status.pdt_entries = pat_rinfo.cur    
 91         pdt_status.pdt_status = 0;                
 92         pdt_status.first_dbe_loc = pat_rinfo.f    
 93         pdt_status.good_mem = pat_rinfo.good_m    
 94                                                   
 95         return ret;                               
 96 }                                                 
 97                                                   
 98 static int get_info_pat_cell(void)                
 99 {                                                 
100         struct pdc_pat_mem_cell_pdt_retinfo ce    
101         int ret;                                  
102                                                   
103         /* older PAT machines like rp5470 repo    
104         if (is_pdc_pat())                         
105                 ret = pdc_pat_mem_pdt_cell_inf    
106         else                                      
107                 return PDC_BAD_PROC;              
108                                                   
109         pdt_status.pdt_size = cell_rinfo.max_p    
110         pdt_status.pdt_entries = cell_rinfo.cu    
111         pdt_status.pdt_status = 0;                
112         pdt_status.first_dbe_loc = cell_rinfo.    
113         pdt_status.good_mem = cell_rinfo.good_    
114                                                   
115         return ret;                               
116 }                                                 
117                                                   
118 static void report_mem_err(unsigned long pde)     
119 {                                                 
120         struct pdc_pat_mem_phys_mem_location l    
121         unsigned long addr;                       
122         char dimm_txt[32];                        
123                                                   
124         addr = pde & PDT_ADDR_PHYS_MASK;          
125                                                   
126         /* show DIMM slot description on PAT m    
127         if (is_pdc_pat()) {                       
128                 pdc_pat_mem_get_dimm_phys_loca    
129                 sprintf(dimm_txt, "DIMM slot %    
130         } else                                    
131                 dimm_txt[0] = 0;                  
132                                                   
133         pr_warn("PDT: BAD MEMORY at 0x%08lx, %    
134                 addr, dimm_txt,                   
135                 pde & PDT_ADDR_PERM_ERR ? "per    
136                 pde & PDT_ADDR_SINGLE_ERR ? "s    
137 }                                                 
138                                                   
139                                                   
140 /*                                                
141  * pdc_pdt_init()                                 
142  *                                                
143  * Initialize kernel PDT structures, read init    
144  * report all current PDT entries and mark bad    
145  * to avoid that the kernel will use broken me    
146  *                                                
147  */                                               
148 void __init pdc_pdt_init(void)                    
149 {                                                 
150         int ret, i;                               
151         unsigned long entries;                    
152         struct pdc_mem_read_pdt pdt_read_ret;     
153                                                   
154         pdt_type = PDT_PAT_NEW;                   
155         ret = get_info_pat_new();                 
156                                                   
157         if (ret != PDC_OK) {                      
158                 pdt_type = PDT_PAT_CELL;          
159                 ret = get_info_pat_cell();        
160         }                                         
161                                                   
162         if (ret != PDC_OK) {                      
163                 pdt_type = PDT_PDC;               
164                 /* non-PAT machines provide th    
165                 ret = pdc_mem_pdt_info(&pdt_st    
166         }                                         
167                                                   
168         if (ret != PDC_OK) {                      
169                 pdt_type = PDT_NONE;              
170                 pr_info("PDT: Firmware does no    
171                         " information.\n");       
172                 return;                           
173         }                                         
174                                                   
175         entries = pdt_status.pdt_entries;         
176         if (WARN_ON(entries > MAX_PDT_ENTRIES)    
177                 entries = pdt_status.pdt_entri    
178                                                   
179         pr_info("PDT: type %s, size %lu, entri    
180                 " good_mem %lu MB\n",             
181                         pdt_type == PDT_PDC ?     
182                         pdt_type == PDT_PAT_CE    
183                                                   
184                         pdt_status.pdt_size, p    
185                         pdt_status.pdt_status,    
186                         pdt_status.good_mem /     
187                                                   
188         if (entries == 0) {                       
189                 pr_info("PDT: Firmware reports    
190                 return;                           
191         }                                         
192                                                   
193         if (pdt_status.first_dbe_loc &&           
194                 pdt_status.first_dbe_loc <= __    
195                 pr_crit("CRITICAL: Bad memory     
196                                                   
197         pr_warn("PDT: Firmware reports %lu ent    
198                 entries);                         
199                                                   
200         if (pdt_type == PDT_PDC)                  
201                 ret = pdc_mem_pdt_read_entries    
202         else {                                    
203 #ifdef CONFIG_64BIT                               
204                 struct pdc_pat_mem_read_pd_ret    
205                                                   
206                 if (pdt_type == PDT_PAT_CELL)     
207                         ret = pdc_pat_mem_read    
208                                 MAX_PDT_ENTRIE    
209                 else                              
210                         ret = pdc_pat_mem_read    
211                                 MAX_PDT_TABLE_    
212 #else                                             
213                 ret = PDC_BAD_PROC;               
214 #endif                                            
215         }                                         
216                                                   
217         if (ret != PDC_OK) {                      
218                 pdt_type = PDT_NONE;              
219                 pr_warn("PDT: Get PDT entries     
220                 return;                           
221         }                                         
222                                                   
223         for (i = 0; i < pdt_status.pdt_entries    
224                 unsigned long addr;               
225                                                   
226                 report_mem_err(pdt_entry[i]);     
227                                                   
228                 addr = pdt_entry[i] & PDT_ADDR    
229                 if (IS_ENABLED(CONFIG_BLK_DEV_    
230                         addr >= initrd_start &    
231                         pr_crit("CRITICAL: ini    
232                                 "due to bad me    
233                                                   
234                 /* mark memory page bad */        
235                 memblock_reserve(pdt_entry[i]     
236                 num_poisoned_pages_inc(addr >>    
237         }                                         
238 }                                                 
239                                                   
240                                                   
241 /*                                                
242  * This is the PDT kernel thread main loop.       
243  */                                               
244                                                   
245 static int pdt_mainloop(void *unused)             
246 {                                                 
247         struct pdc_mem_read_pdt pdt_read_ret;     
248         struct pdc_pat_mem_read_pd_retinfo pat    
249         unsigned long old_num_entries;            
250         unsigned long *bad_mem_ptr;               
251         int num, ret;                             
252                                                   
253         for (;;) {                                
254                 set_current_state(TASK_INTERRU    
255                                                   
256                 old_num_entries = pdt_status.p    
257                                                   
258                 schedule_timeout(pdt_poll_inte    
259                 if (kthread_should_stop())        
260                         break;                    
261                                                   
262                 /* Do we have new PDT entries?    
263                 switch (pdt_type) {               
264                 case PDT_PAT_NEW:                 
265                         ret = get_info_pat_new    
266                         break;                    
267                 case PDT_PAT_CELL:                
268                         ret = get_info_pat_cel    
269                         break;                    
270                 default:                          
271                         ret = pdc_mem_pdt_info    
272                         break;                    
273                 }                                 
274                                                   
275                 if (ret != PDC_OK) {              
276                         pr_warn("PDT: unexpect    
277                         return -EINVAL;           
278                 }                                 
279                                                   
280                 /* if no new PDT entries, just    
281                 num = pdt_status.pdt_entries -    
282                 if (num <= 0)                     
283                         continue;                 
284                                                   
285                 /* decrease poll interval in c    
286                 if (pdt_status.pdt_entries &&     
287                         pdt_poll_interval == P    
288                         pdt_poll_interval = PD    
289                                                   
290                 /* limit entries to get */        
291                 if (num > MAX_PDT_ENTRIES) {      
292                         num = MAX_PDT_ENTRIES;    
293                         pdt_status.pdt_entries    
294                 }                                 
295                                                   
296                 /* get new entries */             
297                 switch (pdt_type) {               
298 #ifdef CONFIG_64BIT                               
299                 case PDT_PAT_CELL:                
300                         if (pdt_status.pdt_ent    
301                                 pr_crit("PDT:     
302                                 return -ENOMEM    
303                         }                         
304                         ret = pdc_pat_mem_read    
305                                 MAX_PDT_ENTRIE    
306                         bad_mem_ptr = &pdt_ent    
307                         break;                    
308                 case PDT_PAT_NEW:                 
309                         ret = pdc_pat_mem_read    
310                                 pdt_entry,        
311                                 num * sizeof(u    
312                                 old_num_entrie    
313                         bad_mem_ptr = &pdt_ent    
314                         break;                    
315 #endif                                            
316                 default:                          
317                         ret = pdc_mem_pdt_read    
318                                 pdt_entry);       
319                         bad_mem_ptr = &pdt_ent    
320                         break;                    
321                 }                                 
322                                                   
323                 /* report and mark memory brok    
324                 while (num--) {                   
325                         unsigned long pde = *b    
326                                                   
327                         report_mem_err(pde);      
328                                                   
329 #ifdef CONFIG_MEMORY_FAILURE                      
330                         if ((pde & PDT_ADDR_PE    
331                             ((pde & PDT_ADDR_S    
332                                 memory_failure    
333                         else                      
334                                 soft_offline_p    
335 #else                                             
336                         pr_crit("PDT: memory e    
337                                 "Rebuild kerne    
338                                 "for real hand    
339                                 pde & PDT_ADDR    
340 #endif                                            
341                                                   
342                 }                                 
343         }                                         
344                                                   
345         return 0;                                 
346 }                                                 
347                                                   
348                                                   
349 static int __init pdt_initcall(void)              
350 {                                                 
351         struct task_struct *kpdtd_task;           
352                                                   
353         if (pdt_type == PDT_NONE)                 
354                 return -ENODEV;                   
355                                                   
356         kpdtd_task = kthread_run(pdt_mainloop,    
357                                                   
358         return PTR_ERR_OR_ZERO(kpdtd_task);       
359 }                                                 
360                                                   
361 late_initcall(pdt_initcall);                      
362                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php