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

📄 pci_fixup.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 2 页
字号:
};#define ROUTER_COUNT (sizeof(router_table)/sizeof(router_table[0]))/* Global variables for current interrupt routing table */static struct routing_table *pirq = NULL;static struct pci_dev *router_dev = NULL;static struct router *router_info = NULL;#ifndef __va#define __va(x) (x)#endifstatic void scan_pirq_table(void){    struct routing_table *r;    struct pci_dev *router, *dev;    u8 pin, fn, *p;    int i, j;    struct slot_entry *e;    /* Scan the BIOS for the routing table signature */    for (p = (u8 *)__va(0xf0000); p < (u8 *)__va(0xfffff); p += 16)	if ((p[0] == '$') && (p[1] == 'P') &&	    (p[2] == 'I') && (p[3] == 'R')) break;    if (p >= (u8 *)__va(0xfffff))	return;        pirq = r = (struct routing_table *)p;    printk(KERN_INFO "PCI routing table version %d.%d at %#06x\n",	   r->major, r->minor, (u32)r & 0xfffff);    for (i = j = 0; i < 16; i++)	j += (r->pci_mask >> i) & 1;    if (j > 4)	printk(KERN_NOTICE "  bogus PCI irq mask %#04x!\n",	       r->pci_mask);    else	pci_irq_mask |= r->pci_mask;    router_dev = router = pci_find_slot(r->bus, r->devfn);    if (router) {	for (i = 0; i < ROUTER_COUNT; i++) {	    if ((router->vendor == router_table[i].vendor) &&		(router->device == router_table[i].device))		break;	    if (((r->compat & 0xffff) == router_table[i].vendor) &&		((r->compat >> 16) == router_table[i].device))		break;	}	if (i == ROUTER_COUNT)	    printk(KERN_INFO "  unknown PCI interrupt router %04x:%04x\n",		   router->vendor, router->device);	else	    router_info = &router_table[i];    }    for (e = r->entry; (u8 *)e < p+r->size; e++) {	for (fn = 0; fn < 8; fn++) {	    dev = pci_find_slot(e->bus, e->devfn | fn);	    if ((dev == NULL) || (dev->irq != 0)) continue;	    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);	    if ((pin == 0) || (pin == 255)) continue;	    if (router_info) {		dev->irq = router_info->xlate(router, e->pin[pin-1].link);	    } else {		/* Fallback: see if only one irq possible */		int map = e->pin[pin-1].irq_map;		if (map && (!(map & (map-1))))		    dev->irq = ffs(map)-1;	    }	    if (dev->irq) {		printk(KERN_INFO "  %02x:%02x.%1x -> irq %d\n",		       e->bus, PCI_SLOT(dev->devfn),		       PCI_FUNC(dev->devfn), dev->irq);		pci_write_config_byte(dev, PCI_INTERRUPT_LINE,				      dev->irq);	    }	}    }}#endif /* (LINUX_VERSION_CODE < VERSION(2,3,24)) && defined(__i386__) *//*======================================================================    PCI device enabler    This is not at all generic... it is mostly a hack to correctly    configure CardBus bridges.    ======================================================================*/#if (LINUX_VERSION_CODE < VERSION(2,3,24))static int check_cb_mapping(u_int phys){    /* A few sanity checks to validate the bridge mapping */    char *virt = ioremap(phys, 0x1000);    int ret = ((readb(virt+0x800+I365_IDENT) & 0x70) ||	       (readb(virt+0x800+I365_CSC) &&		readb(virt+0x800+I365_CSC) &&		readb(virt+0x800+I365_CSC)));    int state = readl(virt+CB_SOCKET_STATE) >> 16;    ret |= (state & ~0x3000) || !(state & 0x3000);    ret |= readl(virt+CB_SOCKET_FORCE);    iounmap(virt);    return ret;}static void setup_cb_bridge(struct pci_dev *dev){    u8 bus, sub;    u32 phys;    int i;    /* This is nasty, but where else can we put it? */    if (PCI_FUNC(dev->devfn) == 0) {	struct pci_dev *sib;	sib = pci_find_slot(dev->bus->number, dev->devfn+1);	if (sib) {	    u8 a, b;	    u32 c, d;	    /* Check for bad PCI bus numbering */	    pci_read_config_byte(dev, CB_CARDBUS_BUS, &a);	    pci_read_config_byte(sib, CB_CARDBUS_BUS, &b);	    if (a == b) {		pci_write_config_byte(dev, CB_CARDBUS_BUS, 0);		pci_write_config_byte(sib, CB_CARDBUS_BUS, 0);	    }	    /* check for bad register mapping */	    pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &c);	    pci_read_config_dword(sib, PCI_BASE_ADDRESS_0, &d);	    if ((c != 0) && (c == d)) {		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);		pci_write_config_dword(sib, PCI_BASE_ADDRESS_0, 0);	    }	}    }    /* Assign PCI bus numbers, if needed */    pci_read_config_byte(dev, CB_CARDBUS_BUS, &bus);    pci_read_config_byte(dev, CB_SUBORD_BUS, &sub);    if ((cb_bus_base > 0) || (bus == 0)) {	if (cb_bus_base <= 0) cb_bus_base = 0x20;	bus = cb_bus_base;	sub = cb_bus_base+cb_bus_step;	cb_bus_base += cb_bus_step+1;	pci_write_config_byte(dev, CB_CARDBUS_BUS, bus);	pci_write_config_byte(dev, CB_SUBORD_BUS, sub);    }    /* Create pci_bus structure for the CardBus, if needed */    {	struct pci_bus *child, *parent = dev->bus;	for (child = parent->children; child; child = child->next)	    if (child->number == bus) break;	if (!child) {	    child = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);	    memset(child, 0, sizeof(struct pci_bus));	    child->self = dev;	    child->primary = bus;	    child->number = child->secondary = bus;	    child->subordinate = sub;	    child->parent = parent;#if (LINUX_VERSION_CODE >= VERSION(2,3,15))	    child->ops = parent->ops;#endif	    child->next = parent->children;	    parent->children = child;	}    }    /* Map the CardBus bridge registers, if needed */    pci_write_config_dword(dev, CB_LEGACY_MODE_BASE, 0);    pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &phys);    if ((phys == 0) || (cb_mem_base[0] != 0)) {	/* Make sure the bridge is awake so we can test it */	pci_set_power_state(dev, 0);	for (i = 0; i < sizeof(cb_mem_base)/sizeof(u_int); i++) {	    phys = cb_mem_base[i];	    if (phys == 0) continue;	    pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, phys);	    if ((i == 0) || (check_cb_mapping(phys) == 0)) break;	}	if (i == sizeof(cb_mem_base)/sizeof(u_int)) {	    pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);	} else {	    cb_mem_base[0] = cb_mem_base[i] + 0x1000;	}    }}#define CMD_DFLT (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | \		  PCI_COMMAND_MASTER | PCI_COMMAND_WAIT)#ifdef __i386__static u8 pirq_init(struct pci_dev *router, struct pirq_pin *pin){    u16 map = pin->irq_map;    u8 irq = 0;    if (pirq->pci_mask)	map &= pirq->pci_mask;    if (cb_pci_irq)	map = 1<<cb_pci_irq;    /* Be conservative: only init irq if the mask is unambiguous */    if (map && (!(map & (map-1)))) {	irq = ffs(map)-1;	router_info->init(router, pin->link, irq);	pci_irq_mask |= (1<<irq);    }    return irq;}static void setup_cb_bridge_irq(struct pci_dev *dev){    struct slot_entry *e;    u8 pin;    u32 phys;    char *virt;    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);    pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &phys);    if (!pin || !phys)	return;    virt = ioremap(phys, 0x1000);    if (virt) {	/* Disable any pending interrupt sources */	writel(0, virt+CB_SOCKET_MASK);	writel(-1, virt+CB_SOCKET_EVENT);	iounmap(virt);    }    for (e = pirq->entry; (u8 *)e < (u8 *)pirq + pirq->size; e++) {	if ((e->bus != dev->bus->number) ||	    (e->devfn != (dev->devfn & ~7)))	    continue;	dev->irq = pirq_init(router_dev, &e->pin[pin-1]);	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);	break;    }}#endifint pci_enable_device(struct pci_dev *dev){    pci_write_config_word(dev, PCI_COMMAND, CMD_DFLT);    if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {	setup_cb_bridge(dev);    }#ifdef __i386__    /* In certain cases, if the interrupt can be deduced, but was       unrouted when the pirq table was scanned, we'll try to set it       up now. */    if (!dev->irq && pirq && (router_info) &&	((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS)) {	setup_cb_bridge_irq(dev);    }#endif    return 0;}int pci_set_power_state(struct pci_dev *dev, int state){    u16 tmp, cmd;    u32 base, bus;    u8 a, b, pmcs;    pci_read_config_byte(dev, PCI_STATUS, &a);    if (a & PCI_STATUS_CAPLIST) {	pci_read_config_byte(dev, PCI_CB_CAPABILITY_POINTER, &b);	while (b != 0) {	    pci_read_config_byte(dev, b+PCI_CAPABILITY_ID, &a);	    if (a == PCI_CAPABILITY_PM) {		pmcs = b + PCI_PM_CONTROL_STATUS;		/* Make sure we're in D0 state */		pci_read_config_word(dev, pmcs, &tmp);		if (!(tmp & PCI_PMCS_PWR_STATE_MASK)) break;		pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &base);		pci_read_config_dword(dev, CB_PRIMARY_BUS, &bus);		pci_read_config_word(dev, PCI_COMMAND, &cmd);		pci_write_config_word(dev, pmcs, PCI_PMCS_PWR_STATE_D0);		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, base);		pci_write_config_dword(dev, CB_PRIMARY_BUS, bus);		pci_write_config_word(dev, PCI_COMMAND, cmd);		break;	    }	    pci_read_config_byte(dev, b+PCI_NEXT_CAPABILITY, &b);	}    }    return 0;}#endif /* (LINUX_VERSION_CODE < VERSION(2,3,24)) *//*======================================================================    General setup and cleanup entry points======================================================================*/void pci_fixup_init(void){    struct pci_dev *p;#if (LINUX_VERSION_CODE < VERSION(2,3,24)) && defined(__i386__)    scan_pirq_table();    pci_for_each_dev(p)	if (((p->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) &&	    (p->irq == 0)) break;    if (p && !pirq)	printk(KERN_INFO "No PCI interrupt routing table!\n");    if (!pirq && cb_pci_irq)	printk(KERN_INFO "cb_pci_irq will be ignored.\n");#endif    pci_for_each_dev(p)	pci_irq_mask |= (1<<p->irq);#ifdef __alpha__#define PIC 0x4d0    pci_irq_mask |= inb(PIC) | (inb(PIC+1) << 8);#endif}void pci_fixup_done(void){#if (LINUX_VERSION_CODE < VERSION(2,1,0))    struct pci_dev *d, *dn;    struct pci_bus *b, *bn;    for (d = pci_devices; d; d = dn) {	dn = d->next;	kfree(d);    }    for (b = pci_root.next; b; b = bn) {	bn = b->next;	kfree(b);    }#endif}

⌨️ 快捷键说明

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