免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: sisi8408

Kernel Bug-Vulnerability-Comment library [复制链接]

论坛徽章:
0
发表于 2007-12-01 18:30 |显示全部楼层

  1. /* linux-2.6.22.5/arch/i386/kernel/io_apic.c */
  2. static void __init setup_IO_APIC_irqs (void)
  3. {
  4.                 entry.trigger  = irq_trigger(idx);
  5.                 entry.polarity = irq_polarity(idx);
  6.                 /*2007-12-1 18:29
  7.                 if (entry.trigger) {
  8.                         entry.mask = 1;
  9.                 }
  10.                 */
  11.                 if (irq_trigger(idx)) {
  12.                         entry.trigger = 1;
  13.                         entry.mask = 1;
  14.                 }
  15.                 irq = pin_2_irq(idx, apic, pin);
  16. }
复制代码

this function maybe modified in a few ways in practical usage

论坛徽章:
0
发表于 2007-12-03 15:14 |显示全部楼层
申请一个指针,直接指向Y1调用出,最简单的是构造一个API变量,那么直接和系统底层NTLL函数调用,这样省去了中间件,硬件的吞吐量也会很大,整体性能也会上来,

最近没时间写代码,后面有时间补充上来

大家不要拍砖 ^_^

论坛徽章:
0
发表于 2007-12-03 15:15 |显示全部楼层
此段指向代码最好用汇编写  。。。。。。。。

具体写法 。。。。。。正在构思中  晚上发上来。。。。

论坛徽章:
0
发表于 2007-12-08 07:54 |显示全部楼层

  1. void set_pending_irq(unsigned int irq, cpumask_t mask)
  2. {
  3.         struct irq_desc *desc = irq_desc + irq;
  4.         unsigned long flags;

  5.         spin_lock_irqsave(&desc->lock, flags);
  6.         desc->status |= IRQ_MOVE_PENDING;
  7.         /* 2007-12-8 7:50
  8.          * linux-2.6.22.5/kernel/irq/migration.c
  9.          * desc->pending_mask = mask;
  10.          */
  11.         irq_desc[irq].pending_mask = mask;
  12.         spin_unlock_irqrestore(&desc->lock, flags);
  13. }

复制代码

论坛徽章:
0
发表于 2007-12-08 11:09 |显示全部楼层

  1. Touching APIC represented by GNU linux-2.6.22+
