⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iosapic.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	case PDC_RET_OK:	/* PAT box. Proceed to get the IRT */		/* save the number of entries in the table */		num_entries = pdc_io_num.num;		ASSERT(0UL != num_entries);		/*		** allocate memory for interrupt routing table		** This interface isn't really right. We are assuming		** the contents of the table are exclusively		** for I/O sapic devices.		*/		table = IOSAPIC_KALLOC(struct irt_entry, num_entries);		if (table == NULL) {			printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");			return 0;		}		/* get PCI INT routing table */		status = pdc_pat_get_irt( (void *) table, cell_num);		DBG(KERN_DEBUG "pdc_pat_get_irt: %ld\n", status);		ASSERT(status == PDC_RET_OK);		break;	case PDC_RET_NE_PROC: /* Not a PAT platform. Try PDC_PCI extensions */		/*		** C3000/J5000 (and similar) platforms with "legacy" PDC		** will return exactly one IRT.		** So if we have one, don't need to get it again.		*/		if (NULL != irt_cell)			break;		status = pdc_pci_irt_size( (void *)&pdc_io_num,				/* elroy HPA (really a NOP) */ 0);		DBG(KERN_WARNING "pdc_pci_irt_size: %ld\n", status);		if (PDC_RET_OK != status) {			/* Not a "legacy" system with I/O SAPIC either */			return 0;		}		num_entries = pdc_io_num.num;		ASSERT(0UL != num_entries);		table = IOSAPIC_KALLOC(struct irt_entry, num_entries);		if (table == NULL) {			printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");			return 0;		}		status = pdc_pci_irt( (void *) &pdc_io_num,				(void *) NULL, /* Elroy HPA - not used */				(void *) table);		ASSERT(PDC_RET_OK == status);		break;	default:		printk(KERN_WARNING MODULE_NAME ": PDC_PAT_IO call failed with %ld\n", status);		break;	}	/* return interrupt table address */	*irt = table;#ifdef DEBUG_IOSAPIC_IRT	{	struct irt_entry *p = table;	int i;	printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);	printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",		table,		num_entries,		(int) sizeof(struct irt_entry));	for (i = 0 ; i < num_entries ; i++, p++)	{		printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",		p->entry_type, p->entry_length, p->interrupt_type,		p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id,		p->src_seg_id, p->dest_iosapic_intin,		((u32 *) p)[2],		((u32 *) p)[3]		);	}	}#endif /* DEBUG_IOSAPIC_IRT */	return num_entries;}void __initiosapic_init(void){	/* init global data */	iosapic_lock = SPIN_LOCK_UNLOCKED;        iosapic_list = (struct iosapic_info *) NULL;	iosapic_count = 0;	DBG("iosapic_init()\n");	/*	**  get IRT for this cell.	*/	irt_num_entry =  iosapic_load_irt(0L, &irt_cell);	if (0 == irt_num_entry)		irt_cell = NULL;	/* old PDC w/o iosapic */#ifdef IOSAPIC_CALLBACK	/*	** When new I/O SAPICs are discovered, this callback	** will get invoked. Implies lba driver will register	** I/O Sapic as a device it "discovered" with faked	** IODC data.	*/	register_driver(iosapic_driver_for);#endif /* IOSAPIC_CALLBACK */}/*** Return the IRT entry in case we need to look something else up.*/static struct irt_entry *irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin){	struct irt_entry *i = irt_cell;	int cnt;	/* track how many entries we've looked at */	u8 irq_devno = (slot << IRT_DEV_SHIFT) | (intr_pin-1);	DBG_IRT("irt_find_irqline() SLOT %d pin %d\n", slot, intr_pin);	for (cnt=0; cnt < irt_num_entry; cnt++, i++) {		/*		** Validate: entry_type, entry_length, interrupt_type		**		** Difference between validate vs compare is the former		** should print debug info and is not expected to "fail"		** on current platforms.		*/		if (i->entry_type != IRT_IOSAPIC_TYPE) {			DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d type %d\n", i, cnt, i->entry_type);			continue;		}				if (i->entry_length != IRT_IOSAPIC_LENGTH) {			DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d  length %d\n", i, cnt, i->entry_length);			continue;		}		if (i->interrupt_type != IRT_VECTORED_INTR) {			DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry  %d interrupt_type %d\n", i, cnt, i->interrupt_type);			continue;		}		/*		** Compare: dest_iosapic_addr, src_bus_irq_devno		*/		if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa))			continue;		if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno)			continue;		/*		** Ignore: src_bus_id and rc_seg_id correlate with		**         iosapic_info->isi_hpa on HP platforms.		**         If needed, pass in "PFA" (aka config space addr)		**         instead of slot.		*/		/* Found it! */		return i;	}	printk(KERN_WARNING MODULE_NAME ": 0x%p : no IRT entry for slot %d, pin %d\n",			isi->isi_hpa, slot, intr_pin);	return NULL;}/*** xlate_pin() supports the skewing of IRQ lines done by subsidiary bridges.** Legacy PDC already does this translation for us and stores it in INTR_LINE.**** PAT PDC needs to basically do what legacy PDC does:** o read PIN** o adjust PIN in case device is "behind" a PPB**     (eg 4-port 100BT and SCSI/LAN "Combo Card")** o convert slot/pin to I/O SAPIC input line.**** HP platforms only support:** o one level of skewing for any number of PPBs** o only support PCI-PCI Bridges.*/static struct irt_entry *iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev){	u8 intr_pin, intr_slot;	(void) pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);	DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", PCI_SLOT(pcidev->devfn), intr_pin);	if (0 == intr_pin)	{		/*		** The device does NOT support/use IRQ lines.		*/		return NULL;	}	/* Check if pcidev behind a PPB */	if (NULL != pcidev->bus->self)	{		/* Convert pcidev INTR_PIN into something we		** can lookup in the IRT.		*/#ifdef PCI_BRIDGE_FUNCS		/*		** Proposal #1:		**		** call implementation specific translation function		** This is architecturally "cleaner". HP-UX doesn't		** support other secondary bus types (eg. E/ISA) directly.		** May be needed for other processor (eg IA64) architectures		** or by some ambitous soul who wants to watch TV.		*/		if (pci_bridge_funcs->xlate_intr_line) {			intr_pin = (*pci_bridge_funcs->xlate_intr_line)(pcidev);		}#else	/* PCI_BRIDGE_FUNCS */		struct pci_bus *p = pcidev->bus;		/*		** Proposal #2:		** The "pin" is skewed ((pin + dev - 1) % 4).		**		** This isn't very clean since I/O SAPIC must assume:		**   - all platforms only have PCI busses.		**   - only PCI-PCI bridge (eg not PCI-EISA, PCI-PCMCIA)		**   - IRQ routing is only skewed once regardless of		**     the number of PPB's between iosapic and device.		**     (Bit3 expansion chassis follows this rule)		**		** Advantage is it's really easy to implement.		*/		intr_pin = ((intr_pin-1)+PCI_SLOT(pcidev->devfn)) % 4;		intr_pin++;	/* convert back to INTA-D (1-4) */#endif /* PCI_BRIDGE_FUNCS */		/*		** Locate the host slot the PPB nearest the Host bus		** adapter.		*/		while (NULL != p->parent->self)			p = p->parent;		intr_slot = PCI_SLOT(p->self->devfn);	} else {		intr_slot = PCI_SLOT(pcidev->devfn);	}	DBG_IRT("iosapic_xlate_pin:  bus %d slot %d pin %d\n",				pcidev->bus->secondary, intr_slot, intr_pin);	return irt_find_irqline(isi, intr_slot, intr_pin);}static voidiosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct vector_info *vi = (struct vector_info *)dev_id;	extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);	int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline;	DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", irq, vi->vi_irqline,				vi->vi_eoi_addr);/* FIXME: Need to mask/unmask? processor IRQ is already masked... */	do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs);	/*	** PCI only supports level triggered in order to share IRQ lines.	** I/O SAPIC must always issue EOI.	*/	IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data);}intiosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev){	struct iosapic_info *isi = (struct iosapic_info *)isi_obj;	struct irt_entry *irte = NULL;  /* only used if PAT PDC */	struct vector_info *vi;	int isi_line;	/* line used by device */	int tmp;	if (NULL == isi) {		printk(KERN_WARNING MODULE_NAME ": 0x%p hpa not registered\n", isi->isi_hpa);		return(-1);	}	/* lookup IRT entry for isi/slot/pin set */	irte = iosapic_xlate_pin(isi, pcidev);	if (NULL == irte) {		return(-1);	}	DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n",		irte,		irte->entry_type,		irte->entry_length,		irte->polarity_trigger,		irte->src_bus_irq_devno,		irte->src_bus_id,		irte->src_seg_id,		irte->dest_iosapic_intin,		(u32) irte->dest_iosapic_addr);	isi_line = irte->dest_iosapic_intin;	/* get vector info for this input line */	ASSERT(NULL != isi->isi_vector);	vi = &(isi->isi_vector[isi_line]);	DBG_IRT("iosapic_fixup_irq:  line %d vi 0x%p\n", isi_line, vi);	vi->vi_irte = irte;	/* Allocate processor IRQ */	vi->vi_txn_irq = txn_alloc_irq();/* XXX/FIXME The txn_alloc_irq() code and related code should be moved** to enable_irq(). That way we only allocate processor IRQ bits** for devices that actually have drivers claiming them.** Right now we assign an IRQ to every PCI device present regardless** of whether it's used or not.*/	if (vi->vi_txn_irq < 0)		panic("I/O sapic: couldn't get TXN IRQ\n");	/* enable_irq() will use txn_* to program IRdT */	vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq);	vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8);        ASSERT(vi->vi_txn_data < 256);  /* matches 8 above */	tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi);	ASSERT(tmp == 0);	vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI;	vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline);	ASSERT(NULL != isi->isi_region);	/*	** pcidev->irq still needs to be virtualized.	*/	pcidev->irq = isi->isi_region->data.irqbase + isi_line;	DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", PCI_SLOT(pcidev->devfn),	PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, pcidev->irq);	return(pcidev->irq);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -