diff --git a/[refs] b/[refs] index b378b91c5e45..31eac5cffcbf 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: d06e7a56d91328267a96b1a4df4ede7529f829e8 +refs/heads/master: 55820ee2f8c767a2833b21bd365e5753f50bd8ce diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/trunk/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c index e86ea486c311..1a49adb1f4a6 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c +++ b/trunk/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c @@ -190,7 +190,7 @@ static __init struct pci_dev *gx_detect_chipset(void) /* detect which companion chip is used */ while ((gx_pci = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) { - if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL) { + if ((pci_match_device (gx_chipset_tbl, gx_pci)) != NULL) { return gx_pci; } } diff --git a/trunk/arch/i386/pci/common.c b/trunk/arch/i386/pci/common.c index 70bcd53451f6..87325263cd4f 100644 --- a/trunk/arch/i386/pci/common.c +++ b/trunk/arch/i386/pci/common.c @@ -165,7 +165,6 @@ static int __init pcibios_init(void) if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) pcibios_sort(); #endif - pci_assign_unassigned_resources(); return 0; } diff --git a/trunk/arch/i386/pci/i386.c b/trunk/arch/i386/pci/i386.c index 93a364c82150..c205ea7e233b 100644 --- a/trunk/arch/i386/pci/i386.c +++ b/trunk/arch/i386/pci/i386.c @@ -106,16 +106,11 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) if ((dev = bus->self)) { for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { r = &dev->resource[idx]; - if (!r->flags) + if (!r->start) continue; pr = pci_find_parent_resource(dev, r); - if (!r->start || !pr || request_resource(pr, r) < 0) { + if (!pr || request_resource(pr, r) < 0) printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev)); - /* Something is wrong with the region. - Invalidate the resource to prevent child - resource allocations in this range. */ - r->flags = 0; - } } } pcibios_allocate_bus_resources(&bus->children); @@ -232,7 +227,7 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask) pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for(idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + for(idx=0; idx<6; idx++) { /* Only set up the requested stuff */ if (!(mask & (1<irq_chain = g5 */ stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ @@ -565,9 +567,9 @@ do_ivec: retry do_ivec_xcall: mov 0x50, %g1 + ldxa [%g1 + %g0] ASI_INTR_R, %g1 srl %g3, 0, %g3 - mov 0x60, %g7 ldxa [%g7 + %g0] ASI_INTR_R, %g7 stxa %g0, [%g0] ASI_INTR_RECEIVE @@ -579,6 +581,19 @@ do_ivec_xcall: 1: jmpl %g3, %g0 nop +do_ivec_spurious: + stw %g3, [%g6 + 0x00] /* irq_work(cpu, 0) = bucket */ + rdpr %pstate, %g5 + + wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + call catch_disabled_ivec + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + clr %l6 + .globl save_alternate_globals save_alternate_globals: /* %o0 = save_area */ rdpr %pstate, %o5 diff --git a/trunk/arch/sparc64/kernel/irq.c b/trunk/arch/sparc64/kernel/irq.c index 74a2e0808cbc..424712577307 100644 --- a/trunk/arch/sparc64/kernel/irq.c +++ b/trunk/arch/sparc64/kernel/irq.c @@ -71,7 +71,31 @@ struct irq_work_struct { struct irq_work_struct __irq_work[NR_CPUS]; #define irq_work(__cpu, __pil) &(__irq_work[(__cpu)].irq_worklists[(__pil)]) -static struct irqaction *irq_action[NR_IRQS+1]; +#ifdef CONFIG_PCI +/* This is a table of physical addresses used to deal with IBF_DMA_SYNC. + * It is used for PCI only to synchronize DMA transfers with IRQ delivery + * for devices behind busses other than APB on Sabre systems. + * + * Currently these physical addresses are just config space accesses + * to the command register for that device. + */ +unsigned long pci_dma_wsync; +unsigned long dma_sync_reg_table[256]; +unsigned char dma_sync_reg_table_entry = 0; +#endif + +/* This is based upon code in the 32-bit Sparc kernel written mostly by + * David Redman (djhr@tadpole.co.uk). + */ +#define MAX_STATIC_ALLOC 4 +static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; +static int static_irq_count; + +/* This is exported so that fast IRQ handlers can get at it... -DaveM */ +struct irqaction *irq_action[NR_IRQS+1] = { + NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL +}; /* This only synchronizes entities which modify IRQ handler * state and some selected user-level spots that want to @@ -217,22 +241,17 @@ void disable_irq(unsigned int irq) * the CPU %tick register and not by some normal vectored interrupt * source. To handle this special case, we use this dummy INO bucket. */ -static struct irq_desc pil0_dummy_desc; static struct ino_bucket pil0_dummy_bucket = { - .irq_info = &pil0_dummy_desc, + 0, /* irq_chain */ + 0, /* pil */ + 0, /* pending */ + 0, /* flags */ + 0, /* __unused */ + NULL, /* irq_info */ + 0UL, /* iclr */ + 0UL, /* imap */ }; -static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup, - unsigned long iclr, unsigned long imap, - struct ino_bucket *bucket) -{ - prom_printf("IRQ: INO %04x (%d:%016lx:%016lx) --> " - "(%d:%d:%016lx:%016lx), halting...\n", - ino, bucket->pil, bucket->iclr, bucket->imap, - pil, inofixup, iclr, imap); - prom_halt(); -} - unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap) { struct ino_bucket *bucket; @@ -261,35 +280,28 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long prom_halt(); } - bucket = &ivector_table[ino]; - if (bucket->flags & IBF_ACTIVE) - build_irq_error("IRQ: Trying to build active INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); - - if (bucket->irq_info) { - if (bucket->imap != imap || bucket->iclr != iclr) - build_irq_error("IRQ: Trying to reinit INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); - - goto out; - } - - bucket->irq_info = kmalloc(sizeof(struct irq_desc), GFP_ATOMIC); - if (!bucket->irq_info) { - prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); - prom_halt(); - } - memset(bucket->irq_info, 0, sizeof(struct irq_desc)); - /* Ok, looks good, set it up. Don't touch the irq_chain or * the pending flag. */ + bucket = &ivector_table[ino]; + if ((bucket->flags & IBF_ACTIVE) || + (bucket->irq_info != NULL)) { + /* This is a gross fatal error if it happens here. */ + prom_printf("IRQ: Trying to reinit INO bucket, fatal error.\n"); + prom_printf("IRQ: Request INO %04x (%d:%d:%016lx:%016lx)\n", + ino, pil, inofixup, iclr, imap); + prom_printf("IRQ: Existing (%d:%016lx:%016lx)\n", + bucket->pil, bucket->iclr, bucket->imap); + prom_printf("IRQ: Cannot continue, halting...\n"); + prom_halt(); + } bucket->imap = imap; bucket->iclr = iclr; bucket->pil = pil; bucket->flags = 0; -out: + bucket->irq_info = NULL; + return __irq(bucket); } @@ -307,65 +319,26 @@ static void atomic_bucket_insert(struct ino_bucket *bucket) __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); } -static int check_irq_sharing(int pil, unsigned long irqflags) -{ - struct irqaction *action, *tmp; - - action = *(irq_action + pil); - if (action) { - if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { - for (tmp = action; tmp->next; tmp = tmp->next) - ; - } else { - return -EBUSY; - } - } - return 0; -} - -static void append_irq_action(int pil, struct irqaction *action) -{ - struct irqaction **pp = irq_action + pil; - - while (*pp) - pp = &((*pp)->next); - *pp = action; -} - -static struct irqaction *get_action_slot(struct ino_bucket *bucket) -{ - struct irq_desc *desc = bucket->irq_info; - int max_irq, i; - - max_irq = 1; - if (bucket->flags & IBF_PCI) - max_irq = MAX_IRQ_DESC_ACTION; - for (i = 0; i < max_irq; i++) { - struct irqaction *p = &desc->action[i]; - u32 mask = (1 << i); - - if (desc->action_active_mask & mask) - continue; - - desc->action_active_mask |= mask; - return p; - } - return NULL; -} - int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *name, void *dev_id) { - struct irqaction *action; + struct irqaction *action, *tmp = NULL; struct ino_bucket *bucket = __bucket(irq); unsigned long flags; int pending = 0; - if (unlikely(!handler)) - return -EINVAL; + if ((bucket != &pil0_dummy_bucket) && + (bucket < &ivector_table[0] || + bucket >= &ivector_table[NUM_IVECS])) { + unsigned int *caller; - if (unlikely(!bucket->irq_info)) - return -ENODEV; + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + printk(KERN_CRIT "request_irq: Old style IRQ registry attempt " + "from %p, irq %08x.\n", caller, irq); + return -EINVAL; + } + if (!handler) + return -EINVAL; if ((bucket != &pil0_dummy_bucket) && (irqflags & SA_SAMPLE_RANDOM)) { /* @@ -383,20 +356,93 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ spin_lock_irqsave(&irq_action_lock, flags); - if (check_irq_sharing(bucket->pil, irqflags)) { - spin_unlock_irqrestore(&irq_action_lock, flags); - return -EBUSY; + action = *(bucket->pil + irq_action); + if (action) { + if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) + for (tmp = action; tmp->next; tmp = tmp->next) + ; + else { + spin_unlock_irqrestore(&irq_action_lock, flags); + return -EBUSY; + } + action = NULL; /* Or else! */ } - action = get_action_slot(bucket); + /* If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + if (irqflags & SA_STATIC_ALLOC) { + if (static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " + "using kmalloc\n", irq, name); + } + if (action == NULL) + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), + GFP_ATOMIC); + if (!action) { spin_unlock_irqrestore(&irq_action_lock, flags); return -ENOMEM; } - bucket->flags |= IBF_ACTIVE; - pending = 0; - if (bucket != &pil0_dummy_bucket) { + if (bucket == &pil0_dummy_bucket) { + bucket->irq_info = action; + bucket->flags |= IBF_ACTIVE; + } else { + if ((bucket->flags & IBF_ACTIVE) != 0) { + void *orig = bucket->irq_info; + void **vector = NULL; + + if ((bucket->flags & IBF_PCI) == 0) { + printk("IRQ: Trying to share non-PCI bucket.\n"); + goto free_and_ebusy; + } + if ((bucket->flags & IBF_MULTI) == 0) { + vector = kmalloc(sizeof(void *) * 4, GFP_ATOMIC); + if (vector == NULL) + goto free_and_enomem; + + /* We might have slept. */ + if ((bucket->flags & IBF_MULTI) != 0) { + int ent; + + kfree(vector); + vector = (void **)bucket->irq_info; + for(ent = 0; ent < 4; ent++) { + if (vector[ent] == NULL) { + vector[ent] = action; + break; + } + } + if (ent == 4) + goto free_and_ebusy; + } else { + vector[0] = orig; + vector[1] = action; + vector[2] = NULL; + vector[3] = NULL; + bucket->irq_info = vector; + bucket->flags |= IBF_MULTI; + } + } else { + int ent; + + vector = (void **)orig; + for (ent = 0; ent < 4; ent++) { + if (vector[ent] == NULL) { + vector[ent] = action; + break; + } + } + if (ent == 4) + goto free_and_ebusy; + } + } else { + bucket->irq_info = action; + bucket->flags |= IBF_ACTIVE; + } pending = bucket->pending; if (pending) bucket->pending = 0; @@ -410,7 +456,10 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ put_ino_in_irqaction(action, irq); put_smpaff_in_irqaction(action, CPU_MASK_NONE); - append_irq_action(bucket->pil, action); + if (tmp) + tmp->next = action; + else + *(bucket->pil + irq_action) = action; enable_irq(irq); @@ -419,103 +468,147 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ atomic_bucket_insert(bucket); set_softint(1 << bucket->pil); } - spin_unlock_irqrestore(&irq_action_lock, flags); - - if (bucket != &pil0_dummy_bucket) + if ((bucket != &pil0_dummy_bucket) && (!(irqflags & SA_STATIC_ALLOC))) register_irq_proc(__irq_ino(irq)); #ifdef CONFIG_SMP distribute_irqs(); #endif return 0; + +free_and_ebusy: + kfree(action); + spin_unlock_irqrestore(&irq_action_lock, flags); + return -EBUSY; + +free_and_enomem: + kfree(action); + spin_unlock_irqrestore(&irq_action_lock, flags); + return -ENOMEM; } EXPORT_SYMBOL(request_irq); -static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id) +void free_irq(unsigned int irq, void *dev_id) { - struct ino_bucket *bucket = __bucket(irq); - struct irqaction *action, **pp; + struct irqaction *action; + struct irqaction *tmp = NULL; + unsigned long flags; + struct ino_bucket *bucket = __bucket(irq), *bp; - pp = irq_action + bucket->pil; - action = *pp; - if (unlikely(!action)) - return NULL; + if ((bucket != &pil0_dummy_bucket) && + (bucket < &ivector_table[0] || + bucket >= &ivector_table[NUM_IVECS])) { + unsigned int *caller; - if (unlikely(!action->handler)) { - printk("Freeing free IRQ %d\n", bucket->pil); - return NULL; + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + printk(KERN_CRIT "free_irq: Old style IRQ removal attempt " + "from %p, irq %08x.\n", caller, irq); + return; } + + spin_lock_irqsave(&irq_action_lock, flags); - while (action && action->dev_id != dev_id) { - pp = &action->next; - action = *pp; + action = *(bucket->pil + irq_action); + if (!action->handler) { + printk("Freeing free IRQ %d\n", bucket->pil); + return; + } + if (dev_id) { + for ( ; action; action = action->next) { + if (action->dev_id == dev_id) + break; + tmp = action; + } + if (!action) { + printk("Trying to free free shared IRQ %d\n", bucket->pil); + spin_unlock_irqrestore(&irq_action_lock, flags); + return; + } + } else if (action->flags & SA_SHIRQ) { + printk("Trying to free shared IRQ %d with NULL device ID\n", bucket->pil); + spin_unlock_irqrestore(&irq_action_lock, flags); + return; } - if (likely(action)) - *pp = action->next; - - return action; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - struct irqaction *action; - struct ino_bucket *bucket; - unsigned long flags; - - spin_lock_irqsave(&irq_action_lock, flags); + if (action->flags & SA_STATIC_ALLOC) { + printk("Attempt to free statically allocated IRQ %d (%s)\n", + bucket->pil, action->name); + spin_unlock_irqrestore(&irq_action_lock, flags); + return; + } - action = unlink_irq_action(irq, dev_id); + if (action && tmp) + tmp->next = action->next; + else + *(bucket->pil + irq_action) = action->next; spin_unlock_irqrestore(&irq_action_lock, flags); - if (unlikely(!action)) - return; - synchronize_irq(irq); spin_lock_irqsave(&irq_action_lock, flags); - bucket = __bucket(irq); if (bucket != &pil0_dummy_bucket) { - struct irq_desc *desc = bucket->irq_info; unsigned long imap = bucket->imap; - int ent, i; - - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; - - if (p == action) { - desc->action_active_mask &= ~(1 << i); - break; + void **vector, *orig; + int ent; + + orig = bucket->irq_info; + vector = (void **)orig; + + if ((bucket->flags & IBF_MULTI) != 0) { + int other = 0; + void *orphan = NULL; + for (ent = 0; ent < 4; ent++) { + if (vector[ent] == action) + vector[ent] = NULL; + else if (vector[ent] != NULL) { + orphan = vector[ent]; + other++; + } } - } - if (!desc->action_active_mask) { - /* This unique interrupt source is now inactive. */ - bucket->flags &= ~IBF_ACTIVE; - - /* See if any other buckets share this bucket's IMAP - * and are still active. + /* Only free when no other shared irq + * uses this bucket. */ - for (ent = 0; ent < NUM_IVECS; ent++) { - struct ino_bucket *bp = &ivector_table[ent]; - if (bp != bucket && - bp->imap == imap && - (bp->flags & IBF_ACTIVE) != 0) - break; + if (other) { + if (other == 1) { + /* Convert back to non-shared bucket. */ + bucket->irq_info = orphan; + bucket->flags &= ~(IBF_MULTI); + kfree(vector); + } + goto out; } + } else { + bucket->irq_info = NULL; + } - /* Only disable when no other sub-irq levels of - * the same IMAP are active. - */ - if (ent == NUM_IVECS) - disable_irq(irq); + /* This unique interrupt source is now inactive. */ + bucket->flags &= ~IBF_ACTIVE; + + /* See if any other buckets share this bucket's IMAP + * and are still active. + */ + for (ent = 0; ent < NUM_IVECS; ent++) { + bp = &ivector_table[ent]; + if (bp != bucket && + bp->imap == imap && + (bp->flags & IBF_ACTIVE) != 0) + break; } + + /* Only disable when no other sub-irq levels of + * the same IMAP are active. + */ + if (ent == NUM_IVECS) + disable_irq(irq); } +out: + kfree(action); spin_unlock_irqrestore(&irq_action_lock, flags); } @@ -554,55 +647,99 @@ void synchronize_irq(unsigned int irq) } #endif /* CONFIG_SMP */ -static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs) +void catch_disabled_ivec(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + struct ino_bucket *bucket = __bucket(*irq_work(cpu, 0)); + + /* We can actually see this on Ultra/PCI PCI cards, which are bridges + * to other devices. Here a single IMAP enabled potentially multiple + * unique interrupt sources (which each do have a unique ICLR register. + * + * So what we do is just register that the IVEC arrived, when registered + * for real the request_irq() code will check the bit and signal + * a local CPU interrupt for it. + */ +#if 0 + printk("IVEC: Spurious interrupt vector (%x) received at (%016lx)\n", + bucket - &ivector_table[0], regs->tpc); +#endif + *irq_work(cpu, 0) = 0; + bucket->pending = 1; +} + +/* Tune this... */ +#define FORWARD_VOLUME 12 + +#ifdef CONFIG_SMP + +static inline void redirect_intr(int cpu, struct ino_bucket *bp) { - struct irq_desc *desc = bp->irq_info; - unsigned char flags = bp->flags; - u32 action_mask, i; - int random; + /* Ok, here is what is going on: + * 1) Retargeting IRQs on Starfire is very + * expensive so just forget about it on them. + * 2) Moving around very high priority interrupts + * is a losing game. + * 3) If the current cpu is idle, interrupts are + * useful work, so keep them here. But do not + * pass to our neighbour if he is not very idle. + * 4) If sysadmin explicitly asks for directed intrs, + * Just Do It. + */ + struct irqaction *ap = bp->irq_info; + cpumask_t cpu_mask; + unsigned int buddy, ticks; - bp->flags |= IBF_INPROGRESS; + cpu_mask = get_smpaff_in_irqaction(ap); + cpus_and(cpu_mask, cpu_mask, cpu_online_map); + if (cpus_empty(cpu_mask)) + cpu_mask = cpu_online_map; - if (unlikely(!(flags & IBF_ACTIVE))) { - bp->pending = 1; + if (this_is_starfire != 0 || + bp->pil >= 10 || current->pid == 0) goto out; - } - if (desc->pre_handler) - desc->pre_handler(bp, - desc->pre_handler_arg1, - desc->pre_handler_arg2); + /* 'cpu' is the MID (ie. UPAID), calculate the MID + * of our buddy. + */ + buddy = cpu + 1; + if (buddy >= NR_CPUS) + buddy = 0; + + ticks = 0; + while (!cpu_isset(buddy, cpu_mask)) { + if (++buddy >= NR_CPUS) + buddy = 0; + if (++ticks > NR_CPUS) { + put_smpaff_in_irqaction(ap, CPU_MASK_NONE); + goto out; + } + } - action_mask = desc->action_active_mask; - random = 0; - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; - u32 mask = (1 << i); + if (buddy == cpu) + goto out; - if (!(action_mask & mask)) - continue; + /* Voo-doo programming. */ + if (cpu_data(buddy).idle_volume < FORWARD_VOLUME) + goto out; - action_mask &= ~mask; + /* This just so happens to be correct on Cheetah + * at the moment. + */ + buddy <<= 26; - if (p->handler(__irq(bp), p->dev_id, regs) == IRQ_HANDLED) - random |= p->flags; + /* Push it to our buddy. */ + upa_writel(buddy | IMAP_VALID, bp->imap); - if (!action_mask) - break; - } - if (bp->pil != 0) { - upa_writel(ICLR_IDLE, bp->iclr); - /* Test and add entropy */ - if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - } out: - bp->flags &= ~IBF_INPROGRESS; + return; } +#endif + void handler_irq(int irq, struct pt_regs *regs) { - struct ino_bucket *bp; + struct ino_bucket *bp, *nbp; int cpu = smp_processor_id(); #ifndef CONFIG_SMP @@ -620,6 +757,8 @@ void handler_irq(int irq, struct pt_regs *regs) clear_softint(clr_mask); } #else + int should_forward = 0; + clear_softint(1 << irq); #endif @@ -634,12 +773,63 @@ void handler_irq(int irq, struct pt_regs *regs) #else bp = __bucket(xchg32(irq_work(cpu, irq), 0)); #endif - while (bp) { - struct ino_bucket *nbp = __bucket(bp->irq_chain); + for ( ; bp != NULL; bp = nbp) { + unsigned char flags = bp->flags; + unsigned char random = 0; + nbp = __bucket(bp->irq_chain); bp->irq_chain = 0; - process_bucket(irq, bp, regs); - bp = nbp; + + bp->flags |= IBF_INPROGRESS; + + if ((flags & IBF_ACTIVE) != 0) { +#ifdef CONFIG_PCI + if ((flags & IBF_DMA_SYNC) != 0) { + upa_readl(dma_sync_reg_table[bp->synctab_ent]); + upa_readq(pci_dma_wsync); + } +#endif + if ((flags & IBF_MULTI) == 0) { + struct irqaction *ap = bp->irq_info; + int ret; + + ret = ap->handler(__irq(bp), ap->dev_id, regs); + if (ret == IRQ_HANDLED) + random |= ap->flags; + } else { + void **vector = (void **)bp->irq_info; + int ent; + for (ent = 0; ent < 4; ent++) { + struct irqaction *ap = vector[ent]; + if (ap != NULL) { + int ret; + + ret = ap->handler(__irq(bp), + ap->dev_id, + regs); + if (ret == IRQ_HANDLED) + random |= ap->flags; + } + } + } + /* Only the dummy bucket lacks IMAP/ICLR. */ + if (bp->pil != 0) { +#ifdef CONFIG_SMP + if (should_forward) { + redirect_intr(cpu, bp); + should_forward = 0; + } +#endif + upa_writel(ICLR_IDLE, bp->iclr); + + /* Test and add entropy */ + if (random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + } + } else + bp->pending = 1; + + bp->flags &= ~IBF_INPROGRESS; } irq_exit(); } @@ -769,10 +959,7 @@ static void distribute_irqs(void) */ for (level = 1; level < NR_IRQS; level++) { struct irqaction *p = irq_action[level]; - - if (level == 12) - continue; - + if (level == 12) continue; while(p) { cpu = retarget_one_irq(p, cpu); p = p->next; diff --git a/trunk/arch/sparc64/kernel/pci_psycho.c b/trunk/arch/sparc64/kernel/pci_psycho.c index 91ab466d6c66..534320ef0db2 100644 --- a/trunk/arch/sparc64/kernel/pci_psycho.c +++ b/trunk/arch/sparc64/kernel/pci_psycho.c @@ -1303,7 +1303,8 @@ static void psycho_controller_hwinit(struct pci_controller_info *p) { u64 tmp; - psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 5); + /* PROM sets the IRQ retry value too low, increase it. */ + psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 0xff); /* Enable arbiter for all PCI slots. */ tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL); diff --git a/trunk/arch/sparc64/kernel/pci_sabre.c b/trunk/arch/sparc64/kernel/pci_sabre.c index 52bf3431a422..53d333b4a4e8 100644 --- a/trunk/arch/sparc64/kernel/pci_sabre.c +++ b/trunk/arch/sparc64/kernel/pci_sabre.c @@ -595,23 +595,6 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) return ret; } -/* When a device lives behind a bridge deeper in the PCI bus topology - * than APB, a special sequence must run to make sure all pending DMA - * transfers at the time of IRQ delivery are visible in the coherency - * domain by the cpu. This sequence is to perform a read on the far - * side of the non-APB bridge, then perform a read of Sabre's DMA - * write-sync register. - */ -static void sabre_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) -{ - struct pci_dev *pdev = _arg1; - unsigned long sync_reg = (unsigned long) _arg2; - u16 _unused; - - pci_read_config_word(pdev, PCI_VENDOR_ID, &_unused); - sabre_read(sync_reg); -} - static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) @@ -656,14 +639,24 @@ static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm, if (pdev) { struct pcidev_cookie *pcp = pdev->sysdata; + /* When a device lives behind a bridge deeper in the + * PCI bus topology than APB, a special sequence must + * run to make sure all pending DMA transfers at the + * time of IRQ delivery are visible in the coherency + * domain by the cpu. This sequence is to perform + * a read on the far side of the non-APB bridge, then + * perform a read of Sabre's DMA write-sync register. + * + * Currently, the PCI_CONFIG register for the device + * is used for this read from the far side of the bridge. + */ if (pdev->bus->number != pcp->pbm->pci_first_busno) { - struct pci_controller_info *p = pcp->pbm->parent; - struct irq_desc *d = bucket->irq_info; - - d->pre_handler = sabre_wsync_handler; - d->pre_handler_arg1 = pdev; - d->pre_handler_arg2 = (void *) - p->pbm_A.controller_regs + SABRE_WRSYNC; + bucket->flags |= IBF_DMA_SYNC; + bucket->synctab_ent = dma_sync_reg_table_entry++; + dma_sync_reg_table[bucket->synctab_ent] = + (unsigned long) sabre_pci_config_mkaddr( + pcp->pbm, + pdev->bus->number, pdev->devfn, PCI_COMMAND); } } return __irq(bucket); @@ -1633,9 +1626,10 @@ void __init sabre_init(int pnode, char *model_name) */ p->pbm_A.controller_regs = pr_regs[0].phys_addr; p->pbm_B.controller_regs = pr_regs[0].phys_addr; + pci_dma_wsync = p->pbm_A.controller_regs + SABRE_WRSYNC; - printk("PCI: Found SABRE, main regs at %016lx\n", - p->pbm_A.controller_regs); + printk("PCI: Found SABRE, main regs at %016lx, wsync at %016lx\n", + p->pbm_A.controller_regs, pci_dma_wsync); /* Clear interrupts */ diff --git a/trunk/arch/sparc64/kernel/pci_schizo.c b/trunk/arch/sparc64/kernel/pci_schizo.c index 6a182bb66281..5753175b94e6 100644 --- a/trunk/arch/sparc64/kernel/pci_schizo.c +++ b/trunk/arch/sparc64/kernel/pci_schizo.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "pci_impl.h" #include "iommu_common.h" @@ -327,44 +326,6 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) return ret; } -static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) -{ - unsigned long sync_reg = (unsigned long) _arg2; - u64 mask = 1 << (__irq_ino(__irq(bucket)) & IMAP_INO); - u64 val; - int limit; - - schizo_write(sync_reg, mask); - - limit = 100000; - val = 0; - while (--limit) { - val = schizo_read(sync_reg); - if (!(val & mask)) - break; - } - if (limit <= 0) { - printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", - val, mask); - } - - if (_arg1) { - static unsigned char cacheline[64] - __attribute__ ((aligned (64))); - - __asm__ __volatile__("rd %%fprs, %0\n\t" - "or %0, %4, %1\n\t" - "wr %1, 0x0, %%fprs\n\t" - "stda %%f0, [%5] %6\n\t" - "wr %0, 0x0, %%fprs\n\t" - "membar #Sync" - : "=&r" (mask), "=&r" (val) - : "0" (mask), "1" (val), - "i" (FPRS_FEF), "r" (&cacheline[0]), - "i" (ASI_BLK_COMMIT_P)); - } -} - static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) @@ -408,15 +369,6 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap)); bucket->flags |= IBF_PCI; - if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { - struct irq_desc *p = bucket->irq_info; - - p->pre_handler = tomatillo_wsync_handler; - p->pre_handler_arg1 = ((pbm->chip_version <= 4) ? - (void *) 1 : (void *) 0); - p->pre_handler_arg2 = (void *) pbm->sync_reg; - } - return __irq(bucket); } @@ -933,7 +885,6 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs) #define SCHIZO_PCI_CTRL (0x2000UL) #define SCHIZO_PCICTRL_BUS_UNUS (1UL << 63UL) /* Safari */ -#define SCHIZO_PCICTRL_DTO_INT (1UL << 61UL) /* Tomatillo */ #define SCHIZO_PCICTRL_ARB_PRIO (0x1ff << 52UL) /* Tomatillo */ #define SCHIZO_PCICTRL_ESLCK (1UL << 51UL) /* Safari */ #define SCHIZO_PCICTRL_ERRSLOT (7UL << 48UL) /* Safari */ @@ -1936,27 +1887,37 @@ static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm) { u64 tmp; - schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5); + /* Set IRQ retry to infinity. */ + schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, + SCHIZO_IRQ_RETRY_INF); + /* Enable arbiter for all PCI slots. Also, disable PCI interval + * timer so that DTO (Discard TimeOuts) are not reported because + * some Schizo revisions report them erroneously. + */ tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL); + if (pbm->chip_type == PBM_CHIP_TYPE_SCHIZO_PLUS && + pbm->chip_version == 0x5 && + pbm->chip_revision == 0x1) + tmp |= 0x0f; + else + tmp |= 0xff; - /* Enable arbiter for all PCI slots. */ - tmp |= 0xff; - + tmp &= ~SCHIZO_PCICTRL_PTO; if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO && pbm->chip_version >= 0x2) tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT; + else + tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT; if (!prom_getbool(pbm->prom_node, "no-bus-parking")) tmp |= SCHIZO_PCICTRL_PARK; - else - tmp &= ~SCHIZO_PCICTRL_PARK; if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO && pbm->chip_version <= 0x1) - tmp |= SCHIZO_PCICTRL_DTO_INT; + tmp |= (1UL << 61); else - tmp &= ~SCHIZO_PCICTRL_DTO_INT; + tmp &= ~(1UL << 61); if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) tmp |= (SCHIZO_PCICTRL_MRM_PREF | @@ -2054,9 +2015,6 @@ static void __init schizo_pbm_init(struct pci_controller_info *p, pbm->pbm_regs = pr_regs[0].phys_addr; pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL; - if (chip_type == PBM_CHIP_TYPE_TOMATILLO) - pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL; - sprintf(pbm->name, (chip_type == PBM_CHIP_TYPE_TOMATILLO ? "TOMATILLO%d PBM%c" : diff --git a/trunk/arch/sparc64/kernel/time.c b/trunk/arch/sparc64/kernel/time.c index b40db389f90b..71b4e3807694 100644 --- a/trunk/arch/sparc64/kernel/time.c +++ b/trunk/arch/sparc64/kernel/time.c @@ -973,7 +973,7 @@ static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_reg int err; /* Register IRQ handler. */ - err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, 0, + err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC, "timer", NULL); if (err) { diff --git a/trunk/drivers/char/hw_random.c b/trunk/drivers/char/hw_random.c index 3480535a09c5..7e6ac14c2450 100644 --- a/trunk/drivers/char/hw_random.c +++ b/trunk/drivers/char/hw_random.c @@ -579,7 +579,7 @@ static int __init rng_init (void) /* Probe for Intel, AMD RNGs */ for_each_pci_dev(pdev) { - ent = pci_match_id(rng_pci_tbl, pdev); + ent = pci_match_device (rng_pci_tbl, pdev); if (ent) { rng_ops = &rng_vendor_ops[ent->driver_data]; goto match; diff --git a/trunk/drivers/char/watchdog/i8xx_tco.c b/trunk/drivers/char/watchdog/i8xx_tco.c index 5d07ee59679d..b14d642439ed 100644 --- a/trunk/drivers/char/watchdog/i8xx_tco.c +++ b/trunk/drivers/char/watchdog/i8xx_tco.c @@ -401,7 +401,7 @@ static unsigned char __init i8xx_tco_getdevice (void) */ while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (pci_match_id(i8xx_tco_pci_tbl, dev)) { + if (pci_match_device(i8xx_tco_pci_tbl, dev)) { i8xx_tco_pci = dev; break; } diff --git a/trunk/drivers/ide/setup-pci.c b/trunk/drivers/ide/setup-pci.c index 77da827b2898..e501675ad72e 100644 --- a/trunk/drivers/ide/setup-pci.c +++ b/trunk/drivers/ide/setup-pci.c @@ -847,7 +847,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev) d = list_entry(l, struct pci_driver, node); if(d->id_table) { - const struct pci_device_id *id = pci_match_id(d->id_table, dev); + const struct pci_device_id *id = pci_match_device(d->id_table, dev); if(id != NULL) { if(d->probe(dev, id) >= 0) diff --git a/trunk/drivers/parport/parport_pc.c b/trunk/drivers/parport/parport_pc.c index 4598c6a9212d..80edfa3abd29 100644 --- a/trunk/drivers/parport/parport_pc.c +++ b/trunk/drivers/parport/parport_pc.c @@ -3008,7 +3008,7 @@ static int __init parport_pc_init_superio (int autoirq, int autodma) int ret = 0; while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - id = pci_match_id(parport_pc_pci_tbl, pdev); + id = pci_match_device (parport_pc_pci_tbl, pdev); if (id == NULL || id->driver_data >= last_sio) continue; diff --git a/trunk/drivers/pci/Makefile b/trunk/drivers/pci/Makefile index 3657f6199c48..7dea494c0d7b 100644 --- a/trunk/drivers/pci/Makefile +++ b/trunk/drivers/pci/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ # # Some architectures use the generic PCI setup functions # -obj-$(CONFIG_X86) += setup-bus.o obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o obj-$(CONFIG_PARISC) += setup-bus.o diff --git a/trunk/drivers/pci/hotplug.c b/trunk/drivers/pci/hotplug.c index b844bc972324..3903f8c559b6 100644 --- a/trunk/drivers/pci/hotplug.c +++ b/trunk/drivers/pci/hotplug.c @@ -54,7 +54,7 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, envp[i++] = scratch; length += scnprintf (scratch, buffer_size - length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), diff --git a/trunk/drivers/pci/pci-driver.c b/trunk/drivers/pci/pci-driver.c index aac6de9568e5..e65bf2b395aa 100644 --- a/trunk/drivers/pci/pci-driver.c +++ b/trunk/drivers/pci/pci-driver.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "pci.h" /* @@ -18,11 +19,35 @@ */ #ifdef CONFIG_HOTPLUG +/** + * pci_device_probe_dynamic() + * + * Walk the dynamic ID list looking for a match. + * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. + */ +static int +pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) +{ + int error = -ENODEV; + struct list_head *pos; + struct dynid *dynid; -struct pci_dynid { - struct list_head node; - struct pci_device_id id; -}; + spin_lock(&drv->dynids.lock); + list_for_each(pos, &drv->dynids.list) { + dynid = list_entry(pos, struct dynid, node); + if (pci_match_one_device(&dynid->id, pci_dev)) { + spin_unlock(&drv->dynids.lock); + error = drv->probe(pci_dev, &dynid->id); + if (error >= 0) { + pci_dev->driver = drv; + return 0; + } + return error; + } + } + spin_unlock(&drv->dynids.lock); + return error; +} /** * store_new_id @@ -33,7 +58,8 @@ struct pci_dynid { static inline ssize_t store_new_id(struct device_driver *driver, const char *buf, size_t count) { - struct pci_dynid *dynid; + struct dynid *dynid; + struct bus_type * bus; struct pci_driver *pdrv = to_pci_driver(driver); __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID, subdevice=PCI_ANY_ID, class=0, class_mask=0; @@ -65,22 +91,37 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) list_add_tail(&pdrv->dynids.list, &dynid->node); spin_unlock(&pdrv->dynids.lock); - if (get_driver(&pdrv->driver)) { - driver_attach(&pdrv->driver); - put_driver(&pdrv->driver); + bus = get_bus(pdrv->driver.bus); + if (bus) { + if (get_driver(&pdrv->driver)) { + down_write(&bus->subsys.rwsem); + driver_attach(&pdrv->driver); + up_write(&bus->subsys.rwsem); + put_driver(&pdrv->driver); + } + put_bus(bus); } return count; } + static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); +static inline void +pci_init_dynids(struct pci_dynids *dynids) +{ + spin_lock_init(&dynids->lock); + INIT_LIST_HEAD(&dynids->list); +} static void pci_free_dynids(struct pci_driver *drv) { - struct pci_dynid *dynid, *n; + struct list_head *pos, *n; + struct dynid *dynid; spin_lock(&drv->dynids.lock); - list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { + list_for_each_safe(pos, n, &drv->dynids.list) { + dynid = list_entry(pos, struct dynid, node); list_del(&dynid->node); kfree(dynid); } @@ -97,70 +138,83 @@ pci_create_newid_file(struct pci_driver *drv) return error; } +static int +pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) +{ + struct list_head *pos; + struct dynid *dynid; + + spin_lock(&pci_drv->dynids.lock); + list_for_each(pos, &pci_drv->dynids.list) { + dynid = list_entry(pos, struct dynid, node); + if (pci_match_one_device(&dynid->id, pci_dev)) { + spin_unlock(&pci_drv->dynids.lock); + return 1; + } + } + spin_unlock(&pci_drv->dynids.lock); + return 0; +} + #else /* !CONFIG_HOTPLUG */ +static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) +{ + return -ENODEV; +} +static inline void pci_init_dynids(struct pci_dynids *dynids) {} static inline void pci_free_dynids(struct pci_driver *drv) {} static inline int pci_create_newid_file(struct pci_driver *drv) { return 0; } +static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) +{ + return 0; +} #endif /** - * pci_match_id - See if a pci device matches a given pci_id table + * pci_match_device - Tell if a PCI device structure has a matching + * PCI device id structure * @ids: array of PCI device id structures to search in - * @dev: the PCI device structure to match against. - * + * @dev: the PCI device structure to match against + * * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices. Returns the matching + * system is in its list of supported devices.Returns the matching * pci_device_id structure or %NULL if there is no match. - * - * Depreciated, don't use this as it will not catch any dynamic ids - * that a driver might want to check for. */ -const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, - struct pci_dev *dev) +const struct pci_device_id * +pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { - if (ids) { - while (ids->vendor || ids->subvendor || ids->class_mask) { - if (pci_match_one_device(ids, dev)) - return ids; - ids++; - } + while (ids->vendor || ids->subvendor || ids->class_mask) { + if (pci_match_one_device(ids, dev)) + return ids; + ids++; } return NULL; } /** - * pci_match_device - Tell if a PCI device structure has a matching - * PCI device id structure - * @ids: array of PCI device id structures to search in - * @dev: the PCI device structure to match against - * @drv: the PCI driver to match against - * - * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices. Returns the matching - * pci_device_id structure or %NULL if there is no match. + * pci_device_probe_static() + * + * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. */ -const struct pci_device_id *pci_match_device(struct pci_driver *drv, - struct pci_dev *dev) -{ +static int +pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev) +{ + int error = -ENODEV; const struct pci_device_id *id; - struct pci_dynid *dynid; - id = pci_match_id(drv->id_table, dev); + if (!drv->id_table) + return error; + id = pci_match_device(drv->id_table, pci_dev); if (id) - return id; - - /* static ids didn't match, lets look at the dynamic ones */ - spin_lock(&drv->dynids.lock); - list_for_each_entry(dynid, &drv->dynids.list, node) { - if (pci_match_one_device(&dynid->id, dev)) { - spin_unlock(&drv->dynids.lock); - return &dynid->id; - } + error = drv->probe(pci_dev, id); + if (error >= 0) { + pci_dev->driver = drv; + error = 0; } - spin_unlock(&drv->dynids.lock); - return NULL; + return error; } /** @@ -171,20 +225,13 @@ const struct pci_device_id *pci_match_device(struct pci_driver *drv, */ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) -{ - const struct pci_device_id *id; +{ int error = 0; if (!pci_dev->driver && drv->probe) { - error = -ENODEV; - - id = pci_match_device(drv, pci_dev); - if (id) - error = drv->probe(pci_dev, id); - if (error >= 0) { - pci_dev->driver = drv; - error = 0; - } + error = pci_device_probe_static(drv, pci_dev); + if (error == -ENODEV) + error = pci_device_probe_dynamic(drv, pci_dev); } return error; } @@ -324,6 +371,12 @@ static struct kobj_type pci_driver_kobj_type = { .sysfs_ops = &pci_driver_sysfs_ops, }; +static int +pci_populate_driver_dir(struct pci_driver *drv) +{ + return pci_create_newid_file(drv); +} + /** * pci_register_driver - register a new pci driver * @drv: the driver structure to register @@ -348,15 +401,13 @@ int pci_register_driver(struct pci_driver *drv) drv->driver.shutdown = pci_device_shutdown; drv->driver.owner = drv->owner; drv->driver.kobj.ktype = &pci_driver_kobj_type; - - spin_lock_init(&drv->dynids.lock); - INIT_LIST_HEAD(&drv->dynids.list); + pci_init_dynids(&drv->dynids); /* register with core */ error = driver_register(&drv->driver); if (!error) - error = pci_create_newid_file(drv); + pci_populate_driver_dir(drv); return error; } @@ -412,17 +463,21 @@ pci_dev_driver(const struct pci_dev *dev) * system is in its list of supported devices.Returns the matching * pci_device_id structure or %NULL if there is no match. */ -static int pci_bus_match(struct device *dev, struct device_driver *drv) +static int pci_bus_match(struct device * dev, struct device_driver * drv) { - struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *pci_drv = to_pci_driver(drv); + const struct pci_dev * pci_dev = to_pci_dev(dev); + struct pci_driver * pci_drv = to_pci_driver(drv); + const struct pci_device_id * ids = pci_drv->id_table; const struct pci_device_id *found_id; - found_id = pci_match_device(pci_drv, pci_dev); + if (!ids) + return 0; + + found_id = pci_match_device(ids, pci_dev); if (found_id) return 1; - return 0; + return pci_bus_match_dynids(pci_dev, pci_drv); } /** @@ -481,7 +536,6 @@ static int __init pci_driver_init(void) postcore_initcall(pci_driver_init); -EXPORT_SYMBOL(pci_match_id); EXPORT_SYMBOL(pci_match_device); EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_unregister_driver); diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index d382bdb7b560..f04b9ffe4153 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -334,6 +334,10 @@ EXPORT_SYMBOL(pci_choose_state); /** * pci_save_state - save the PCI configuration space of a device before suspending * @dev: - PCI device that we're dealing with + * @buffer: - buffer to hold config space context + * + * @buffer must be large enough to hold the entire PCI 2.2 config space + * (>= 64 bytes). */ int pci_save_state(struct pci_dev *dev) @@ -348,6 +352,8 @@ pci_save_state(struct pci_dev *dev) /** * pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with + * @buffer: - saved PCI config space + * */ int pci_restore_state(struct pci_dev *dev) diff --git a/trunk/drivers/pci/pcie/portdrv.h b/trunk/drivers/pci/pcie/portdrv.h index a63bd8f72601..537b372dc340 100644 --- a/trunk/drivers/pci/pcie/portdrv.h +++ b/trunk/drivers/pci/pcie/portdrv.h @@ -27,11 +27,6 @@ #define get_descriptor_id(type, service) (((type - 4) << 4) | service) -struct pcie_port_device_ext { - int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ - unsigned int saved_msi_config_space[5]; -}; - extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_probe(struct pci_dev *dev); extern int pcie_port_device_register(struct pci_dev *dev); diff --git a/trunk/drivers/pci/pcie/portdrv_core.c b/trunk/drivers/pci/pcie/portdrv_core.c index 4db69982876e..f5c5f10a3d2f 100644 --- a/trunk/drivers/pci/pcie/portdrv_core.c +++ b/trunk/drivers/pci/pcie/portdrv_core.c @@ -275,17 +275,10 @@ int pcie_port_device_probe(struct pci_dev *dev) int pcie_port_device_register(struct pci_dev *dev) { - struct pcie_port_device_ext *p_ext; int status, type, capabilities, irq_mode, i; int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; u16 reg16; - /* Allocate port device extension */ - if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL))) - return -ENOMEM; - - pci_set_drvdata(dev, p_ext); - /* Get port type */ pci_read_config_word(dev, pci_find_capability(dev, PCI_CAP_ID_EXP) + @@ -295,7 +288,6 @@ int pcie_port_device_register(struct pci_dev *dev) /* Now get port services */ capabilities = get_port_device_capability(dev); irq_mode = assign_interrupt_mode(dev, vectors, capabilities); - p_ext->interrupt_mode = irq_mode; /* Allocate child services if any */ for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { diff --git a/trunk/drivers/pci/pcie/portdrv_pci.c b/trunk/drivers/pci/pcie/portdrv_pci.c index 30bac7ed7c16..e9095ee508e3 100644 --- a/trunk/drivers/pci/pcie/portdrv_pci.c +++ b/trunk/drivers/pci/pcie/portdrv_pci.c @@ -29,78 +29,6 @@ MODULE_LICENSE("GPL"); /* global data */ static const char device_name[] = "pcieport-driver"; -static void pci_save_msi_state(struct pci_dev *dev) -{ - struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); - int i = 0, pos; - u16 control; - - if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) - return; - - pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]); - control = p_ext->saved_msi_config_space[0] >> 16; - pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, - &p_ext->saved_msi_config_space[i++]); - if (control & PCI_MSI_FLAGS_64BIT) { - pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, - &p_ext->saved_msi_config_space[i++]); - pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, - &p_ext->saved_msi_config_space[i++]); - } else - pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, - &p_ext->saved_msi_config_space[i++]); - if (control & PCI_MSI_FLAGS_MASKBIT) - pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, - &p_ext->saved_msi_config_space[i++]); -} - -static void pci_restore_msi_state(struct pci_dev *dev) -{ - struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); - int i = 0, pos; - u16 control; - - if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) - return; - - control = p_ext->saved_msi_config_space[i++] >> 16; - pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); - pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, - p_ext->saved_msi_config_space[i++]); - if (control & PCI_MSI_FLAGS_64BIT) { - pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, - p_ext->saved_msi_config_space[i++]); - pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, - p_ext->saved_msi_config_space[i++]); - } else - pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, - p_ext->saved_msi_config_space[i++]); - if (control & PCI_MSI_FLAGS_MASKBIT) - pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, - p_ext->saved_msi_config_space[i++]); -} - -static void pcie_portdrv_save_config(struct pci_dev *dev) -{ - struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); - - pci_save_state(dev); - if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) - pci_save_msi_state(dev); -} - -static void pcie_portdrv_restore_config(struct pci_dev *dev) -{ - struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); - - pci_restore_state(dev); - if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) - pci_restore_msi_state(dev); - pci_enable_device(dev); - pci_set_master(dev); -} - /* * pcie_portdrv_probe - Probe PCI-Express port devices * @dev: PCI-Express port device being probed @@ -136,21 +64,16 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, static void pcie_portdrv_remove (struct pci_dev *dev) { pcie_port_device_remove(dev); - kfree(pci_get_drvdata(dev)); } #ifdef CONFIG_PM static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) { - int ret = pcie_port_device_suspend(dev, state); - - pcie_portdrv_save_config(dev); - return ret; + return pcie_port_device_suspend(dev, state); } static int pcie_portdrv_resume (struct pci_dev *dev) { - pcie_portdrv_restore_config(dev); return pcie_port_device_resume(dev); } #endif diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index df3bdae2040f..6a0a82f0508b 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -239,8 +239,9 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) if (dev->transparent) { printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev)); - for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) - child->resource[i] = child->parent->resource[i - 3]; + for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) + child->resource[i] = child->parent->resource[i]; + return; } for(i=0; i<3; i++) @@ -397,16 +398,6 @@ static void pci_enable_crs(struct pci_dev *dev) pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); } -static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) -{ - struct pci_bus *parent = child->parent; - while (parent->parent && parent->subordinate < max) { - parent->subordinate = max; - pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max); - parent = parent->parent; - } -} - unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); /* @@ -508,13 +499,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max if (!is_cardbus) { child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA; - /* - * Adjust subordinate busnr in parent buses. - * We do this before scanning for children because - * some devices may not be detected if the bios - * was lazy. - */ - pci_fixup_parent_subordinate_busnr(child, max); + /* Now we can scan all subordinate buses... */ max = pci_scan_child_bus(child); } else { @@ -528,7 +513,6 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max max+i+1)) break; max += i; - pci_fixup_parent_subordinate_busnr(child, max); } /* * Set the subordinate bus number to its real value. diff --git a/trunk/drivers/pci/quirks.c b/trunk/drivers/pci/quirks.c index 1521fd5d95cc..968033fd29f0 100644 --- a/trunk/drivers/pci/quirks.c +++ b/trunk/drivers/pci/quirks.c @@ -767,7 +767,6 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) switch(dev->subsystem_device) { - case 0x8025: /* P4B-LX */ case 0x8070: /* P4B */ case 0x8088: /* P4B533 */ case 0x1626: /* L3C notebook */ diff --git a/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c index c1bdfb424658..6b628de948af 100644 --- a/trunk/drivers/pci/setup-bus.c +++ b/trunk/drivers/pci/setup-bus.c @@ -273,8 +273,6 @@ find_free_bus_resource(struct pci_bus *bus, unsigned long type) for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { r = bus->resource[i]; - if (r == &ioport_resource || r == &iomem_resource) - continue; if (r && (r->flags & type_mask) == type && !r->parent) return r; } diff --git a/trunk/drivers/sbus/char/bpp.c b/trunk/drivers/sbus/char/bpp.c index 87302fb14885..8f0f46907a81 100644 --- a/trunk/drivers/sbus/char/bpp.c +++ b/trunk/drivers/sbus/char/bpp.c @@ -79,6 +79,10 @@ struct inst { unsigned char run_length; unsigned char repeat_byte; + + /* These members manage timeouts for programmed delays */ + wait_queue_head_t wait_queue; + struct timer_list timer_list; }; static struct inst instances[BPP_NO]; @@ -293,10 +297,16 @@ static unsigned short get_pins(unsigned minor) #endif /* __sparc__ */ +static void bpp_wake_up(unsigned long val) +{ wake_up(&instances[val].wait_queue); } + static void snooze(unsigned long snooze_time, unsigned minor) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(snooze_time + 1); + init_timer(&instances[minor].timer_list); + instances[minor].timer_list.expires = jiffies + snooze_time + 1; + instances[minor].timer_list.data = minor; + add_timer(&instances[minor].timer_list); + sleep_on (&instances[minor].wait_queue); } static int wait_for(unsigned short set, unsigned short clr, @@ -870,8 +880,11 @@ static void probeLptPort(unsigned idx) instances[idx].enhanced = 0; instances[idx].direction = 0; instances[idx].mode = COMPATIBILITY; + instances[idx].wait_queue = 0; instances[idx].run_length = 0; instances[idx].run_flag = 0; + init_timer(&instances[idx].timer_list); + instances[idx].timer_list.function = bpp_wake_up; if (!request_region(lpAddr,3, dev_name)) return; /* @@ -964,8 +977,11 @@ static void probeLptPort(unsigned idx) instances[idx].enhanced = 0; instances[idx].direction = 0; instances[idx].mode = COMPATIBILITY; + init_waitqueue_head(&instances[idx].wait_queue); instances[idx].run_length = 0; instances[idx].run_flag = 0; + init_timer(&instances[idx].timer_list); + instances[idx].timer_list.function = bpp_wake_up; if (!rp) return; diff --git a/trunk/include/asm-sparc64/irq.h b/trunk/include/asm-sparc64/irq.h index 8b70edcb80dc..018e2e46082b 100644 --- a/trunk/include/asm-sparc64/irq.h +++ b/trunk/include/asm-sparc64/irq.h @@ -16,18 +16,6 @@ #include #include -struct ino_bucket; - -#define MAX_IRQ_DESC_ACTION 4 - -struct irq_desc { - void (*pre_handler)(struct ino_bucket *, void *, void *); - void *pre_handler_arg1; - void *pre_handler_arg2; - u32 action_active_mask; - struct irqaction action[MAX_IRQ_DESC_ACTION]; -}; - /* You should not mess with this directly. That's the job of irq.c. * * If you make changes here, please update hand coded assembler of @@ -54,11 +42,24 @@ struct ino_bucket { /* Miscellaneous flags. */ /*0x06*/unsigned char flags; - /* Currently unused. */ -/*0x07*/unsigned char __pad; - - /* Reference to IRQ descriptor for this bucket. */ -/*0x08*/struct irq_desc *irq_info; + /* This is used to deal with IBF_DMA_SYNC on + * Sabre systems. + */ +/*0x07*/unsigned char synctab_ent; + + /* Reference to handler for this IRQ. If this is + * non-NULL this means it is active and should be + * serviced. Else the pending member is set to one + * and later registry of the interrupt checks for + * this condition. + * + * Normally this is just an irq_action structure. + * But, on PCI, if multiple interrupt sources behind + * a bridge have multiple interrupt sources that share + * the same INO bucket, this points to an array of + * pointers to four IRQ action structures. + */ +/*0x08*/void *irq_info; /* Sun5 Interrupt Clear Register. */ /*0x10*/unsigned long iclr; @@ -68,6 +69,12 @@ struct ino_bucket { }; +#ifdef CONFIG_PCI +extern unsigned long pci_dma_wsync; +extern unsigned long dma_sync_reg_table[256]; +extern unsigned char dma_sync_reg_table_entry; +#endif + /* IMAP/ICLR register defines */ #define IMAP_VALID 0x80000000 /* IRQ Enabled */ #define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */ @@ -83,9 +90,11 @@ struct ino_bucket { #define ICLR_PENDING 0x00000003 /* Pending state */ /* Only 8-bits are available, be careful. -DaveM */ -#define IBF_PCI 0x02 /* PSYCHO/SABRE/SCHIZO PCI interrupt. */ -#define IBF_ACTIVE 0x04 /* Interrupt is active and has a handler.*/ -#define IBF_INPROGRESS 0x10 /* IRQ is being serviced. */ +#define IBF_DMA_SYNC 0x01 /* DMA synchronization behind PCI bridge needed. */ +#define IBF_PCI 0x02 /* Indicates PSYCHO/SABRE/SCHIZO PCI interrupt. */ +#define IBF_ACTIVE 0x04 /* This interrupt is active and has a handler. */ +#define IBF_MULTI 0x08 /* On PCI, indicates shared bucket. */ +#define IBF_INPROGRESS 0x10 /* IRQ is being serviced. */ #define NUM_IVECS (IMAP_INR + 1) extern struct ino_bucket ivector_table[NUM_IVECS]; diff --git a/trunk/include/asm-sparc64/pbm.h b/trunk/include/asm-sparc64/pbm.h index 38bbbccb4068..4c15610a2bac 100644 --- a/trunk/include/asm-sparc64/pbm.h +++ b/trunk/include/asm-sparc64/pbm.h @@ -145,9 +145,6 @@ struct pci_pbm_info { /* Physical address base of PBM registers. */ unsigned long pbm_regs; - /* Physical address of DMA sync register, if any. */ - unsigned long sync_reg; - /* Opaque 32-bit system bus Port ID. */ u32 portid; diff --git a/trunk/include/asm-sparc64/signal.h b/trunk/include/asm-sparc64/signal.h index e3059bb4a465..becdf1bc5924 100644 --- a/trunk/include/asm-sparc64/signal.h +++ b/trunk/include/asm-sparc64/signal.h @@ -162,6 +162,21 @@ struct sigstack { #define MINSIGSTKSZ 4096 #define SIGSTKSZ 16384 +#ifdef __KERNEL__ +/* + * DJHR + * SA_STATIC_ALLOC is used for the SPARC system to indicate that this + * interrupt handler's irq structure should be statically allocated + * by the request_irq routine. + * The alternative is that arch/sparc/kernel/irq.c has carnal knowledge + * of interrupt usage and that sucks. Also without a flag like this + * it may be possible for the free_irq routine to attempt to free + * statically allocated data.. which is NOT GOOD. + * + */ +#define SA_STATIC_ALLOC 0x80 +#endif + #include struct __new_sigaction { diff --git a/trunk/include/linux/compat_ioctl.h b/trunk/include/linux/compat_ioctl.h index ecb0d39c0798..70a4ebb5d964 100644 --- a/trunk/include/linux/compat_ioctl.h +++ b/trunk/include/linux/compat_ioctl.h @@ -346,27 +346,10 @@ COMPATIBLE_IOCTL(PPPOEIOCDFWD) /* LP */ COMPATIBLE_IOCTL(LPGETSTATUS) /* ppdev */ -COMPATIBLE_IOCTL(PPSETMODE) -COMPATIBLE_IOCTL(PPRSTATUS) -COMPATIBLE_IOCTL(PPRCONTROL) -COMPATIBLE_IOCTL(PPWCONTROL) -COMPATIBLE_IOCTL(PPFCONTROL) -COMPATIBLE_IOCTL(PPRDATA) -COMPATIBLE_IOCTL(PPWDATA) COMPATIBLE_IOCTL(PPCLAIM) COMPATIBLE_IOCTL(PPRELEASE) -COMPATIBLE_IOCTL(PPYIELD) COMPATIBLE_IOCTL(PPEXCL) -COMPATIBLE_IOCTL(PPDATADIR) -COMPATIBLE_IOCTL(PPNEGOT) -COMPATIBLE_IOCTL(PPWCTLONIRQ) -COMPATIBLE_IOCTL(PPCLRIRQ) -COMPATIBLE_IOCTL(PPSETPHASE) -COMPATIBLE_IOCTL(PPGETMODES) -COMPATIBLE_IOCTL(PPGETMODE) -COMPATIBLE_IOCTL(PPGETPHASE) -COMPATIBLE_IOCTL(PPGETFLAGS) -COMPATIBLE_IOCTL(PPSETFLAGS) +COMPATIBLE_IOCTL(PPYIELD) /* CDROM stuff */ COMPATIBLE_IOCTL(CDROMPAUSE) COMPATIBLE_IOCTL(CDROMRESUME) diff --git a/trunk/include/linux/pci-dynids.h b/trunk/include/linux/pci-dynids.h new file mode 100644 index 000000000000..183b6b0de81c --- /dev/null +++ b/trunk/include/linux/pci-dynids.h @@ -0,0 +1,18 @@ +/* + * PCI defines and function prototypes + * Copyright 2003 Dell Inc. + * by Matt Domsch + */ + +#ifndef LINUX_PCI_DYNIDS_H +#define LINUX_PCI_DYNIDS_H + +#include +#include + +struct dynid { + struct list_head node; + struct pci_device_id id; +}; + +#endif diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 7ac14961ba22..66798b46f308 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -586,7 +586,7 @@ struct pci_dev { #define PCI_NUM_RESOURCES 11 #ifndef PCI_BUS_NUM_RESOURCES -#define PCI_BUS_NUM_RESOURCES 8 +#define PCI_BUS_NUM_RESOURCES 4 #endif #define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */ @@ -860,8 +860,7 @@ int pci_register_driver(struct pci_driver *); void pci_unregister_driver(struct pci_driver *); void pci_remove_behind_bridge(struct pci_dev *); struct pci_driver *pci_dev_driver(const struct pci_dev *); -const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev); -const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev); +const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); /* kmem_cache style wrapper around pci_alloc_consistent() */ diff --git a/trunk/include/linux/skbuff.h b/trunk/include/linux/skbuff.h index 416a2e4024b2..fbcb18651970 100644 --- a/trunk/include/linux/skbuff.h +++ b/trunk/include/linux/skbuff.h @@ -1211,7 +1211,7 @@ static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, { int hlen = skb_headlen(skb); - if (offset + len <= hlen) + if (hlen - offset >= len) return skb->data + offset; if (skb_copy_bits(skb, offset, buffer, len) < 0) diff --git a/trunk/sound/pci/bt87x.c b/trunk/sound/pci/bt87x.c index 909fef8903cb..defdc5a459f0 100644 --- a/trunk/sound/pci/bt87x.c +++ b/trunk/sound/pci/bt87x.c @@ -804,7 +804,7 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) int i; const struct pci_device_id *supported; - supported = pci_match_device(driver, pci); + supported = pci_match_device(snd_bt87x_ids, pci); if (supported) return supported->driver_data;