复制代码

  1. #ifndef _LINUX_IRQ_H
  2. #define _LINUX_IRQ_H
  3. /*
  4. * Please do not include this file in generic code.
  5. *
  6. * There is currently no requirement for any architecture
  7. * to implement anything held within this file.
  8. *
  9. * Thanks. --rmk
  10. *
  11. ××××××××××××××××××××××××××××××××××××
  12. * IRQ的处理,Ingo Molnar是大今天的赢家,
  13. * 2.6.21+ 迎来Ingo Molnar的时代,还有Andi Kleen in X86-64.
  14. *
  15. * 这种统一的设计方法,俺八哥百学不会,汗汗汗,
  16. × 类似的经典
  17. *        VFS,
  18. *        Block,       老鸟 Jens Axboe, Andrea Arcangeli
  19. *        Socket,     新秀 Arnaldo Carvalho de Melo
  20. ×        Netfilter,  新秀 Yasuyuki Kozakai的时代
  21. ××××××××××××××××××××××××××××××××××××
  22. ×
  23. × 2007/9--11月,八哥出京躲债,在APIC上吃了亏,今天想把这一课补上。
  24. * IRQ,软件的基本定义从<linux/irq.h>发源,
  25. × 硬件已经是XAPIC的时代,八哥想介绍几个关系,
  26. *        1, vector[IRQ]
  27. *        2, LAPIC[IRQ]/IOPIC[IRQ]
  28. *        3, cpu-balance[IRQ]
  29. *        4, request[IRQ]
  30. *
  31. * 代码来自linux-2.6.22.5 from kernel.org
  32. */

  33. request[IRQ]
  34. ============

  35. 先看熟悉的,菜鸟八哥这里仅限于PCI,
  36. request[IRQ]是IRQ subsystem给device driver提供的接口,

  37. static int e1000_request_irq (struct e1000_adapter *adapter)
  38. {
  39.         struct net_device *netdev = adapter->netdev;
  40.         void (*handler) = &e1000_intr;
  41.         int irq_flags = IRQF_SHARED;
  42.         int err;

  43.         if (adapter->hw.mac_type >= e1000_82571) {
  44.                 adapter->have_msi = !pci_enable_msi(adapter->pdev);
  45.                 if (adapter->have_msi) {
  46.                         handler = &e1000_intr_msi;
  47.                         irq_flags = 0;
  48.                 }
  49.         }

  50.         err = request_irq(adapter->pdev->irq, handler,
  51.                           irq_flags, netdev->name, netdev);
  52.         if (err) {
  53.                 if (adapter->have_msi)
  54.                         pci_disable_msi(adapter->pdev);
  55.                 DPRINTK(PROBE, ERR,
  56.                         "Unable to allocate interrupt Error: %d\n", err);
  57.         }
  58.         return err;
  59. }

  60. 设备/芯片的属性/能力不同,表现在request[IRQ]的操作上,

  61. 1,msi与non-msi两种模式
  62. [homework]
  63.         if (adapter->hw.mac_type >= e1000_82571) {
  64.                 adapter->have_msi = !pci_enable_msi(adapter->pdev);
  65.                 if (adapter->have_msi) {
  66.                         handler = &e1000_intr_msi;
  67.                         irq_flags = 0;
  68.                 }
  69.         } else
  70.                 irq_flags = 0;
  71. 又如何?
  72. [/homework]

  73. [homework]
  74. falgs 的定义在 <linux/interrupt.h>
  75. 请比较
  76.         flags |= IRQF_DISABLED ;
  77.         request_irq();

  78.         flags ~= IRQF_DISABLED ;
  79.         request_irq();
  80.        
  81. 的do_IRQ的上下文的区别,扯远啦。
  82. [/homework]

  83. 2,handler统吃两种模式,够牛吧,
  84.    非兮,应该是硬件支持。

  85. int pci_enable_msi (struct pci_dev *dev)
  86. {
  87.         int status;

  88.         status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
  89.         if (status)
  90.                 return status;

  91.         WARN_ON(!!dev->msi_enabled);

  92.         /* Check whether driver already requested for MSI-X irqs */
  93.         ///
  94.         /// nnd, MSI还没整明白,MSI-X又冒出来了,
  95.         /// 三天不学习,赶不上刘少奇
  96.         ///
  97.         if (dev->msix_enabled) {
  98.                 printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
  99.                         "Device already has MSI-X enabled\n",
  100.                         pci_name(dev));
  101.                 return -EINVAL;
  102.         }
  103.         status = msi_capability_init(dev);
  104.         return status;
  105. }

  106. static int pci_msi_check_device (struct pci_dev* dev, int nvec, int type)
  107. {
  108.         struct pci_bus *bus;
  109.         int ret;

  110.         /* MSI must be globally enabled and supported by the device */
  111.         ///
  112.         ///其一,CONFIG_MSI
  113.         ///
  114.         if (!pci_msi_enable || !dev || dev->no_msi)
  115.                 return -EINVAL;

  116.         /*
  117.          * You can't ask to have 0 or less MSIs configured.
  118.          *  a) it's stupid ..
  119.          *  b) the list manipulation code assumes nvec >= 1.
  120.          */
  121.         if (nvec < 1)
  122.                 return -ERANGE;

  123.         /* Any bridge which does NOT route MSI transactions from it's
  124.          * secondary bus to it's primary bus must set NO_MSI flag on
  125.          * the secondary pci_bus.
  126.          * We expect only arch-specific PCI host bus controller driver
  127.          * or quirks for specific PCI bridges to be setting NO_MSI.
  128.          */
  129.         ///
  130.         ///其二,要求芯片组上下贯通,丝毫不含糊
  131.         ///
  132.         for (bus = dev->bus; bus; bus = bus->parent)
  133.                 if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
  134.                         return -EINVAL;

  135.         ///
  136.         ///其三,查询其他要求
  137.         ///
  138.         ret = arch_msi_check_device(dev, nvec, type);
  139.         if (ret)
  140.                 return ret;
  141.         ///
  142.         ///其四,设备要有能力
  143.         ///
  144.         if (!pci_find_capability(dev, type))
  145.                 return -EINVAL;

  146.         return 0;
  147. }

  148. 3,pdev->irq 哪来的?

  149. static void __init pdev_fixup_irq (struct pci_dev *dev,
  150.                 u8 (*swizzle)(struct pci_dev *, u8 *),
  151.                 int (*map_irq)(struct pci_dev *, u8, u8))
  152. {
  153.         u8 pin, slot;
  154.         int irq = 0;
  155.         /*
  156.         If this device is not on the primary bus,
  157.         we need to figure out which interrupt pin it will come in on.
  158.        
  159.         We know which slot it will come in on 'cos that slot is where the bridge is.

  160.         Each time the interrupt line passes through a PCI-PCI bridge we must
  161.         apply the swizzle function.
  162.         */
  163.         pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
  164.         /* Cope with illegal */
  165.         if (pin > 4)
  166.                 pin = 1;

  167.         if (pin != 0) {
  168.                 /* Follow the chain of bridges, swizzling as we go.  */
  169.                 slot = (*swizzle)(dev, &pin);
  170.                 irq  = (*map_irq)(dev, slot, pin);
  171.                
  172.                 if (irq == -1)
  173.                         irq = 0;
  174.         }
  175.         ///
  176.         ///其二,原来如此
  177.         /// pci dev 在PCI空间是 bus:slot.fun
  178.         /// 在APCI空间是 bus:slot.pin,这是后话
  179. /***
  180. static void pci_read_irq (struct pci_dev *dev)
  181. {
  182.         unsigned char irq;

  183.         pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
  184.         dev->pin = irq;

  185.         if (irq)
  186.                 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);

  187.         ///
  188.         ///其三,PCI_INTERRUPT_PIN 与PCI_INTERRUPT_LINE的统一
  189.         ///
  190.         dev->irq = irq;
  191. }
  192. ***/
  193.         dev->irq = irq;

  194.         pr_debug("PCI: fixup irq: (%s) got irq%d\n",
  195.                 dev->dev.kobj.name, dev->irq);

  196.         /* Always tell the device, so the driver knows what is
  197.            the real IRQ to use; the device does not use it.
  198.         */
  199.         pcibios_update_irq(dev, irq);
  200. }

  201. void __init pci_fixup_irqs (u8 (*swizzle)(struct pci_dev *, u8 *),
  202.                                 int (*map_irq)(struct pci_dev *, u8, u8))
  203. {
  204.         struct pci_dev *dev = NULL;
  205.         ///
  206.         ///其一,都在这了,呵呵
  207.         ///
  208.         while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
  209.                 pdev_fixup_irq(dev, swizzle, map_irq);
  210.         }
  211. }
  212. [homework]
  213. MSI的IRQ如何不同,有的驱动在这儿就没有留心。
  214. [/homework]
复制代码


参加Linux爱好者技术聚会,去喽。。。

[ 本帖最后由 sisi8408 于 2007-12-8 11:16 编辑 ]

论坛徽章:
0
发表于 2007-12-09 10:31 |显示全部楼层

  1. vector[IRQ]
  2. ===========

  3. Understanding 有一章介绍Vector和IDT(Interrupt Description Table),
  4. 八哥看的是第二版,其基本定义在

  5. #ifndef _ASM_HW_IRQ_H
  6. #define _ASM_HW_IRQ_H
  7. /*
  8. * linux/include/asm/hw_irq.h
  9. *
  10. * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
  11. *
  12. * moved some of the old arch/i386/kernel/irq.h to here. VY
  13. *
  14. * IRQ/IPI changes taken from work by Thomas Radke
  15. * <[email]tomsoft@informatik.tu-chemnitz.de[/email]>
  16. *
  17. * hacked by Andi Kleen for x86-64
  18. */
  19. 相对i386,x86-64的情况简单些,

  20. #define NMI_VECTOR                0x02
  21. /*
  22. * IDT vectors usable for external interrupt sources start
  23. * at 0x20:
  24. ×
  25. × 0x00--0x1f被处理器占用,in kernel/traps.c

  26. void __init trap_init(void)
  27. {
  28.         set_intr_gate(0,&divide_error);
  29.         set_intr_gate_ist(1,&debug,DEBUG_STACK);
  30.         set_intr_gate_ist(2,&nmi,NMI_STACK);
  31.         set_system_gate_ist(3,&int3,DEBUG_STACK); /* int3 can be called from all */
  32.         set_system_gate(4,&overflow);        /* int4 can be called from all */
  33.         set_intr_gate(5,&bounds);
  34.         set_intr_gate(6,&invalid_op);
  35.         set_intr_gate(7,&device_not_available);
  36.         set_intr_gate_ist(8,&double_fault, DOUBLEFAULT_STACK);
  37.         set_intr_gate(9,&coprocessor_segment_overrun);
  38.         set_intr_gate(10,&invalid_TSS);
  39.         set_intr_gate(11,&segment_not_present);
  40.         set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
  41.         set_intr_gate(13,&general_protection);
  42.         set_intr_gate(14,&page_fault);
  43.         set_intr_gate(15,&spurious_interrupt_bug);
  44.         set_intr_gate(16,&coprocessor_error);
  45.         set_intr_gate(17,&alignment_check);
  46. #ifdef CONFIG_X86_MCE
  47.         set_intr_gate_ist(18,&machine_check, MCE_STACK);
  48. #endif
  49.         set_intr_gate(19,&simd_coprocessor_error);

  50. #ifdef CONFIG_IA32_EMULATION
  51.         set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
  52. #endif
  53.       
  54.         /*
  55.          * Should be a barrier for any external CPU state.
  56.          */
  57.         cpu_init();
  58. }
  59. ×××××××××××××
  60. */
  61. #define FIRST_EXTERNAL_VECTOR        0x20

  62. #define IA32_SYSCALL_VECTOR        0x80



  63. /* Reserve the lowest usable priority level 0x20 - 0x2f for triggering
  64. * cleanup after irq migration.
  65. */
  66. #define IRQ_MOVE_CLEANUP_VECTOR        FIRST_EXTERNAL_VECTOR
  67. /*
  68. * Vectors 0x30-0x3f are used for ISA interrupts.
  69. *
  70. * 所谓的16个legacy IRQ被映射到vector[0x30--0x3f]
  71. */
  72. #define IRQ0_VECTOR                FIRST_EXTERNAL_VECTOR + 0x10 ///0x20 + 0x10 = 0x30
  73. #define IRQ1_VECTOR                IRQ0_VECTOR + 1
  74. #define IRQ2_VECTOR                IRQ0_VECTOR + 2
  75. #define IRQ3_VECTOR                IRQ0_VECTOR + 3
  76. #define IRQ4_VECTOR                IRQ0_VECTOR + 4
  77. #define IRQ5_VECTOR                IRQ0_VECTOR + 5
  78. #define IRQ6_VECTOR                IRQ0_VECTOR + 6
  79. #define IRQ7_VECTOR                IRQ0_VECTOR + 7
  80. #define IRQ8_VECTOR                IRQ0_VECTOR + 8
  81. #define IRQ9_VECTOR                IRQ0_VECTOR + 9
  82. #define IRQ10_VECTOR                IRQ0_VECTOR + 10
  83. #define IRQ11_VECTOR                IRQ0_VECTOR + 11
  84. #define IRQ12_VECTOR                IRQ0_VECTOR + 12
  85. #define IRQ13_VECTOR                IRQ0_VECTOR + 13
  86. #define IRQ14_VECTOR                IRQ0_VECTOR + 14
  87. #define IRQ15_VECTOR                IRQ0_VECTOR + 15

  88. /*
  89. * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
  90. *
  91. *  some of the following vectors are 'rare', they are merged
  92. *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
  93. *
  94. *  TLB, reschedule and local APIC vectors are performance-critical.
  95. */
  96. #define SPURIOUS_APIC_VECTOR        0xff
  97. #define ERROR_APIC_VECTOR        0xfe
  98. #define RESCHEDULE_VECTOR        0xfd
  99. #define CALL_FUNCTION_VECTOR        0xfc
  100. /*
  101.   0xfb free - please don't re-add KDB here because it's useless
  102.   (hint - think what a NMI bit does to a vector)
  103. */
  104. #define THERMAL_APIC_VECTOR        0xfa
  105. #define THRESHOLD_APIC_VECTOR   0xf9
  106. /*
  107.   0xf8 free
  108. */
  109. #define INVALIDATE_TLB_VECTOR_END        0xf7
  110. #define INVALIDATE_TLB_VECTOR_START        0xf0        /* 0xf0--0xf7 used for TLB flush */

  111. #define NUM_INVALIDATE_TLB_VECTORS        8        /* 0xf0--0xf7 */

  112. /*
  113. * Local APIC timer IRQ vector is on a different priority level,
  114. * to work around the 'lost local interrupt if more than 2 IRQ
  115. * sources per level' errata.
  116. */
  117. #define LOCAL_TIMER_VECTOR        0xef

  118. /*
  119. * First APIC vector available to drivers: (vectors 0x30-0xee)
  120. * we start at 0x41 to spread out vectors evenly between priority
  121. * levels. (0x80 is the syscall vector)
  122. *
  123. * 有了vector和IRQ的映射关系,还要主意 priority levels.
  124. */
  125. #define FIRST_DEVICE_VECTOR        (IRQ15_VECTOR + 2)
  126. #define FIRST_SYSTEM_VECTOR        0xef   /* duplicated in irq.h */

  127. #ifndef __ASSEMBLY__
  128. typedef int vector_irq_t[NR_VECTORS];
  129. DECLARE_PER_CPU(vector_irq_t, vector_irq);
  130. /*
  131. * 映射关系的具体实现,int[NR_CPUS][NR_VECTORS];
  132. */
  133. extern void __setup_vector_irq(int cpu);
  134. /*
  135. * 映射关系的操作方法
  136. */
  137. extern spinlock_t vector_lock;

  138. /*
  139. * Various low-level irq details needed by
  140. *        irq.c,
  141. *        process.c,
  142. *        time.c,
  143. *        io_apic.c and
  144. *        smp.c
  145. *
  146. * 如此多,如此诱惑的金矿,镐在哪?
  147. *
  148. * Interrupt entry/exit code at both C and assembly level
  149. */

  150. extern void disable_8259A_irq(unsigned int irq);
  151. extern void enable_8259A_irq(unsigned int irq);
  152. /*
  153. * 8259A的系列操作
  154. */
  155. extern int i8259A_irq_pending(unsigned int irq);
  156. extern void make_8259A_irq(unsigned int irq);
  157. extern void init_8259A(int aeoi);

  158. extern void send_IPI(int dest, int vector);
  159. /*
  160. * IPI, inter-processor interrupt 操作
  161. *
  162. [homework]
  163. 搜出所有的IPI操作,under arch/x86_64,
  164. 仔细揣摩,玩法多多。
  165. [/homework]
  166. */
  167. extern void send_IPI_self(int vector);

  168. extern void init_VISWS_APIC_irqs(void);

  169. extern void setup_IO_APIC(void);
  170. extern void disable_IO_APIC(void);
  171. /*
  172. * IO_APIC的系列操作,后文慢慢说
  173. */
  174. extern void print_IO_APIC(void);
  175. extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
  176. extern void setup_ioapic_dest(void);

  177. extern unsigned long io_apic_irqs;

  178. extern atomic_t irq_err_count;
  179. extern atomic_t irq_mis_count;
  180. /*
  181. io_apic_irqs 是 bitmap??
  182. */
  183. #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))

  184. #define __STR(x) #x
  185. #define STR(x) __STR(x)

  186. #include <asm/ptrace.h>

  187. #define IRQ_NAME2(nr) nr##_interrupt(void)
  188. #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

  189. /*
  190. * SMP has a few special interrupts for IPI messages
  191. *
  192. * 请说明 #define BUILD_IRQ(nr)
  193. */
  194. #define BUILD_IRQ(nr) \
  195. asmlinkage void IRQ_NAME(nr);        \
  196. __asm__("\n.p2align\n"                \
  197.         "IRQ" #nr "_interrupt:\n\t" \
  198.         "push $~(" #nr ") ; " \
  199.         "jmp common_interrupt");


  200. #define platform_legacy_irq(irq)        ((irq) < 16)

  201. #endif
  202. #endif /* _ASM_HW_IRQ_H */

  203. ///
  204. ///中断发生时,vector 的操作在 arch/kernel/head.S
  205. ///vector[IRQ]如何填充??
  206. ///
复制代码

论坛徽章:
0
发表于 2007-12-09 17:25 |显示全部楼层

  1. APIC[IRQ]
  2. =========

  3. #ifndef __ASM_APICDEF_H
  4. #define __ASM_APICDEF_H
  5. /*
  6. * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
  7. *
  8. * Alan Cox <[email]Alan.Cox@linux.org[/email]>, 1995.
  9. * Ingo Molnar <[email]mingo@redhat.com[/email]>, 1999, 2000
  10. */
  11. #define MAX_IO_APICS        128
  12. #define MAX_LOCAL_APIC        256
  13. ///
  14. /// APIC = Local APIC + IO APIC
  15. /// 相比 IO APIC,LAPIC要简单些,
  16. /// 软件描述为 struct local_apic。
  17. ///
  18. /// 多处理器环境,cpu = smp_processor_id();
  19. /// boot_cpu = 0; 这是逻辑编号;还有phy_cpu_id[cpu]编号。
  20. ///
  21. /// 在APIC空间,phy_lapic_id[nr], 0 <= nr <  MAX_LOCAL_APIC,
  22. /// cpu还有与nr的映射关系,cpu = lapic_cpu[nr]。
  23. ///
  24. /// 八哥从来不看Manul, either Intel or AMD,
  25. /// 实话是看不懂,只在代码里面体会。
  26. /// 这里摘录Understanding-II,
  27. /// 1,CPU包含一部分called LAPIC
  28. /// 2,LAPIC包含:
  29. ///                 一堆寄存器        /* in struct local_apic */
  30. ///                 一个内部时钟
  31. ///                 LINT0/1
  32. ///
  33. /// 3, IOAPIC包含:
  34. ///                 N条IRQ线
  35. ///                 N项IRT,interrupt routing/redirection table
  36. ///    IRT可以被独立编程,指明
  37. ///                    中断向量
  38. ///                    优先级
  39. ///                    目标处理器        /* represented by lapic */
  40. ///                    选择处理器的方式
  41. ///
  42. /// 4, 中断的分发方式
  43. ///        4.1  静态分发
  44. ///             查IRT中设定的LAPIC,可以是一个CPU,多个CPU, 全部CPU。
  45. ///
  46. ///        4.2  动态分发
  47. ///             4.2.1  根据正在运行的进程的优先级,发送给低优先级。
  48. ///                    因为LAPIC有可编程TPR,task priority register.
  49. ///             4.2.2  优先级不能决定时,由arbitration决定。
  50. ///
  51. /// 5,通过写LAPIC的ICR,interrupt command register,
  52. ///    产生IPI,inter-processor interrupt             
  53. ///
  54. /// APIC的着眼点是P,在代码中领会,
  55. /// LAPIC的中断分发,IOAPIC的IRT。
  56. ///

  57. /*
  58. * All x86-64 systems are xAPIC compatible.
  59. * In the following, "apicid" is a physical APIC ID.
  60. */
  61. #define XAPIC_DEST_CPUS_SHIFT        4
  62. #define XAPIC_DEST_CPUS_MASK        ((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
  63. #define XAPIC_DEST_CLUSTER_MASK        (XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)

  64. #define APIC_CLUSTER(apicid)        ((apicid) & XAPIC_DEST_CLUSTER_MASK)
  65. #define APIC_CLUSTERID(apicid)        (APIC_CLUSTER(apicid) >> XAPIC_DEST_CPUS_SHIFT)
  66. /*
  67. * cluster:         high 4 bits
  68. * cpu:                low  4 bits
  69. */
  70. #define APIC_CPUID(apicid)        ((apicid) & XAPIC_DEST_CPUS_MASK)
  71. #define NUM_APIC_CLUSTERS        ((BAD_APICID + 1) >> XAPIC_DEST_CPUS_SHIFT)

  72. /*
  73. * Basic functions accessing LAPIC
  74. *
  75. * 类似 pci_read_config_dword
  76. */
  77. static __inline void apic_write(unsigned long reg, unsigned int v)
  78. {
  79.         *((volatile unsigned int *)(APIC_BASE+reg)) = v;
  80. }

  81. static __inline unsigned int apic_read(unsigned long reg)
  82. {
  83.         return *((volatile unsigned int *)(APIC_BASE+reg));
  84. }
  85. /*
  86. * Basic functions 的具体应用
  87. */
  88. static inline void ack_APIC_irq(void)
  89. {
  90.         /*
  91.          * ack_APIC_irq() actually gets compiled as a single instruction:
  92.          * - a single rmw on Pentium/82489DX
  93.          * - a single write on P6+ cores (CONFIG_X86_GOOD_APIC)
  94.          * ... yummie.
  95.          */

  96.         /* Docs say use 0 for future compatibility */
  97.         apic_write(APIC_EOI, 0);
  98. }
  99. /*
  100.   有了basic,就可以摆弄寄存器了,
  101.   八哥坚持认为,摆弄寄存器是三流代码,照着manul添就是了,
  102.   不如CFQ in block, CBQ in QoS自由和浪漫,
  103.   不过,摆弄好了,也是功夫。
  104. */
  105. extern int get_maxlvt (void);
  106. extern void clear_local_APIC (void);
  107. extern void connect_bsp_APIC (void);
  108. extern void disconnect_bsp_APIC (int virt_wire_setup);
  109. extern void disable_local_APIC (void);
  110. extern int verify_local_APIC (void);
  111. extern void cache_APIC_registers (void);
  112. extern void sync_Arb_IDs (void);
  113. extern void init_bsp_APIC (void);
  114. extern void setup_local_APIC (void);
  115. extern void init_apic_mappings (void);
  116. extern void smp_local_timer_interrupt (void);
  117. extern void setup_boot_APIC_clock (void);
  118. extern void setup_secondary_APIC_clock (void);
  119. extern int APIC_init_uniprocessor (void);
  120. extern void disable_APIC_timer(void);
  121. extern void enable_APIC_timer(void);
  122. extern void setup_apic_routing(void);

  123. extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
  124.                                    unsigned char msg_type, unsigned char mask);

  125. #define K8_APIC_EXT_LVT_BASE    0x500
  126. #define K8_APIC_EXT_INT_MSG_FIX 0x0
  127. #define K8_APIC_EXT_INT_MSG_SMI 0x2
  128. #define K8_APIC_EXT_INT_MSG_NMI 0x4
  129. #define K8_APIC_EXT_INT_MSG_EXT 0x7
  130. #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD    0

  131. void smp_send_timer_broadcast_ipi(void);
  132. void switch_APIC_timer_to_ipi(void *cpumask);
  133. void switch_ipi_to_APIC_timer(void *cpumask);

  134. #define ARCH_APICTIMER_STOPS_ON_C3        1

  135. extern unsigned boot_cpu_id;
  136. extern int local_apic_timer_c2_ok;
