📄 iosapic.c
字号:
static voidiosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1){ struct iosapic_info *isp = vi->vi_ios; u8 idx = vi->vi_irqline; /* point the window register to the lower word */ WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); *dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); /* point the window register to the higher word */ WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); *dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);}static voidiosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1){ struct iosapic_info *isp = vi->vi_ios; ASSERT(NULL != isp); ASSERT(NULL != isp->isi_hpa); DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n", vi->vi_irqline, isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW, dp0, dp1); /* point the window register to the lower word */ WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW); /* Read the window register to flush the writes down to HW */ dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); /* point the window register to the higher word */ WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW); /* Read the window register to flush the writes down to HW */ dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);}/*** set_irt prepares the data (dp0, dp1) according to the vector_info** and target cpu (id_eid). dp0/dp1 are then used to program I/O SAPIC** IRdT for the given "vector" (aka IRQ line).*/static voidiosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1){ u32 mode = 0; struct irt_entry *p = vi->vi_irte; ASSERT(NULL != vi->vi_irte); if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO) mode |= IOSAPIC_IRDT_PO_LOW; if (((p->polarity_trigger >> IRT_EL_SHIFT) & IRT_EL_MASK) == IRT_LEVEL_TRIG) mode |= IOSAPIC_IRDT_LEVEL_TRIG; /* ** IA64 REVISIT ** PA doesn't support EXTINT or LPRIO bits. */ ASSERT(vi->vi_txn_data); *dp0 = mode | (u32) vi->vi_txn_data; /* ** Extracting id_eid isn't a real clean way of getting it. ** But the encoding is the same for both PA and IA64 platforms. */#ifdef __LP64__ if (pdc_pat) { /* ** PAT PDC just hands it to us "right". ** vi_txn_addr comes from cpu_data[x].txn_addr. */ *dp1 = (u32) (vi->vi_txn_addr); } else#endif { /* ** eg if base_addr == 0xfffa0000), ** we want to get 0xa0ff0000. ** ** eid 0x0ff00000 -> 0x00ff0000 ** id 0x000ff000 -> 0xff000000 */ *dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) | (((u32)vi->vi_txn_addr & 0x000ff000) << 12); } DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1);}static voidiosapic_disable_irq(void *irq_dev, int irq){ ulong irqflags; struct vector_info *vi = &(((struct vector_info *) irq_dev)[irq]); u32 d0, d1; ASSERT(NULL != vi); IOSAPIC_LOCK(&iosapic_lock);#ifdef REVISIT_DESIGN_ISSUE/* ** XXX/FIXMEdisable_irq()/enable_irq(): drawback of using IRQ as a "handle"Current disable_irq interface only allows the irq_region support routinesto manage sharing of "irq" objects. The problem is the disable_irq()interface specifies which IRQ line needs to be disabled but does notidentify the particular ISR which needs to be disabled. IO sapic(and similar code in Dino) can only support one handler per IRQsince they don't further encode the meaning of the IRQ number.irq_region support has to hide it's implementation of "shared IRQ"behind a function call.Encoding the IRQ would be possible by I/O SAPIC but makes life reallycomplicated for the IRQ handler and not help performance.Need more info on how Linux supports shared IRQ lines on a PC.*/#endif /* REVISIT_DESIGN_ISSUE */ iosapic_rd_irt_entry(vi, &d0, &d1); d0 |= IOSAPIC_IRDT_ENABLE; iosapic_wr_irt_entry(vi, d0, d1); IOSAPIC_UNLOCK(&iosapic_lock); /* disable ISR for parent */ disable_irq(vi->vi_txn_irq);}static voidiosapic_enable_irq(void *dev, int irq){ struct vector_info *vi = &(((struct vector_info *) dev)[irq]); u32 d0, d1; ASSERT(NULL != vi); ASSERT(NULL != vi->vi_irte); /* data is initialized by fixup_irq */ ASSERT(0 < vi->vi_txn_irq); ASSERT(0UL != vi->vi_txn_addr); ASSERT(0UL != vi->vi_txn_data); iosapic_set_irt_data(vi, &d0, &d1); iosapic_wr_irt_entry(vi, d0, d1);#ifdef DEBUG_IOSAPIC_IRT{u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));printk("\n");}printk("iosapic_enable_irq(): sel ");{ struct iosapic_info *isp = vi->vi_ios; for (d0=0x10; d0<0x1e; d0++) { /* point the window register to the lower word */ WRITE_U32(d0, isp->isi_hpa+IOSAPIC_REG_SELECT); /* read the word */ d1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); printk(" %x", d1); }}printk("\n");#endif /* ** KLUGE: IRQ should not be asserted when Drivers enabling their IRQ. ** PCI supports level triggered in order to share IRQ lines. ** ** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is ** asserted. */ IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data);}static voidiosapic_mask_irq(void *dev, int irq){ BUG();}static voidiosapic_unmask_irq(void *dev, int irq){ BUG();}static struct irq_region_ops iosapic_irq_ops = { iosapic_disable_irq, iosapic_enable_irq, iosapic_mask_irq, iosapic_unmask_irq};/*** squirrel away the I/O Sapic Version*/static unsigned intiosapic_rd_version(struct iosapic_info *isi){ ASSERT(isi); ASSERT(isi->isi_hpa); /* point window to the version register */ WRITE_U32(IOSAPIC_REG_VERSION, isi->isi_hpa+IOSAPIC_REG_SELECT); /* now read the version register */ return (READ_U32(isi->isi_hpa+IOSAPIC_REG_WINDOW));}#ifndef IOSAPIC_CALLBACK/*** iosapic_register() is the alternative to iosapic_driver_for().** (Only one or the other should be implemented.)*//*** iosapic_register() is called by "drivers" with an integrated I/O SAPIC.** Caller must be certain they have an I/O SAPIC and know it's MMIO address.**** o allocate iosapic_info and add it to the list** o read iosapic version and squirrel that away** o read size of IRdT.** o allocate and initialize isi_vector[]** o allocate isi_region (registers region handlers)*/void *iosapic_register(void *hpa){ struct iosapic_info *isi = NULL; struct irt_entry *irte = irt_cell; struct vector_info *vip; int cnt; /* track how many entries we've looked at */ /* ** Astro based platforms can't support PCI OLARD if they ** implement the legacy PDC (not PAT). Though Legacy PDC ** supports an IRT, LBA's with no device under them ** are *not* listed in the IRT. ** Search the IRT and ignore iosapic's which aren't ** in the IRT. */ ASSERT(NULL != irte); /* always have built-in devices */ for (cnt=0; cnt < irt_num_entry; cnt++, irte++) { ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type); /* ** We need sign extension of the hpa on 32-bit kernels. ** The address in the IRT is *always* 64 bit and really ** is an unsigned quantity (like all physical addresses). */ if (irte->dest_iosapic_addr == (s64) ((long) hpa)) break; } if (cnt >= irt_num_entry) return (NULL); if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) { BUG(); return (NULL); } memset(isi, 0, sizeof(struct iosapic_info)); isi->isi_hpa = (unsigned char *) hpa; isi->isi_version = iosapic_rd_version(isi); isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1; vip = isi->isi_vector = IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors); if (vip == NULL) { IOSAPIC_FREE(isi, struct iosapic_info, 1); return (NULL); } memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors); /* ** Initialize vector array */ for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { vip->vi_irqline = (unsigned char) cnt; vip->vi_ios = isi; } isi->isi_region = alloc_irq_region(isi->isi_num_vectors, &iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK, "I/O Sapic", (void *) isi->isi_vector); ASSERT(NULL != isi->isi_region); return ((void *) isi);}#endif /* !IOSAPIC_CALLBACK */#ifdef DEBUG_IOSAPICstatic voidiosapic_prt_irt(void *irt, long num_entry){ unsigned int i, *irp = (unsigned int *) irt; ASSERT(NULL != irt); printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry); for (i=0; i<num_entry; i++, irp += 4) { printk(KERN_DEBUG "%p : %2d %.8x %.8x %.8x %.8x\n", irp, i, irp[0], irp[1], irp[2], irp[3]); }}static voidiosapic_prt_vi(struct vector_info *vi){ ASSERT(NULL != vi); printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->vi_irqline, vi); printk(KERN_DEBUG "\t\tvi_status: %.4x\n", vi->vi_status); printk(KERN_DEBUG "\t\tvi_txn_irq: %d\n", vi->vi_txn_irq); printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr); printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data); printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n", vi->vi_eoi_addr); printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n", vi->vi_eoi_data);}static voidiosapic_prt_isi(struct iosapic_info *isi){ ASSERT(NULL != isi); printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi); printk(KERN_DEBUG "\t\tisi_hpa: %p\n", isi->isi_hpa); printk(KERN_DEBUG "\t\tisi_satus: %x\n", isi->isi_status); printk(KERN_DEBUG "\t\tisi_version: %x\n", isi->isi_version); printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector);}#endif /* DEBUG_IOSAPIC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -