Subversion Repositories HelenOS

Rev

Rev 512 | Rev 514 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2001-2004 Jakub Jermar
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. #include <arch/types.h>
  30. #include <arch/smp/apic.h>
  31. #include <arch/smp/ap.h>
  32. #include <arch/smp/mps.h>
  33. #include <mm/page.h>
  34. #include <time/delay.h>
  35. #include <arch/interrupt.h>
  36. #include <print.h>
  37. #include <arch/asm.h>
  38. #include <arch.h>
  39.  
  40. #ifdef CONFIG_SMP
  41.  
  42. /*
  43.  * Advanced Programmable Interrupt Controller for SMP systems.
  44.  * Tested on:
  45.  *  Bochs 2.0.2 - Bochs 2.2 with 2-8 CPUs
  46.  *  Simics 2.0.28 - Simics 2.2.19 2-8 CPUs
  47.  *  ASUS P/I-P65UP5 + ASUS C-P55T2D REV. 1.41 with 2x 200Mhz Pentium CPUs
  48.  *  ASUS PCH-DL with 2x 3000Mhz Pentium 4 Xeon (HT) CPUs
  49.  *  MSI K7D Master-L with 2x 2100MHz Athlon MP CPUs
  50.  */
  51.  
  52. /*
  53.  * These variables either stay configured as initilalized, or are changed by
  54.  * the MP configuration code.
  55.  *
  56.  * Pay special attention to the volatile keyword. Without it, gcc -O2 would
  57.  * optimize the code too much and accesses to l_apic and io_apic, that must
  58.  * always be 32-bit, would use byte oriented instructions.
  59.  */
  60. volatile __u32 *l_apic = (__u32 *) 0xfee00000;
  61. volatile __u32 *io_apic = (__u32 *) 0xfec00000;
  62.  
  63. __u32 apic_id_mask = 0;
  64.  
  65. int apic_poll_errors(void);
  66.  
  67. /** Initialize APIC on BSP. */
  68. void apic_init(void)
  69. {
  70.     __u32 tmp, id, i;
  71.  
  72.     trap_register(VECTOR_APIC_SPUR, apic_spurious);
  73.  
  74.     enable_irqs_function = io_apic_enable_irqs;
  75.     disable_irqs_function = io_apic_disable_irqs;
  76.     eoi_function = l_apic_eoi;
  77.    
  78.     /*
  79.      * Configure interrupt routing.
  80.      * IRQ 0 remains masked as the time signal is generated by l_apic's themselves.
  81.      * Other interrupts will be forwarded to the lowest priority CPU.
  82.      */
  83.     io_apic_disable_irqs(0xffff);
  84.     trap_register(VECTOR_CLK, l_apic_timer_interrupt);
  85.     for (i=0; i<16; i++) {
  86.         int pin;
  87.    
  88.         if ((pin = smp_irq_to_pin(i)) != -1) {
  89.             io_apic_change_ioredtbl(pin, 0xff, IVT_IRQBASE+i, LOPRI);
  90.         }
  91.     }
  92.    
  93.  
  94.     /*
  95.      * Ensure that io_apic has unique ID.
  96.      */
  97.     tmp = io_apic_read(IOAPICID);
  98.     id = (tmp >> 24) & 0xf;
  99.     if ((1<<id) & apic_id_mask) {
  100.         int i;
  101.        
  102.         for (i=0; i<15; i++) {
  103.             if (!((1<<i) & apic_id_mask)) {
  104.                 io_apic_write(IOAPICID, (tmp & (~(0xf<<24))) | (i<<24));
  105.                 break;
  106.             }
  107.         }
  108.     }
  109.  
  110.     /*
  111.      * Configure the BSP's lapic.
  112.      */
  113.     l_apic_init();
  114.     l_apic_debug();
  115. }
  116.  
  117. void apic_spurious(__u8 n, __native stack[])
  118. {
  119.     printf("cpu%d: APIC spurious interrupt\n", CPU->id);
  120. }
  121.  
  122. int apic_poll_errors(void)
  123. {
  124.     __u32 esr;
  125.    
  126.     esr = l_apic[ESR] & ~ESRClear;
  127.    
  128.     if ((esr>>0) & 1)
  129.         printf("Send CS Error\n");
  130.     if ((esr>>1) & 1)
  131.         printf("Receive CS Error\n");
  132.     if ((esr>>2) & 1)
  133.         printf("Send Accept Error\n");
  134.     if ((esr>>3) & 1)
  135.         printf("Receive Accept Error\n");
  136.     if ((esr>>5) & 1)
  137.         printf("Send Illegal Vector\n");
  138.     if ((esr>>6) & 1)
  139.         printf("Received Illegal Vector\n");
  140.     if ((esr>>7) & 1)
  141.         printf("Illegal Register Address\n");
  142.  
  143.     return !esr;
  144. }
  145.  
  146. /*
  147.  * Send all CPUs excluding CPU IPI vector.
  148.  */
  149. int l_apic_broadcast_custom_ipi(__u8 vector)
  150. {
  151.     icr_t icr;
  152.  
  153.     icr.lo = l_apic[ICRlo];
  154.     icr.delmod = DELMOD_FIXED;
  155.     icr.destmod = DESTMOD_LOGIC;
  156.     icr.level = LEVEL_ASSERT;
  157.     icr.shorthand = SHORTHAND_ALL_EXCL;
  158.     icr.trigger_mode = TRIGMOD_LEVEL;
  159.     icr.vector = vector;
  160.  
  161.     l_apic[ICRlo] = icr.lo;
  162.  
  163.     icr.lo = l_apic[ICRlo];
  164.     if (icr.lo & SEND_PENDING)
  165.         printf("IPI is pending.\n");
  166.  
  167.     return apic_poll_errors();
  168. }
  169.  
  170. /*
  171.  * Universal Start-up Algorithm for bringing up the AP processors.
  172.  */
  173. int l_apic_send_init_ipi(__u8 apicid)
  174. {
  175.     icr_t icr;
  176.     int i;
  177.  
  178.     /*
  179.      * Read the ICR register in and zero all non-reserved fields.
  180.      */
  181.     icr.lo = l_apic[ICRlo];
  182.     icr.hi = l_apic[ICRhi];
  183.    
  184.     icr.delmod = DELMOD_INIT;
  185.     icr.destmod = DESTMOD_PHYS;
  186.     icr.level = LEVEL_ASSERT;
  187.     icr.trigger_mode = TRIGMOD_LEVEL;
  188.     icr.shorthand = SHORTHAND_NONE;
  189.     icr.vector = 0;
  190.     icr.dest = apicid;
  191.    
  192.     l_apic[ICRhi] = icr.hi;
  193.     l_apic[ICRlo] = icr.lo;
  194.  
  195.     /*
  196.      * According to MP Specification, 20us should be enough to
  197.      * deliver the IPI.
  198.      */
  199.     delay(20);
  200.  
  201.     if (!apic_poll_errors()) return 0;
  202.  
  203.     icr.lo = l_apic[ICRlo];
  204.     if (icr.lo & SEND_PENDING)
  205.         printf("IPI is pending.\n");
  206.  
  207.     icr.delmod = DELMOD_INIT;
  208.     icr.destmod = DESTMOD_PHYS;
  209.     icr.level = LEVEL_DEASSERT;
  210.     icr.shorthand = SHORTHAND_NONE;
  211.     icr.trigger_mode = TRIGMOD_LEVEL;
  212.     icr.vector = 0;
  213.     l_apic[ICRlo] = icr.lo;
  214.  
  215.     /*
  216.      * Wait 10ms as MP Specification specifies.
  217.      */
  218.     delay(10000);
  219.  
  220.     if (!is_82489DX_apic(l_apic[LAVR])) {
  221.         /*
  222.          * If this is not 82489DX-based l_apic we must send two STARTUP IPI's.
  223.          */
  224.         for (i = 0; i<2; i++) {
  225.             icr.lo = l_apic[ICRlo];
  226.             icr.vector = ((__address) ap_boot) / 4096; /* calculate the reset vector */
  227.             icr.delmod = DELMOD_STARTUP;
  228.             icr.destmod = DESTMOD_PHYS;
  229.             icr.level = LEVEL_ASSERT;
  230.             icr.shorthand = SHORTHAND_NONE;
  231.             icr.trigger_mode = TRIGMOD_LEVEL;
  232.             l_apic[ICRlo] = icr.lo;
  233.             delay(200);
  234.         }
  235.     }
  236.    
  237.    
  238.     return apic_poll_errors();
  239. }
  240.  
  241. void l_apic_init(void)
  242. {
  243.     lvt_error_t error;
  244.     lvt_lint_t lint;
  245.     svr_t svr;
  246.     lvt_tm_t tm;
  247.     icr_t icr;
  248.     __u32 t1, t2;
  249.  
  250.     /* Initialize LVT Error register. */
  251.     error.value = l_apic[LVT_Err];
  252.     error.masked = true;
  253.     l_apic[LVT_Err] = error.value;
  254.  
  255.     /* Initialize LVT LINT0 register. */
  256.     lint.value = l_apic[LVT_LINT0];
  257.     lint.masked = true;
  258.     l_apic[LVT_LINT0] = lint.value;
  259.  
  260.     /* Initialize LVT LINT1 register. */
  261.     lint.value = l_apic[LVT_LINT1];
  262.     lint.masked = true;
  263.     l_apic[LVT_LINT1] = lint.value;
  264.    
  265.     /* Spurious-Interrupt Vector Register initialization. */
  266.     svr.value = l_apic[SVR];
  267.     svr.vector = VECTOR_APIC_SPUR;
  268.     svr.lapic_enabled = true;
  269.     l_apic[SVR] = svr.value;
  270.  
  271.     l_apic[TPR] &= TPRClear;
  272.  
  273.     if (CPU->arch.family >= 6)
  274.         enable_l_apic_in_msr();
  275.    
  276.     /* Interrupt Command Register initialization. */
  277.     icr.lo = l_apic[ICRlo];
  278.     icr.delmod = DELMOD_INIT;
  279.     icr.destmod = DESTMOD_PHYS;
  280.     icr.level = LEVEL_DEASSERT;
  281.     icr.shorthand = SHORTHAND_ALL_INCL;
  282.     icr.trigger_mode = TRIGMOD_LEVEL;
  283.     l_apic[ICRlo] = icr.lo;
  284.    
  285.     /*
  286.      * Program the timer for periodic mode and respective vector.
  287.      */
  288.  
  289.     l_apic[TDCR] &= TDCRClear;
  290.     l_apic[TDCR] |= 0xb;
  291.  
  292.     tm.value = l_apic[LVT_Tm];
  293.     tm.vector = VECTOR_CLK;
  294.     tm.mode = TIMER_PERIODIC;
  295.     tm.masked = false;
  296.     l_apic[LVT_Tm] = tm.value;
  297.  
  298.     t1 = l_apic[CCRT];
  299.     l_apic[ICRT] = 0xffffffff;
  300.  
  301.     while (l_apic[CCRT] == t1)
  302.         ;
  303.        
  304.     t1 = l_apic[CCRT];
  305.     delay(1000);
  306.     t2 = l_apic[CCRT];
  307.    
  308.     l_apic[ICRT] = t1-t2;
  309.    
  310. }
  311.  
  312. void l_apic_eoi(void)
  313. {
  314.     l_apic[EOI] = 0;
  315. }
  316.  
  317. void l_apic_debug(void)
  318. {
  319. #ifdef LAPIC_VERBOSE
  320.     int i, lint;
  321.  
  322.     printf("LVT on cpu%d, LAPIC ID: %d\n", CPU->id, l_apic_id());
  323.  
  324.     printf("LVT_Tm: ");
  325.     if (l_apic[LVT_Tm] & (1<<17)) printf("periodic"); else printf("one-shot"); putchar(',');   
  326.     if (l_apic[LVT_Tm] & (1<<16)) printf("masked"); else printf("not masked"); putchar(',');
  327.     if (l_apic[LVT_Tm] & (1<<12)) printf("send pending"); else printf("idle"); putchar(',');
  328.     printf("%B\n", l_apic[LVT_Tm] & 0xff);
  329.    
  330.     for (i=0; i<2; i++) {
  331.         lint = i ? LVT_LINT1 : LVT_LINT0;
  332.         printf("LVT_LINT%d: ", i);
  333.         if (l_apic[lint] & (1<<16)) printf("masked"); else printf("not masked"); putchar(',');
  334.         if (l_apic[lint] & (1<<15)) printf("level"); else printf("edge"); putchar(',');
  335.         printf("%d", l_apic[lint] & (1<<14)); putchar(',');
  336.         printf("%d", l_apic[lint] & (1<<13)); putchar(',');
  337.         if (l_apic[lint] & (1<<12)) printf("send pending"); else printf("idle"); putchar(',');
  338.    
  339.         switch ((l_apic[lint]>>8)&7) {
  340.             case 0: printf("fixed"); break;
  341.             case 4: printf("NMI"); break;
  342.             case 7: printf("ExtINT"); break;
  343.         }
  344.         putchar(',');
  345.         printf("%B\n", l_apic[lint] & 0xff);   
  346.     }
  347.  
  348.     printf("LVT_Err: ");
  349.     if (l_apic[LVT_Err] & (1<<16)) printf("masked"); else printf("not masked"); putchar(',');
  350.     if (l_apic[LVT_Err] & (1<<12)) printf("send pending"); else printf("idle"); putchar(',');
  351.     printf("%B\n", l_apic[LVT_Err] & 0xff);
  352.  
  353.     /*
  354.      * This register is supported only on P6 and higher.
  355.      */
  356.     if (CPU->arch.family > 5) {
  357.         printf("LVT_PCINT: ");
  358.         if (l_apic[LVT_PCINT] & (1<<16)) printf("masked"); else printf("not masked"); putchar(',');
  359.         if (l_apic[LVT_PCINT] & (1<<12)) printf("send pending"); else printf("idle"); putchar(',');
  360.         switch ((l_apic[LVT_PCINT] >> 8)&7) {
  361.             case 0: printf("fixed"); break;
  362.             case 4: printf("NMI"); break;
  363.             case 7: printf("ExtINT"); break;
  364.         }
  365.         putchar(',');
  366.         printf("%B\n", l_apic[LVT_PCINT] & 0xff);
  367.     }
  368. #endif
  369. }
  370.  
  371. void l_apic_timer_interrupt(__u8 n, __native stack[])
  372. {
  373.     l_apic_eoi();
  374.     clock();
  375. }
  376.  
  377. __u8 l_apic_id(void)
  378. {
  379.     return (l_apic[L_APIC_ID] >> L_APIC_IDShift)&L_APIC_IDMask;
  380. }
  381.  
  382. __u32 io_apic_read(__u8 address)
  383. {
  384.     __u32 tmp;
  385.    
  386.     tmp = io_apic[IOREGSEL] & ~0xf;
  387.     io_apic[IOREGSEL] = tmp | address;
  388.     return io_apic[IOWIN];
  389. }
  390.  
  391. void io_apic_write(__u8 address, __u32 x)
  392. {
  393.     __u32 tmp;
  394.  
  395.     tmp = io_apic[IOREGSEL] & ~0xf;
  396.     io_apic[IOREGSEL] = tmp | address;
  397.     io_apic[IOWIN] = x;
  398. }
  399.  
  400. void io_apic_change_ioredtbl(int signal, int dest, __u8 v, int flags)
  401. {
  402.     io_redirection_reg_t reg;
  403.     int dlvr = 0;
  404.    
  405.     if (flags & LOPRI)
  406.         dlvr = DELMOD_LOWPRI;
  407.  
  408.    
  409.     reg.lo = io_apic_read(IOREDTBL + signal*2);
  410.     reg.hi = io_apic_read(IOREDTBL + signal*2 + 1);
  411.    
  412.     reg.dest =  dest;
  413.     reg.destmod = DESTMOD_LOGIC;
  414.     reg.trigger_mode = TRIGMOD_EDGE;
  415.     reg.intpol = POLARITY_HIGH;
  416.     reg.delmod = dlvr;
  417.     reg.intvec = v;
  418.  
  419.     io_apic_write(IOREDTBL + signal*2, reg.lo);
  420.     io_apic_write(IOREDTBL + signal*2 + 1, reg.hi);
  421. }
  422.  
  423. void io_apic_disable_irqs(__u16 irqmask)
  424. {
  425.     io_redirection_reg_t reg;
  426.     int i, pin;
  427.    
  428.     for (i=0;i<16;i++) {
  429.         if ((irqmask>>i) & 1) {
  430.             /*
  431.              * Mask the signal input in IO APIC if there is a
  432.              * mapping for the respective IRQ number.
  433.              */
  434.             pin = smp_irq_to_pin(i);
  435.             if (pin != -1) {
  436.                 reg.lo = io_apic_read(IOREDTBL + pin*2);
  437.                 reg.masked = true;
  438.                 io_apic_write(IOREDTBL + pin*2, reg.lo);
  439.             }
  440.            
  441.         }
  442.     }
  443. }
  444.  
  445. void io_apic_enable_irqs(__u16 irqmask)
  446. {
  447.     int i, pin;
  448.     io_redirection_reg_t reg;  
  449.    
  450.     for (i=0;i<16;i++) {
  451.         if ((irqmask>>i) & 1) {
  452.             /*
  453.              * Unmask the signal input in IO APIC if there is a
  454.              * mapping for the respective IRQ number.
  455.              */
  456.             pin = smp_irq_to_pin(i);
  457.             if (pin != -1) {
  458.                 reg.lo = io_apic_read(IOREDTBL + pin*2);
  459.                 reg.masked = false;
  460.                 io_apic_write(IOREDTBL + pin*2, reg.lo);
  461.             }
  462.            
  463.         }
  464.     }
  465.  
  466. }
  467.  
  468. #endif /* CONFIG_SMP */
  469.