/** * struct ti_sci_inta_event_desc - Description of an event coming to * Interrupt Aggregator. This serves * as a mapping table for global event, * hwirq and vint bit. * @global_event: Global event number corresponding to this event * @hwirq: Hwirq of the incoming interrupt * @vint_bit: Corresponding vint bit to which this event is attached.
*/ struct ti_sci_inta_event_desc {
u16 global_event;
u32 hwirq;
u8 vint_bit;
};
/** * struct ti_sci_inta_vint_desc - Description of a virtual interrupt coming out * of Interrupt Aggregator. * @domain: Pointer to IRQ domain to which this vint belongs. * @list: List entry for the vint list * @event_map: Bitmap to manage the allocation of events to vint. * @events: Array of event descriptors assigned to this vint. * @parent_virq: Linux IRQ number that gets attached to parent * @vint_id: TISCI vint ID
*/ struct ti_sci_inta_vint_desc { struct irq_domain *domain; struct list_head list;
DECLARE_BITMAP(event_map, MAX_EVENTS_PER_VINT); struct ti_sci_inta_event_desc events[MAX_EVENTS_PER_VINT]; unsignedint parent_virq;
u16 vint_id;
};
/** * struct ti_sci_inta_irq_domain - Structure representing a TISCI based * Interrupt Aggregator IRQ domain. * @sci: Pointer to TISCI handle * @vint: TISCI resource pointer representing IA interrupts. * @global_event: TISCI resource pointer representing global events. * @vint_list: List of the vints active in the system * @vint_mutex: Mutex to protect vint_list * @base: Base address of the memory mapped IO registers * @pdev: Pointer to platform device. * @ti_sci_id: TI-SCI device identifier * @unmapped_cnt: Number of @unmapped_dev_ids entries * @unmapped_dev_ids: Pointer to an array of TI-SCI device identifiers of * unmapped event sources. * Unmapped Events are not part of the Global Event Map and * they are converted to Global event within INTA to be * received by the same INTA to generate an interrupt. * In case an interrupt request comes for a device which is * generating Unmapped Event, we must use the INTA's TI-SCI * device identifier in place of the source device * identifier to let sysfw know where it has to program the * Global Event number.
*/ struct ti_sci_inta_irq_domain { conststruct ti_sci_handle *sci; struct ti_sci_resource *vint; struct ti_sci_resource *global_event; struct list_head vint_list; /* Mutex to protect vint list */ struct mutex vint_mutex; void __iomem *base; struct platform_device *pdev;
u32 ti_sci_id;
/* * For devices sending Unmapped Events we must use the INTA's TI-SCI * device identifier number to be able to convert it to a Global Event * and map it to an interrupt.
*/ for (i = 0; i < inta->unmapped_cnt; i++) { if (dev_id == inta->unmapped_dev_ids[i]) {
dev_id = inta->ti_sci_id; break;
}
}
return dev_id;
}
/** * ti_sci_inta_irq_handler() - Chained IRQ handler for the vint irqs * @desc: Pointer to irq_desc corresponding to the irq
*/ staticvoid ti_sci_inta_irq_handler(struct irq_desc *desc)
{ struct ti_sci_inta_vint_desc *vint_desc; struct ti_sci_inta_irq_domain *inta; struct irq_domain *domain; unsignedint bit; unsignedlong val;
/** * ti_sci_inta_alloc_event() - Attach an event to a IA vint. * @vint_desc: Pointer to vint_desc to which the event gets attached * @free_bit: Bit inside vint to which event gets attached * @hwirq: hwirq of the input event * * Return event_desc pointer if all went ok else appropriate error value.
*/ staticstruct ti_sci_inta_event_desc *ti_sci_inta_alloc_event(struct ti_sci_inta_vint_desc *vint_desc,
u16 free_bit,
u32 hwirq)
{ struct ti_sci_inta_irq_domain *inta = vint_desc->domain->host_data; struct ti_sci_inta_event_desc *event_desc;
u16 dev_id, dev_index; int err;
/** * ti_sci_inta_alloc_irq() - Allocate an irq within INTA domain * @domain: irq_domain pointer corresponding to INTA * @hwirq: hwirq of the input event * * Note: Allocation happens in the following manner: * - Find a free bit available in any of the vints available in the list. * - If not found, allocate a vint from the vint pool * - Attach the free bit to input hwirq. * Return event_desc if all went ok else appropriate error value.
*/ staticstruct ti_sci_inta_event_desc *ti_sci_inta_alloc_irq(struct irq_domain *domain,
u32 hwirq)
{ struct ti_sci_inta_irq_domain *inta = domain->host_data; struct ti_sci_inta_vint_desc *vint_desc = NULL; struct ti_sci_inta_event_desc *event_desc;
u16 free_bit;
/** * ti_sci_inta_free_parent_irq() - Free a parent irq to INTA * @inta: Pointer to inta domain. * @vint_desc: Pointer to vint_desc that needs to be freed.
*/ staticvoid ti_sci_inta_free_parent_irq(struct ti_sci_inta_irq_domain *inta, struct ti_sci_inta_vint_desc *vint_desc)
{ if (find_first_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT) == MAX_EVENTS_PER_VINT) {
list_del(&vint_desc->list);
ti_sci_release_resource(inta->vint, vint_desc->vint_id);
irq_dispose_mapping(vint_desc->parent_virq);
kfree(vint_desc);
}
}
/** * ti_sci_inta_free_irq() - Free an IRQ within INTA domain * @event_desc: Pointer to event_desc that needs to be freed. * @hwirq: Hwirq number within INTA domain that needs to be freed
*/ staticvoid ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
u32 hwirq)
{ struct ti_sci_inta_vint_desc *vint_desc; struct ti_sci_inta_irq_domain *inta;
u16 dev_id;
/** * ti_sci_inta_request_resources() - Allocate resources for input irq * @data: Pointer to corresponding irq_data * * Note: This is the core api where the actual allocation happens for input * hwirq. This allocation involves creating a parent irq for vint. * If this is done in irq_domain_ops.alloc() then a deadlock is reached * for allocation. So this allocation is being done in request_resources() * * Return: 0 if all went well else corresponding error.
*/ staticint ti_sci_inta_request_resources(struct irq_data *data)
{ struct ti_sci_inta_event_desc *event_desc;
event_desc = ti_sci_inta_alloc_irq(data->domain, data->hwirq); if (IS_ERR(event_desc)) return PTR_ERR(event_desc);
data->chip_data = event_desc;
return 0;
}
/** * ti_sci_inta_release_resources - Release resources for input irq * @data: Pointer to corresponding irq_data * * Note: Corresponding to request_resources(), all the unmapping and deletion * of parent vint irqs happens in this api.
*/ staticvoid ti_sci_inta_release_resources(struct irq_data *data)
{ struct ti_sci_inta_event_desc *event_desc;
/** * ti_sci_inta_manage_event() - Control the event based on the offset * @data: Pointer to corresponding irq_data * @offset: register offset using which event is controlled.
*/ staticvoid ti_sci_inta_manage_event(struct irq_data *data, u32 offset)
{ struct ti_sci_inta_event_desc *event_desc; struct ti_sci_inta_vint_desc *vint_desc; struct ti_sci_inta_irq_domain *inta;
/** * ti_sci_inta_ack_irq() - Ack an event * @data: Pointer to corresponding irq_data
*/ staticvoid ti_sci_inta_ack_irq(struct irq_data *data)
{ /* * Do not clear the event if hardware is capable of sending * a down event.
*/ if (irqd_get_trigger_type(data) != IRQF_TRIGGER_HIGH)
ti_sci_inta_manage_event(data, VINT_STATUS_OFFSET);
}
/** * ti_sci_inta_set_type() - Update the trigger type of the irq. * @data: Pointer to corresponding irq_data * @type: Trigger type as specified by user * * Note: This updates the handle_irq callback for level msi. * * Return 0 if all went well else appropriate error.
*/ staticint ti_sci_inta_set_type(struct irq_data *data, unsignedint type)
{ /* * .alloc default sets handle_edge_irq. But if the user specifies * that IRQ is level MSI, then update the handle to handle_level_irq
*/ switch (type & IRQ_TYPE_SENSE_MASK) { case IRQF_TRIGGER_HIGH:
irq_set_handler_locked(data, handle_level_irq); return 0; case IRQF_TRIGGER_RISING: return 0; default: return -EINVAL;
}
}
/** * ti_sci_inta_irq_domain_free() - Free an IRQ from the IRQ domain * @domain: Domain to which the irqs belong * @virq: base linux virtual IRQ to be freed. * @nr_irqs: Number of continuous irqs to be freed
*/ staticvoid ti_sci_inta_irq_domain_free(struct irq_domain *domain, unsignedint virq, unsignedint nr_irqs)
{ struct irq_data *data = irq_domain_get_irq_data(domain, virq);
irq_domain_reset_irq_data(data);
}
/** * ti_sci_inta_irq_domain_alloc() - Allocate Interrupt aggregator IRQs * @domain: Point to the interrupt aggregator IRQ domain * @virq: Corresponding Linux virtual IRQ number * @nr_irqs: Continuous irqs to be allocated * @data: Pointer to firmware specifier * * No actual allocation happens here. * * Return 0 if all went well else appropriate error value.
*/ staticint ti_sci_inta_irq_domain_alloc(struct irq_domain *domain, unsignedint virq, unsignedint nr_irqs, void *data)
{
msi_alloc_info_t *arg = data;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.