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

TOMOYO Linux Cross Reference
Linux/arch/x86/kernel/i8259.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/x86/kernel/i8259.c (Version linux-6.12-rc7) and /arch/sparc64/kernel/i8259.c (Version linux-6.5.13)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 #include <linux/linkage.h>                        
  3 #include <linux/errno.h>                          
  4 #include <linux/signal.h>                         
  5 #include <linux/sched.h>                          
  6 #include <linux/ioport.h>                         
  7 #include <linux/interrupt.h>                      
  8 #include <linux/irq.h>                            
  9 #include <linux/timex.h>                          
 10 #include <linux/random.h>                         
 11 #include <linux/init.h>                           
 12 #include <linux/kernel_stat.h>                    
 13 #include <linux/syscore_ops.h>                    
 14 #include <linux/bitops.h>                         
 15 #include <linux/acpi.h>                           
 16 #include <linux/io.h>                             
 17 #include <linux/delay.h>                          
 18 #include <linux/pgtable.h>                        
 19                                                   
 20 #include <linux/atomic.h>                         
 21 #include <asm/timer.h>                            
 22 #include <asm/hw_irq.h>                           
 23 #include <asm/desc.h>                             
 24 #include <asm/apic.h>                             
 25 #include <asm/i8259.h>                            
 26                                                   
 27 /*                                                
 28  * This is the 'legacy' 8259A Programmable Int    
 29  * present in the majority of PC/AT boxes.        
 30  * plus some generic x86 specific things if ge    
 31  * any sense at all.                              
 32  */                                               
 33 static void init_8259A(int auto_eoi);             
 34                                                   
 35 static bool pcat_compat __ro_after_init;          
 36 static int i8259A_auto_eoi;                       
 37 DEFINE_RAW_SPINLOCK(i8259A_lock);                 
 38                                                   
 39 /*                                                
 40  * 8259A PIC functions to handle ISA devices:     
 41  */                                               
 42                                                   
 43 /*                                                
 44  * This contains the irq mask for both 8259A i    
 45  */                                               
 46 unsigned int cached_irq_mask = 0xffff;            
 47                                                   
 48 /*                                                
 49  * Not all IRQs can be routed through the IO-A    
 50  * boards the timer interrupt is not really co    
 51  * it's fed to the master 8259A's IR0 line onl    
 52  *                                                
 53  * Any '1' bit in this mask means the IRQ is r    
 54  * this 'mixed mode' IRQ handling costs nothin    
 55  * at IRQ setup time.                             
 56  */                                               
 57 unsigned long io_apic_irqs;                       
 58                                                   
 59 static void mask_8259A_irq(unsigned int irq)      
 60 {                                                 
 61         unsigned int mask = 1 << irq;             
 62         unsigned long flags;                      
 63                                                   
 64         raw_spin_lock_irqsave(&i8259A_lock, fl    
 65         cached_irq_mask |= mask;                  
 66         if (irq & 8)                              
 67                 outb(cached_slave_mask, PIC_SL    
 68         else                                      
 69                 outb(cached_master_mask, PIC_M    
 70         raw_spin_unlock_irqrestore(&i8259A_loc    
 71 }                                                 
 72                                                   
 73 static void disable_8259A_irq(struct irq_data     
 74 {                                                 
 75         mask_8259A_irq(data->irq);                
 76 }                                                 
 77                                                   
 78 static void unmask_8259A_irq(unsigned int irq)    
 79 {                                                 
 80         unsigned int mask = ~(1 << irq);          
 81         unsigned long flags;                      
 82                                                   
 83         raw_spin_lock_irqsave(&i8259A_lock, fl    
 84         cached_irq_mask &= mask;                  
 85         if (irq & 8)                              
 86                 outb(cached_slave_mask, PIC_SL    
 87         else                                      
 88                 outb(cached_master_mask, PIC_M    
 89         raw_spin_unlock_irqrestore(&i8259A_loc    
 90 }                                                 
 91                                                   
 92 static void enable_8259A_irq(struct irq_data *    
 93 {                                                 
 94         unmask_8259A_irq(data->irq);              
 95 }                                                 
 96                                                   
 97 static int i8259A_irq_pending(unsigned int irq    
 98 {                                                 
 99         unsigned int mask = 1<<irq;               
100         unsigned long flags;                      
101         int ret;                                  
102                                                   
103         raw_spin_lock_irqsave(&i8259A_lock, fl    
104         if (irq < 8)                              
105                 ret = inb(PIC_MASTER_CMD) & ma    
106         else                                      
107                 ret = inb(PIC_SLAVE_CMD) & (ma    
108         raw_spin_unlock_irqrestore(&i8259A_loc    
109                                                   
110         return ret;                               
111 }                                                 
112                                                   
113 static void make_8259A_irq(unsigned int irq)      
114 {                                                 
115         disable_irq_nosync(irq);                  
116         io_apic_irqs &= ~(1<<irq);                
117         irq_set_chip_and_handler(irq, &i8259A_    
118         irq_set_status_flags(irq, IRQ_LEVEL);     
119         enable_irq(irq);                          
120         lapic_assign_legacy_vector(irq, true);    
121 }                                                 
122                                                   
123 /*                                                
124  * This function assumes to be called rarely.     
125  * 8259A registers is slow.                       
126  * This has to be protected by the irq control    
127  * before being called.                           
128  */                                               
129 static inline int i8259A_irq_real(unsigned int    
130 {                                                 
131         int value;                                
132         int irqmask = 1<<irq;                     
133                                                   
134         if (irq < 8) {                            
135                 outb(0x0B, PIC_MASTER_CMD);       
136                 value = inb(PIC_MASTER_CMD) &     
137                 outb(0x0A, PIC_MASTER_CMD);       
138                 return value;                     
139         }                                         
140         outb(0x0B, PIC_SLAVE_CMD);      /* ISR    
141         value = inb(PIC_SLAVE_CMD) & (irqmask     
142         outb(0x0A, PIC_SLAVE_CMD);      /* bac    
143         return value;                             
144 }                                                 
145                                                   
146 /*                                                
147  * Careful! The 8259A is a fragile beast, it p    
148  * much _has_ to be done exactly like this (ma    
149  * first, _then_ send the EOI, and the order o    
150  * to the two 8259s is important!                 
151  */                                               
152 static void mask_and_ack_8259A(struct irq_data    
153 {                                                 
154         unsigned int irq = data->irq;             
155         unsigned int irqmask = 1 << irq;          
156         unsigned long flags;                      
157                                                   
158         raw_spin_lock_irqsave(&i8259A_lock, fl    
159         /*                                        
160          * Lightweight spurious IRQ detection.    
161          * to overdo spurious IRQ handling - i    
162          * of hardware problems, so we only do    
163          * do without slowing down good hardwa    
164          *                                        
165          * Note that IRQ7 and IRQ15 (the two s    
166          * usually resulting from the 8259A-1|    
167          * even if the IRQ is masked in the 82    
168          * can check spurious 8259A IRQs witho    
169          * quite slow i8259A_irq_real() call f    
170          * This does not cover 100% of spuriou    
171          * but should be enough to warn the us    
172          * is something bad going on ...          
173          */                                       
174         if (cached_irq_mask & irqmask)            
175                 goto spurious_8259A_irq;          
176         cached_irq_mask |= irqmask;               
177                                                   
178 handle_real_irq:                                  
179         if (irq & 8) {                            
180                 inb(PIC_SLAVE_IMR);     /* DUM    
181                 outb(cached_slave_mask, PIC_SL    
182                 /* 'Specific EOI' to slave */     
183                 outb(0x60+(irq&7), PIC_SLAVE_C    
184                  /* 'Specific EOI' to master-I    
185                 outb(0x60+PIC_CASCADE_IR, PIC_    
186         } else {                                  
187                 inb(PIC_MASTER_IMR);    /* DUM    
188                 outb(cached_master_mask, PIC_M    
189                 outb(0x60+irq, PIC_MASTER_CMD)    
190         }                                         
191         raw_spin_unlock_irqrestore(&i8259A_loc    
192         return;                                   
193                                                   
194 spurious_8259A_irq:                               
195         /*                                        
196          * this is the slow path - should happ    
197          */                                       
198         if (i8259A_irq_real(irq))                 
199                 /*                                
200                  * oops, the IRQ _is_ in servi    
201                  * 8259A - not spurious, go ha    
202                  */                               
203                 goto handle_real_irq;             
204                                                   
205         {                                         
206                 static int spurious_irq_mask;     
207                 /*                                
208                  * At this point we can be sur    
209                  * lets ACK and report it. [on    
210                  */                               
211                 if (!(spurious_irq_mask & irqm    
212                         printk_deferred(KERN_D    
213                                "spurious 8259A    
214                         spurious_irq_mask |= i    
215                 }                                 
216                 atomic_inc(&irq_err_count);       
217                 /*                                
218                  * Theoretically we do not hav    
219                  * but in Linux this does not     
220                  * simpler for us.                
221                  */                               
222                 goto handle_real_irq;             
223         }                                         
224 }                                                 
225                                                   
226 struct irq_chip i8259A_chip = {                   
227         .name           = "XT-PIC",               
228         .irq_mask       = disable_8259A_irq,      
229         .irq_disable    = disable_8259A_irq,      
230         .irq_unmask     = enable_8259A_irq,       
231         .irq_mask_ack   = mask_and_ack_8259A,     
232 };                                                
233                                                   
234 static char irq_trigger[2];                       
235 /* ELCR registers (0x4d0, 0x4d1) control edge/    
236 static void restore_ELCR(char *trigger)           
237 {                                                 
238         outb(trigger[0], PIC_ELCR1);              
239         outb(trigger[1], PIC_ELCR2);              
240 }                                                 
241                                                   
242 static void save_ELCR(char *trigger)              
243 {                                                 
244         /* IRQ 0,1,2,8,13 are marked as reserv    
245         trigger[0] = inb(PIC_ELCR1) & 0xF8;       
246         trigger[1] = inb(PIC_ELCR2) & 0xDE;       
247 }                                                 
248                                                   
249 static void i8259A_resume(void)                   
250 {                                                 
251         init_8259A(i8259A_auto_eoi);              
252         restore_ELCR(irq_trigger);                
253 }                                                 
254                                                   
255 static int i8259A_suspend(void)                   
256 {                                                 
257         save_ELCR(irq_trigger);                   
258         return 0;                                 
259 }                                                 
260                                                   
261 static void i8259A_shutdown(void)                 
262 {                                                 
263         /* Put the i8259A into a quiescent sta    
264          * the kernel initialization code can     
265          * out of.                                
266          */                                       
267         outb(0xff, PIC_MASTER_IMR);     /* mas    
268         outb(0xff, PIC_SLAVE_IMR);      /* mas    
269 }                                                 
270                                                   
271 static struct syscore_ops i8259_syscore_ops =     
272         .suspend = i8259A_suspend,                
273         .resume = i8259A_resume,                  
274         .shutdown = i8259A_shutdown,              
275 };                                                
276                                                   
277 static void mask_8259A(void)                      
278 {                                                 
279         unsigned long flags;                      
280                                                   
281         raw_spin_lock_irqsave(&i8259A_lock, fl    
282                                                   
283         outb(0xff, PIC_MASTER_IMR);     /* mas    
284         outb(0xff, PIC_SLAVE_IMR);      /* mas    
285                                                   
286         raw_spin_unlock_irqrestore(&i8259A_loc    
287 }                                                 
288                                                   
289 static void unmask_8259A(void)                    
290 {                                                 
291         unsigned long flags;                      
292                                                   
293         raw_spin_lock_irqsave(&i8259A_lock, fl    
294                                                   
295         outb(cached_master_mask, PIC_MASTER_IM    
296         outb(cached_slave_mask, PIC_SLAVE_IMR)    
297                                                   
298         raw_spin_unlock_irqrestore(&i8259A_loc    
299 }                                                 
300                                                   
301 static int probe_8259A(void)                      
302 {                                                 
303         unsigned char new_val, probe_val = ~(1    
304         unsigned long flags;                      
305                                                   
306         /*                                        
307          * If MADT has the PCAT_COMPAT flag se    
308          * for the PIC. Some BIOSes leave the     
309          * fails.                                 
310          *                                        
311          * Right now this causes problems as q    
312          * nr_legacy_irqs() > 0 or has_legacy_    
313          * when the system has an IO/APIC beca    
314          * at all, except for really old machi    
315          * must be routed through the PIC. So     
316          * there and let legacy_pic->init() in    
317          *                                        
318          * Alternatively this could just try t    
319          * repeat the probe, but for cases whe    
320          * just pointless.                        
321          */                                       
322         if (pcat_compat)                          
323                 return nr_legacy_irqs();          
324                                                   
325         /*                                        
326          * Check to see if we have a PIC.  Mas    
327          * read back the value we just wrote.     
328          * will read 0xff as opposed to the va    
329          */                                       
330         raw_spin_lock_irqsave(&i8259A_lock, fl    
331                                                   
332         outb(0xff, PIC_SLAVE_IMR);      /* mas    
333         outb(probe_val, PIC_MASTER_IMR);          
334         new_val = inb(PIC_MASTER_IMR);            
335         if (new_val != probe_val) {               
336                 printk(KERN_INFO "Using NULL l    
337                 legacy_pic = &null_legacy_pic;    
338         }                                         
339                                                   
340         raw_spin_unlock_irqrestore(&i8259A_loc    
341         return nr_legacy_irqs();                  
342 }                                                 
343                                                   
344 static void init_8259A(int auto_eoi)              
345 {                                                 
346         unsigned long flags;                      
347                                                   
348         i8259A_auto_eoi = auto_eoi;               
349                                                   
350         raw_spin_lock_irqsave(&i8259A_lock, fl    
351                                                   
352         outb(0xff, PIC_MASTER_IMR);     /* mas    
353                                                   
354         /*                                        
355          * outb_pic - this has to work on a wi    
356          */                                       
357         outb_pic(0x11, PIC_MASTER_CMD); /* ICW    
358                                                   
359         /* ICW2: 8259A-1 IR0-7 mapped to ISA_I    
360         outb_pic(ISA_IRQ_VECTOR(0), PIC_MASTER    
361                                                   
362         /* 8259A-1 (the master) has a slave on    
363         outb_pic(1U << PIC_CASCADE_IR, PIC_MAS    
364                                                   
365         if (auto_eoi)   /* master does Auto EO    
366                 outb_pic(MASTER_ICW4_DEFAULT |    
367         else            /* master expects norm    
368                 outb_pic(MASTER_ICW4_DEFAULT,     
369                                                   
370         outb_pic(0x11, PIC_SLAVE_CMD);  /* ICW    
371                                                   
372         /* ICW2: 8259A-2 IR0-7 mapped to ISA_I    
373         outb_pic(ISA_IRQ_VECTOR(8), PIC_SLAVE_    
374         /* 8259A-2 is a slave on master's IR2     
375         outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR    
376         /* (slave's support for AEOI in flat m    
377         outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE    
378                                                   
379         if (auto_eoi)                             
380                 /*                                
381                  * In AEOI mode we just have t    
382                  * when acking.                   
383                  */                               
384                 i8259A_chip.irq_mask_ack = dis    
385         else                                      
386                 i8259A_chip.irq_mask_ack = mas    
387                                                   
388         udelay(100);            /* wait for 82    
389                                                   
390         outb(cached_master_mask, PIC_MASTER_IM    
391         outb(cached_slave_mask, PIC_SLAVE_IMR)    
392                                                   
393         raw_spin_unlock_irqrestore(&i8259A_loc    
394 }                                                 
395                                                   
396 /*                                                
397  * make i8259 a driver so that we can select p    
398  * is to make x86 binary compatible among pc c    
399  * platforms, such as x86 MID.                    
400  */                                               
401                                                   
402 static void legacy_pic_noop(void) { };            
403 static void legacy_pic_uint_noop(unsigned int     
404 static void legacy_pic_int_noop(int unused) {     
405 static int legacy_pic_irq_pending_noop(unsigne    
406 {                                                 
407         return 0;                                 
408 }                                                 
409 static int legacy_pic_probe(void)                 
410 {                                                 
411         return 0;                                 
412 }                                                 
413                                                   
414 struct legacy_pic null_legacy_pic = {             
415         .nr_legacy_irqs = 0,                      
416         .chip = &dummy_irq_chip,                  
417         .mask = legacy_pic_uint_noop,             
418         .unmask = legacy_pic_uint_noop,           
419         .mask_all = legacy_pic_noop,              
420         .restore_mask = legacy_pic_noop,          
421         .init = legacy_pic_int_noop,              
422         .probe = legacy_pic_probe,                
423         .irq_pending = legacy_pic_irq_pending_    
424         .make_irq = legacy_pic_uint_noop,         
425 };                                                
426                                                   
427 static struct legacy_pic default_legacy_pic =     
428         .nr_legacy_irqs = NR_IRQS_LEGACY,         
429         .chip  = &i8259A_chip,                    
430         .mask = mask_8259A_irq,                   
431         .unmask = unmask_8259A_irq,               
432         .mask_all = mask_8259A,                   
433         .restore_mask = unmask_8259A,             
434         .init = init_8259A,                       
435         .probe = probe_8259A,                     
436         .irq_pending = i8259A_irq_pending,        
437         .make_irq = make_8259A_irq,               
438 };                                                
439                                                   
440 struct legacy_pic *legacy_pic = &default_legac    
441 EXPORT_SYMBOL(legacy_pic);                        
442                                                   
443 static int __init i8259A_init_ops(void)           
444 {                                                 
445         if (legacy_pic == &default_legacy_pic)    
446                 register_syscore_ops(&i8259_sy    
447                                                   
448         return 0;                                 
449 }                                                 
450 device_initcall(i8259A_init_ops);                 
451                                                   
452 void __init legacy_pic_pcat_compat(void)          
453 {                                                 
454         pcat_compat = true;                       
455 }                                                 
456                                                   

~ [ 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