复制代码

论坛徽章:
0
发表于 2007-12-14 23:17 |显示全部楼层

  1. /*  ===== in x86_64/kernel/apic.c ====== */

  2. static __init int setup_disableapic(char *str)
  3. {
  4.         disable_apic = 1;
  5.         /*
  6.          * P not only in APIC, but also
  7.          */
  8.         clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
  9.         return 0;
  10. }
  11. early_param("disableapic", setup_disableapic);

  12. /*
  13. * This initializes the IO-APIC and APIC hardware if this is
  14. * a UP kernel.
  15. */
  16. int __init APIC_init_uniprocessor(void)
  17. {
  18.         if (disable_apic) {
  19.                 printk(KERN_INFO "Apic disabled\n");
  20.                 return -1;
  21.         }
  22.         if (!cpu_has_apic) {
  23.                 disable_apic = 1;
  24.                 printk(KERN_INFO "Apic disabled by BIOS\n");
  25.                 return -1;
  26.         }
  27.         verify_local_APIC();

  28.         phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
  29.         /*
  30.          * 1, what cpu is in APIC space
  31.          */
  32.         apic_write(APIC_ID, SET_APIC_ID(boot_cpu_id));
  33.         /*
  34.          * 2, LAPIC first
  35.          */
  36.         setup_local_APIC();

  37.         if (smp_found_config
  38.             && !skip_ioapic_setup
  39.             && nr_ioapics) {
  40.         /*
  41.          * 3, then IO APIC if at least smp_found_config
  42.          *    why??
  43.          *        maybe IRT unecessary
  44.          */
  45.                 setup_IO_APIC();
  46.         } else
  47.                 nr_ioapics = 0;

  48.         /*
  49.          * 4, and LAPIC clock
  50.          */
  51.         setup_boot_APIC_clock();
  52.         /*
  53.          * 5, finally NMI
  54.          */
  55.         check_nmi_watchdog();
  56.         return 0;
  57. }

  58. asmlinkage void smp_error_interrupt(void)
  59. {
  60.         unsigned int v, v1;

  61.         exit_idle();
  62.         irq_enter();
  63.         /*
  64.           First tickle the hardware,
  65.           only then report what went on.
  66.           -- REW
  67.         */
  68.         v = apic_read(APIC_ESR);
  69.         apic_write(APIC_ESR, 0);
  70.         v1 = apic_read(APIC_ESR);
  71.         ack_APIC_irq();
  72.         /*
  73.          * and the order is important, why not???
  74.         v = apic_read(APIC_ESR);
  75.         apic_write(APIC_ESR, 0);
  76.         ack_APIC_irq();
  77.         v1 = apic_read(APIC_ESR);
  78.          */
  79.         atomic_inc(&irq_err_count);

  80.         /* Here is what the APIC error bits mean:
  81.            0: Send CS error
  82.            1: Receive CS error
  83.            2: Send accept error
  84.            3: Receive accept error
  85.            4: Reserved
  86.            5: Send illegal vector
  87.            6: Received illegal vector
  88.            7: Illegal register address
  89.         */
  90.         printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
  91.                 smp_processor_id(), v , v1);
  92.         irq_exit();
  93. }

  94. asmlinkage void smp_spurious_interrupt (void)
  95. {
  96.         unsigned int v;

  97.         exit_idle();
  98.         irq_enter();
  99.         /*
  100.          * Check if this really is a spurious interrupt and ACK it.
  101.          * if it is a vectored one.  Just in case...
  102.          * Spurious interrupts should not be ACKed.
  103.          */
  104.         v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
  105.         if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
  106.                 ack_APIC_irq();

  107. /* ack should be ASAP,
  108. * and tell user innomarl occured,
  109. *
  110. * 八哥遇见e100-82559中断无人处理的情况,on Intel-5110,
  111. * 系统将其关闭。
  112. */
  113. {
  114.         static unsigned long last_warning;
  115.         static unsigned long skipped;

  116.         /* see sw-dev-man vol 3, chapter 7.4.13.5 */
  117. ///        if (time_before(last_warning+30*HZ, jiffies)) {
  118.         if (time_before(jiffies, last_warning +30*HZ)) {
  119.                 printk(KERN_INFO
  120.                 "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
  121.                 smp_processor_id(), skipped);
  122.                 last_warning = jiffies;
  123.                 skipped = 0;
  124.         } else {
  125.                 skipped++;
  126.         }
  127. }
  128.         irq_exit();
  129. }

  130. /*
  131. * LAPIC包含一个内部时钟 and operation
  132. */
  133. void enable_APIC_timer (void)
  134. {
  135.         /*
  136.          * 多数情况的应用是logic cpu number
  137.          */
  138.         int cpu = smp_processor_id();

  139.         if (using_apic_timer &&
  140.             !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
  141.                 unsigned long v;

  142.                 v = apic_read(APIC_LVTT);
  143.                 apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
  144.         }
  145. }
  146. /*
  147. * goto read manul by AMD
  148. */
  149. void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
  150.                             unsigned char msg_type, unsigned char mask)
  151. {
  152.         unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
  153.         unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
  154.         apic_write(reg, v);
  155. }

  156. void smp_send_timer_broadcast_ipi(void)
  157. {
  158.         int cpu = smp_processor_id();
  159.         cpumask_t mask;

  160.         cpus_and(mask, cpu_online_map,
  161.                  timer_interrupt_broadcast_ipi_mask);

  162.         if (cpu_isset(cpu, mask)) {
  163.                 cpu_clear(cpu, mask);
  164.                 add_pda(apic_timer_irqs, 1);
  165.                 smp_local_timer_interrupt();
  166.         }
  167.         /*
  168.          * 请 cpus in mask do IRQ represented by LOCAL_TIMER_VECTOR,
  169.          * cpu 不懂IRQ,but vector
  170.          *
  171.          * 这样的应用方式大有意思。
  172.          */
  173.         if (!cpus_empty(mask))
  174.                 send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
  175. }
  176. /*
  177. * 编程APIC,启用timer
  178. */
  179. void enable_APIC_timer (void)
  180. {
  181.         int cpu = smp_processor_id();

  182.         if (using_apic_timer &&
  183.             !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
  184.                 unsigned long v;

  185.                 v = apic_read(APIC_LVTT);
  186.                 apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
  187.         }
  188. }

  189. static int __init calibrate_APIC_clock(void)
  190. {
  191.         unsigned apic, apic_start;
  192.         unsigned long tsc, tsc_start;
  193.         int result;
  194.         /*
  195.          * Put whatever arbitrary (but long enough) timeout
  196.          * value into the APIC clock, we just want to get the
  197.          * counter running for calibration.
  198.          */
  199.         __setup_APIC_LVTT(4000000000);

  200.         apic_start = apic_read(APIC_TMCCT);
  201.        
  202. #ifdef CONFIG_X86_PM_TIMER
  203.         if (apic_calibrate_pmtmr && pmtmr_ioport) {
  204.                 pmtimer_wait(5000);  /* 5ms wait */
  205.                 apic = apic_read(APIC_TMCCT);
  206.                 result = (apic_start - apic) * 1000L / 5;
  207.         } else
  208. #endif
  209.         {
  210.         /*
  211.          * tsc, timestamp counter,
  212.          * 这个准一些,亚纳秒级的精度。
  213.          */
  214.                 rdtscll(tsc_start);

  215.                 do {
  216.                         apic = apic_read(APIC_TMCCT);
  217.                         rdtscll(tsc);
  218.                 } while ((tsc - tsc_start) < TICK_COUNT &&
  219.                         (apic_start - apic) < TICK_COUNT);

  220.                 /* 得到微秒级的结果 */
  221.                 result = (apic_start - apic) * 1000L * tsc_khz /
  222.                                         (tsc - tsc_start);
  223.         }
  224.         printk("result %d\n", result);

  225.         printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
  226.                 result / 1000 / 1000, result / 1000 % 1000);

  227.         return result * APIC_DIVISOR / HZ;
  228. }
  229. /*
  230. * This function sets up the local APIC timer,
  231. * with a timeout of 'clocks' APIC bus clock.
  232. */
  233. static void __setup_APIC_LVTT(unsigned int clocks)
  234. {
  235.         unsigned int lvtt_value, tmp_value;
  236.         int cpu = smp_processor_id();

  237.         lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;

  238.         if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
  239.                 lvtt_value |= APIC_LVT_MASKED;
  240.         apic_write(APIC_LVTT, lvtt_value);

  241.         /*
  242.          * Divide PICLK by 16
  243.          * 32, 64...1024 未必不可,不过没试过。
  244.          * 看看如何影响 Ingo Molnar的HPET
  245.          */
  246.         tmp_value = apic_read(APIC_TDCR);
  247.         apic_write(APIC_TDCR,
  248.           (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
  249.           | APIC_TDR_DIV_16);

  250.         apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
  251. }

  252. void __init init_apic_mappings(void)
  253. {
  254.         unsigned long apic_phys;
  255.         /*
  256.          * If no local APIC can be found then set up a fake all
  257.          * zeroes page to simulate the local APIC and another
  258.          * one for the IO-APIC.
  259.          */
  260.         if (!smp_found_config && detect_init_APIC()) {
  261.                 apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
  262.                 apic_phys = __pa(apic_phys);
  263.         } else /*
  264.                 * 当然是硬件的,
  265.                 * smp_found_config的由来,下回再说。
  266.                 */
  267.                 apic_phys = mp_lapic_addr;

  268.         set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
  269.         apic_mapped = 1;
  270.         apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n",
  271.                         APIC_BASE, apic_phys);

  272.         /* Put local APIC into the resource map. */
  273.         lapic_resource.start = apic_phys;
  274.         lapic_resource.end = lapic_resource.start + PAGE_SIZE - 1;
  275.         insert_resource(&iomem_resource, &lapic_resource);

  276.         /*
  277.          * Fetch the APIC ID of the BSP in case we have a
  278.          * default configuration (or the MP table is broken).
  279.          *
  280.          * 对应smp_processor_id
  281.          */
  282.         boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));

  283.         {
  284.                 unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
  285.                 int i;
  286.                 struct resource *ioapic_res;

  287.                 ioapic_res = ioapic_setup_resources();
  288.                 for (i = 0; i < nr_ioapics; i++) {
  289.                         if (smp_found_config) {
  290.                                 ioapic_phys = mp_ioapics[i].mpc_apicaddr;
  291.                         } else {
  292.                                 ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
  293.                                 ioapic_phys = __pa(ioapic_phys);
  294.                         }
  295.                         set_fixmap_nocache(idx, ioapic_phys);
  296.                         apic_printk(APIC_VERBOSE,
  297.                                 "mapped IOAPIC to %016lx (%016lx)\n",
  298.                                 __fix_to_virt(idx), ioapic_phys);
  299.                         idx++;

  300.                         if (ioapic_res != NULL) {
  301.                                 ioapic_res->start = ioapic_phys;
  302.                                 ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
  303.                                 ioapic_res++;
  304.                         }
  305.                 }
  306.         }
  307. }

  308. static int lapic_suspend(struct sys_device *dev, pm_message_t state);
  309. /*
  310. * 变化真快,LAPIC也睡觉,
  311. * 还是请球王alb讲讲ACPI
  312. */
  313. static int lapic_resume(struct sys_device *dev)

  314. void __cpuinit setup_local_APIC (void)
  315. {
  316.         unsigned int value, maxlvt;
  317.         int i, j;

  318.         value = apic_read(APIC_LVR);

  319.         BUILD_BUG_ON((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f);

  320.         /*
  321.          * Double-check whether this APIC is really registered.
  322.          * This is meaningless in clustered apic mode, so we skip it.
  323.          */
  324.         if (!apic_id_registered())
  325.                 BUG();

  326.         /*
  327.          * Intel recommends to set DFR, LDR and TPR before enabling
  328.          * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  329.          * document number 292116).  So here it goes...
  330.          */
  331.         init_apic_ldr();

  332.         /*
  333.          * Set Task Priority to 'accept all'.
  334.          * We never change this later on.
  335.          *
  336.          * 其一,linux 处理LAPIC与IOAPIC的关系如此简单,
  337.          * 这是主要关系
  338.          */
  339.         value = apic_read(APIC_TASKPRI);
  340.         value &= ~APIC_TPRI_MASK;
  341.         apic_write(APIC_TASKPRI, value);

  342.         /*
  343.          * After a crash, we no longer service the interrupts and a pending
  344.          * interrupt from previous kernel might still have ISR bit set.
  345.          *
  346.          * Most probably by now CPU has serviced that pending interrupt and
  347.          * it might not have done the ack_APIC_irq() because it thought,
  348.          * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
  349.          * does not clear the ISR bit and cpu thinks it has already serivced
  350.          * the interrupt. Hence a vector might get locked. It was noticed
  351.          * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
  352.          */
  353.         for (i = APIC_ISR_NR - 1; i >= 0; i--) {
  354.                 value = apic_read(APIC_ISR + i*0x10);
  355.                 for (j = 31; j >= 0; j--) {
  356.                         if (value & (1<<j))
  357.                                 ack_APIC_irq();
  358.                 }
  359.         }

  360.         /*
  361.          * Now that we are all set up, enable the APIC
  362.          */
  363.         value = apic_read(APIC_SPIV);
  364.         value &= ~APIC_VECTOR_MASK;
  365.         /*
  366.          * Enable APIC
  367.          */
  368.         value |= APIC_SPIV_APIC_ENABLED;

  369.         /* We always use processor focus */
  370.         /*
  371.          * Set spurious IRQ vector
  372.          */
  373.         value |= SPURIOUS_APIC_VECTOR;
  374.         apic_write(APIC_SPIV, value);

  375.         /*
  376.          * Set up LVT0, LVT1:
  377.          *
  378.          * set up through-local-APIC on the BP's LINT0. This is not
  379.          * strictly necessary in pure symmetric-IO mode, but sometimes
  380.          * we delegate interrupts to the 8259A.
  381.          */
  382.         /*
  383.          * TODO: set up through-local-APIC from through-I/O-APIC? --macro
  384.          */
  385.         value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
  386.         if (!smp_processor_id() && !value) {
  387.                 value = APIC_DM_EXTINT;
  388.                 apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
  389.         } else {
  390.                 value = APIC_DM_EXTINT | APIC_LVT_MASKED;
  391.                 apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
  392.         }
  393.         apic_write(APIC_LVT0, value);

  394.         /*
  395.          * only the BP should see the LINT1 NMI signal, obviously.
  396.          */
  397.         if (!smp_processor_id())
  398.                 value = APIC_DM_NMI;
  399.         else
  400.                 value = APIC_DM_NMI | APIC_LVT_MASKED;
  401.         apic_write(APIC_LVT1, value);

  402.         {
  403.                 unsigned oldvalue;
  404.                
  405.                 maxlvt = get_maxlvt();
  406.                 oldvalue = apic_read(APIC_ESR);
  407.                 value = ERROR_APIC_VECTOR;      // enables sending errors
  408.                 apic_write(APIC_LVTERR, value);
  409.                 /*
  410.                  * spec says clear errors after enabling vector.
  411.                  */
  412.                 if (maxlvt > 3)
  413.                         apic_write(APIC_ESR, 0);
  414.                 value = apic_read(APIC_ESR);
  415.                 if (value != oldvalue)
  416.                         apic_printk(APIC_VERBOSE,
  417.                         "ESR value after enabling vector: %08x, after %08x\n",
  418.                         oldvalue, value);
  419.         }
  420.         nmi_watchdog_default();
  421.         setup_apic_nmi_watchdog(NULL);
  422.         apic_pm_activate();
  423. }

  424. void __init init_bsp_APIC(void)
  425. {
  426.         unsigned int value;

  427.         /*
  428.          * Don't do the setup now if we have a SMP BIOS as the
  429.          * through-I/O-APIC virtual wire mode might be active.
  430.          */
  431.         if (smp_found_config || !cpu_has_apic)
  432.                 return;

  433.         value = apic_read(APIC_LVR);

  434.         /*
  435.          * Do not trust the local APIC being empty at bootup.
  436.          */
  437.         clear_local_APIC();

  438.         /*
  439.          * Enable APIC.
  440.          */
  441.         value = apic_read(APIC_SPIV);
  442.         value &= ~APIC_VECTOR_MASK;
  443.         value |= APIC_SPIV_APIC_ENABLED;
  444.         /*
  445.          * 其二,BSP不用FOCUS
  446.          */
  447.         value |= APIC_SPIV_FOCUS_DISABLED;
  448.         value |= SPURIOUS_APIC_VECTOR;
  449.         apic_write(APIC_SPIV, value);

  450.         /*
  451.          * Set up the virtual wire mode.
  452.          */
  453.         apic_write(APIC_LVT0, APIC_DM_EXTINT);
  454.         value = APIC_DM_NMI;
  455.         apic_write(APIC_LVT1, value);
  456. }

  457. void __init sync_Arb_IDs(void)
  458. {
  459.         /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
  460.         unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
  461.        
  462.         /* P4 or higher
  463.          * Intel 关于SMP的1.4版本
  464.          */
  465.         if (ver >= 0x14)
  466.                 return;
  467.         /*
  468.          * Wait for idle.
  469.          */
  470.         apic_wait_icr_idle();

  471.         apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
  472.         /*
  473.          * 其三,仲裁机制的使用
  474.          */
  475.         apic_write(APIC_ICR, APIC_DEST_ALLINC |
  476.                                 APIC_INT_LEVELTRIG
  477.                                 | APIC_DM_INIT);
  478. }

复制代码

论坛徽章:
0
发表于 2007-12-15 09:09 |显示全部楼层

  1. static int modern_apic(void)
  2. {
  3.         /* AMD systems use old APIC versions, so check the CPU */
  4.         if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
  5.             boot_cpu_data.x86 >= 0xf)
  6.                 return 1;

  7.         /*
  8.          * linux is able to combine specifications by
  9.          * both Intel and AMD
  10.          */
  11.         return lapic_get_version() >= 0x14;
  12. }

  13. int get_physical_broadcast(void)
  14. {
  15.         /*
  16.          * v1.1 specifies 16 LAPIC
  17.          * v1.4 specifies 2566 LAPIC
  18.          */
  19.         return modern_apic() ? 0xff : 0xf;
  20. }

  21. /* ===== end of LAPIC =====
  22.   summary:
  23.   1, two versions 1.1 and 1.4
  24.   2, the key of LAPIC is P from software point
  25.   3, programing lapic timer
  26.   4, programing lapic LINT0/1
  27.   5, programing lapic IRQ DM, delivery model
复制代码

[ 本帖最后由 sisi8408 于 2007-12-15 10:27 编辑 ]

论坛徽章:
0
发表于 2007-12-15 10:26 |显示全部楼层

  1. IOAPIC[IRQ]
  2. ===========

  3. IOAPIC比LAPIC麻烦些,有几种版本,
  4. 1,PIC,2个8259A
  5. 2,MPS,multi pentium standar
  6. 3,MADT,multi APIC description table
  7. 现在流行MADT,由BIOS提供。

  8. part—1,basic def and operation

  9. int nr_ioapic_registers[MAX_IO_APICS];
  10. /*
  11. * Rough estimation of how many shared IRQs there are, can
  12. * be changed anytime.
  13. */
  14. #define MAX_PLUS_SHARED_IRQS        NR_IRQS
  15. #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
  16. /*
  17. * This is performance-critical, we want to do it O(1)
  18. *
  19. * the indexing order of this array favors 1:1 mappings
  20. * between pins and IRQs.
  21. */
  22. static struct irq_pin_list
  23. {
  24.         int apic,
  25.              pin,
  26.              next;
  27. } irq_2_pin[PIN_MAP_SIZE];

  28. struct io_apic
  29. {
  30.         unsigned int index;        /* reg indx */
  31.         unsigned int unused[3];
  32.         unsigned int data;        /* reg value */
  33. };

  34. /*
  35.   in asm/io_apic.h

  36.   the chip is structured by linux as
  37.         IO_APIC_reg_0x + struct IO_APIC_route_entry
  38.   and that is all ;)
  39. */
  40. union entry_union
  41. {
  42.         /*
  43.          * or simply just a 64-bit number :/
  44.          *
  45.          * and currently engineers to play chip
  46.          * are strongly demanded, specially in CNY,
  47.          * not by linux??
  48.          */
  49.         struct { u32 w1, w2; } ;
  50.         struct IO_APIC_route_entry entry;
  51. };

  52. static struct io_apic __iomem * __attribute_const__  io_apic_base (int idx)
  53. {
  54.         return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
  55.                 + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK);
  56.         /*
  57.          * mp_ioapics[],暂且认为是来自MADT
  58.          */
  59. }
  60. static inline unsigned int io_apic_read (unsigned int apic, unsigned int reg)
  61. {
  62.         struct io_apic __iomem *io_apic = io_apic_base(apic);

  63.         writel(reg, &io_apic->index);
  64.         return readl(&io_apic->data);
  65. }
  66. static inline void io_apic_write(unsigned int apic,
  67.                                 unsigned int reg, unsigned int value)
  68. {
  69.         struct io_apic __iomem *io_apic = io_apic_base(apic);
  70.         writel(reg, &io_apic->index);
  71.         writel(value, &io_apic->data);
  72. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP