📄 intc.c
字号:
static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id){ struct intc_group *g = desc->groups; unsigned int i, j; for (i = 0; g && enum_id && i < desc->nr_groups; i++) { g = desc->groups + i; for (j = 0; g->enum_ids[j]; j++) { if (g->enum_ids[j] != enum_id) continue; return g->enum_id; } } return 0;}static unsigned int __init intc_prio_value(struct intc_desc *desc, intc_enum enum_id, int do_grps){ struct intc_prio *p = desc->priorities; unsigned int i; for (i = 0; p && enum_id && i < desc->nr_priorities; i++) { p = desc->priorities + i; if (p->enum_id != enum_id) continue; return p->priority; } if (do_grps) return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0); /* default to the lowest priority possible if no priority is set * - this needs to be at least 2 for 5-bit priorities on 7780 */ return 2;}static unsigned int __init intc_mask_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, int do_grps){ struct intc_mask_reg *mr = desc->mask_regs; unsigned int i, j, fn, mode; unsigned long reg_e, reg_d; for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) { mr = desc->mask_regs + i; for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { if (mr->enum_ids[j] != enum_id) continue; if (mr->set_reg && mr->clr_reg) { fn = REG_FN_WRITE_BASE; mode = MODE_DUAL_REG; reg_e = mr->clr_reg; reg_d = mr->set_reg; } else { fn = REG_FN_MODIFY_BASE; if (mr->set_reg) { mode = MODE_ENABLE_REG; reg_e = mr->set_reg; reg_d = mr->set_reg; } else { mode = MODE_MASK_REG; reg_e = mr->clr_reg; reg_d = mr->clr_reg; } } fn += (mr->reg_width >> 3) - 1; return _INTC_MK(fn, mode, intc_get_reg(d, reg_e), intc_get_reg(d, reg_d), 1, (mr->reg_width - 1) - j); } } if (do_grps) return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0;}static unsigned int __init intc_prio_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, int do_grps){ struct intc_prio_reg *pr = desc->prio_regs; unsigned int i, j, fn, mode, bit; unsigned long reg_e, reg_d; for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) { pr = desc->prio_regs + i; for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) { if (pr->enum_ids[j] != enum_id) continue; if (pr->set_reg && pr->clr_reg) { fn = REG_FN_WRITE_BASE; mode = MODE_PCLR_REG; reg_e = pr->set_reg; reg_d = pr->clr_reg; } else { fn = REG_FN_MODIFY_BASE; mode = MODE_PRIO_REG; if (!pr->set_reg) BUG(); reg_e = pr->set_reg; reg_d = pr->set_reg; } fn += (pr->reg_width >> 3) - 1; bit = pr->reg_width - ((j + 1) * pr->field_width); BUG_ON(bit < 0); return _INTC_MK(fn, mode, intc_get_reg(d, reg_e), intc_get_reg(d, reg_d), pr->field_width, bit); } } if (do_grps) return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0;}static unsigned int __init intc_sense_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id){ struct intc_sense_reg *sr = desc->sense_regs; unsigned int i, j, fn, bit; for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) { sr = desc->sense_regs + i; for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) { if (sr->enum_ids[j] != enum_id) continue; fn = REG_FN_MODIFY_BASE; fn += (sr->reg_width >> 3) - 1; bit = sr->reg_width - ((j + 1) * sr->field_width); BUG_ON(bit < 0); return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg), 0, sr->field_width, bit); } } return 0;}static void __init intc_register_irq(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, unsigned int irq){ struct intc_handle_int *hp; unsigned int data[2], primary; /* Prefer single interrupt source bitmap over other combinations: * 1. bitmap, single interrupt source * 2. priority, single interrupt source * 3. bitmap, multiple interrupt sources (groups) * 4. priority, multiple interrupt sources (groups) */ data[0] = intc_mask_data(desc, d, enum_id, 0); data[1] = intc_prio_data(desc, d, enum_id, 0); primary = 0; if (!data[0] && data[1]) primary = 1; data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1); data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1); if (!data[primary]) primary ^= 1; BUG_ON(!data[primary]); /* must have primary masking method */ disable_irq_nosync(irq); set_irq_chip_and_handler_name(irq, &d->chip, handle_level_irq, "level"); set_irq_chip_data(irq, (void *)data[primary]); /* record the desired priority level */ intc_prio_level[irq] = intc_prio_value(desc, enum_id, 1); /* enable secondary masking method if present */ if (data[!primary]) _intc_enable(irq, data[!primary]); /* add irq to d->prio list if priority is available */ if (data[1]) { hp = d->prio + d->nr_prio; hp->irq = irq; hp->handle = data[1]; if (primary) { /* * only secondary priority should access registers, so * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() */ hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); } d->nr_prio++; } /* add irq to d->sense list if sense is available */ data[0] = intc_sense_data(desc, d, enum_id); if (data[0]) { (d->sense + d->nr_sense)->irq = irq; (d->sense + d->nr_sense)->handle = data[0]; d->nr_sense++; } /* irq should be disabled by default */ d->chip.mask(irq);}static unsigned int __init save_reg(struct intc_desc_int *d, unsigned int cnt, unsigned long value, unsigned int smp){ if (value) { d->reg[cnt] = value;#ifdef CONFIG_SMP d->smp[cnt] = smp;#endif return 1; } return 0;}void __init register_intc_controller(struct intc_desc *desc){ unsigned int i, k, smp; struct intc_desc_int *d; d = alloc_bootmem(sizeof(*d)); d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));#ifdef CONFIG_SMP d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));#endif k = 0; if (desc->mask_regs) { for (i = 0; i < desc->nr_mask_regs; i++) { smp = IS_SMP(desc->mask_regs[i]); k += save_reg(d, k, desc->mask_regs[i].set_reg, smp); k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp); } } if (desc->prio_regs) { d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio)); for (i = 0; i < desc->nr_prio_regs; i++) { smp = IS_SMP(desc->prio_regs[i]); k += save_reg(d, k, desc->prio_regs[i].set_reg, smp); k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp); } } if (desc->sense_regs) { d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense)); for (i = 0; i < desc->nr_sense_regs; i++) { k += save_reg(d, k, desc->sense_regs[i].reg, 0); } } BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ d->chip.name = desc->name; d->chip.mask = intc_disable; d->chip.unmask = intc_enable; d->chip.mask_ack = intc_disable; d->chip.set_type = intc_set_sense; for (i = 0; i < desc->nr_vectors; i++) { struct intc_vect *vect = desc->vectors + i; intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -