[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 10/13] xen/events: Refactor evtchn_to_irq array to be dynamically allocated



On Fri, Sep 13, 2013 at 05:59:58PM +0100, David Vrabel wrote:
> From: Malcolm Crossley <malcolm.crossley@xxxxxxxxxx>
> 
> Refactor static array evtchn_to_irq array to be dynamically allocated by
> implementing get and set functions for accesses to the array.
> 
> Two new port ops are added: max_channels (maximum supported number of
> event channels) and nr_channels (number of currently usable event
> channels).  For the N-level ABI, these numbers are both the same as
> the shared data structure is a fixed size. For the FIFO ABI, these
                            ^^ has 

> will be different as the event array is expanded dynamically.
> 
> This allows more than 65000 event channels so an unsigned short is no
> longer sufficient for an event channel port number and unsigned int is
> used instead.
> 
> Signed-off-by: Malcolm Crossley <malcolm.crossley@xxxxxxxxxx>
> Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
> ---
>  drivers/xen/events/events.c          |  129 
> +++++++++++++++++++++++++---------
>  drivers/xen/events/events_internal.h |   18 ++++-
>  drivers/xen/events/n-level.c         |   11 +++-
>  3 files changed, 121 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/xen/events/events.c b/drivers/xen/events/events.c
> index cf1c7ba..8660459 100644
> --- a/drivers/xen/events/events.c
> +++ b/drivers/xen/events/events.c
> @@ -77,12 +77,16 @@ static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 
> ... NR_VIRQS-1] = -1};
>  /* IRQ <-> IPI mapping */
>  static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... 
> XEN_NR_IPIS-1] = -1};
>  
> -int *evtchn_to_irq;
> +int **evtchn_to_irq;
>  #ifdef CONFIG_X86
>  static unsigned long *pirq_eoi_map;
>  #endif
>  static bool (*pirq_needs_eoi)(unsigned irq);
>  
> +#define EVTCHN_ROW(e)  (e / (PAGE_SIZE/sizeof(**evtchn_to_irq)))
> +#define EVTCHN_COL(e)  (e % (PAGE_SIZE/sizeof(**evtchn_to_irq)))
> +#define EVTCHN_PER_ROW (PAGE_SIZE / sizeof(**evtchn_to_irq))
> +
>  /* Xen will never allocate port zero for any purpose. */
>  #define VALID_EVTCHN(chn)    ((chn) != 0)
>  
> @@ -92,6 +96,61 @@ static struct irq_chip xen_pirq_chip;
>  static void enable_dynirq(struct irq_data *data);
>  static void disable_dynirq(struct irq_data *data);
>  
> +static void clear_evtchn_to_irq_row(unsigned row)
> +{
> +     unsigned col;
> +
> +     for (col = 0; col < EVTCHN_PER_ROW; col++)
> +             evtchn_to_irq[row][col] = -1;
> +}
> +
> +static void clear_evtchn_to_irq_all(void)
> +{
> +     unsigned row;
> +
> +     for (row = 0; row < EVTCHN_ROW(xen_evtchn_max_channels()); row++) {
> +             if (evtchn_to_irq[row] == NULL)
> +                     continue;
> +             clear_evtchn_to_irq_row(row);
> +     }
> +} 
> +
> +static int set_evtchn_to_irq(unsigned evtchn, unsigned irq)
> +{
> +     unsigned row;
> +     unsigned col;
> +
> +     if (evtchn >= xen_evtchn_max_channels())
> +             return -EINVAL;
> +
> +     row = EVTCHN_ROW(evtchn);
> +     col = EVTCHN_COL(evtchn);
> +
> +     if (evtchn_to_irq[row] == NULL) {
> +             /* Unallocated irq entries return -1 anyway */
                                           ^^^^^ - are


> +             if (irq == -1)
> +                     return 0;
> +
> +             evtchn_to_irq[row] = (int *)get_zeroed_page(GFP_KERNEL);
> +             if (evtchn_to_irq[row] == NULL)
> +                     return -ENOMEM;
> +
> +             clear_evtchn_to_irq_row(row);
> +     }
> +
> +     evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)] = irq;
> +     return 0;
> +}
> +
> +int get_evtchn_to_irq(unsigned evtchn)
> +{
> +     if (evtchn >= xen_evtchn_max_channels())
> +             return -1;
> +     if (evtchn_to_irq[EVTCHN_ROW(evtchn)] == NULL)
> +             return -1;
> +     return evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)];
> +}
> +
>  /* Get info for IRQ */
>  struct irq_info *info_for_irq(unsigned irq)
>  {
> @@ -102,7 +161,7 @@ struct irq_info *info_for_irq(unsigned irq)
>  static int xen_irq_info_common_setup(struct irq_info *info,
>                                    unsigned irq,
>                                    enum xen_irq_type type,
> -                                  unsigned short evtchn,
> +                                  unsigned evtchn,
>                                    unsigned short cpu)
>  {
>  
> @@ -113,7 +172,8 @@ static int xen_irq_info_common_setup(struct irq_info 
> *info,
>       info->evtchn = evtchn;
>       info->cpu = cpu;
>  
> -     evtchn_to_irq[evtchn] = irq;
> +     if (set_evtchn_to_irq(evtchn, irq))
> +             return -ENOMEM;
>  
>       irq_clear_status_flags(irq, IRQ_NOREQUEST|IRQ_NOAUTOEN);
>  
> @@ -121,7 +181,7 @@ static int xen_irq_info_common_setup(struct irq_info 
> *info,
>  }
>  
>  static int xen_irq_info_evtchn_setup(unsigned irq,
> -                                  unsigned short evtchn)
> +                                  unsigned evtchn)
>  {
>       struct irq_info *info = info_for_irq(irq);
>  
> @@ -130,7 +190,7 @@ static int xen_irq_info_evtchn_setup(unsigned irq,
>  
>  static int xen_irq_info_ipi_setup(unsigned cpu,
>                                 unsigned irq,
> -                               unsigned short evtchn,
> +                               unsigned evtchn,
>                                 enum ipi_vector ipi)
>  {
>       struct irq_info *info = info_for_irq(irq);
> @@ -144,8 +204,8 @@ static int xen_irq_info_ipi_setup(unsigned cpu,
>  
>  static int xen_irq_info_virq_setup(unsigned cpu,
>                                  unsigned irq,
> -                                unsigned short evtchn,
> -                                unsigned short virq)
> +                                unsigned evtchn,
> +                                unsigned virq)
>  {
>       struct irq_info *info = info_for_irq(irq);
>  
> @@ -157,9 +217,9 @@ static int xen_irq_info_virq_setup(unsigned cpu,
>  }
>  
>  static int xen_irq_info_pirq_setup(unsigned irq,
> -                                unsigned short evtchn,
> -                                unsigned short pirq,
> -                                unsigned short gsi,
> +                                unsigned evtchn,
> +                                unsigned pirq,
> +                                unsigned gsi,
>                                  uint16_t domid,
>                                  unsigned char flags)
>  {
> @@ -186,7 +246,7 @@ static unsigned int evtchn_from_irq(unsigned irq)
>  
>  unsigned irq_from_evtchn(unsigned int evtchn)
>  {
> -     return evtchn_to_irq[evtchn];
> +     return get_evtchn_to_irq(evtchn);
>  }
>  EXPORT_SYMBOL_GPL(irq_from_evtchn);
>  
> @@ -232,7 +292,7 @@ unsigned cpu_from_irq(unsigned irq)
>  
>  unsigned int cpu_from_evtchn(unsigned int evtchn)
>  {
> -     int irq = evtchn_to_irq[evtchn];
> +     int irq = get_evtchn_to_irq(evtchn);
>       unsigned ret = 0;
>  
>       if (irq != -1)
> @@ -258,7 +318,7 @@ static bool pirq_needs_eoi_flag(unsigned irq)
>  
>  static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
>  {
> -     int irq = evtchn_to_irq[chn];
> +     int irq = get_evtchn_to_irq(chn);
>       struct irq_info *info = info_for_irq(irq);
>  
>       BUG_ON(irq == -1);
> @@ -453,7 +513,9 @@ static unsigned int __startup_pirq(unsigned int irq)
>  
>       pirq_query_unmask(irq);
>  
> -     evtchn_to_irq[evtchn] = irq;
> +     rc = set_evtchn_to_irq(evtchn, irq);
> +     if (rc != 0)
> +             return 0;

I think you also need to unroll the hypercall you did (EVTCHNOP_bind_pirq).

I think doing EVTCHNOP_close should suffice?


>       bind_evtchn_to_cpu(evtchn, 0);
>       info->evtchn = evtchn;
>  
> @@ -474,7 +536,7 @@ static void shutdown_pirq(struct irq_data *data)
>       struct evtchn_close close;
>       unsigned int irq = data->irq;
>       struct irq_info *info = info_for_irq(irq);
> -     int evtchn = evtchn_from_irq(irq);
> +     int rc, evtchn = evtchn_from_irq(irq);
>  
>       BUG_ON(info->type != IRQT_PIRQ);
>  
> @@ -488,7 +550,7 @@ static void shutdown_pirq(struct irq_data *data)
>               BUG();
>  
>       bind_evtchn_to_cpu(evtchn, 0);
> -     evtchn_to_irq[evtchn] = -1;
> +     rc = set_evtchn_to_irq(evtchn, -1);
>       info->evtchn = 0;
>  }
>  
> @@ -551,7 +613,7 @@ static void __unbind_from_irq(unsigned int irq)
>               /* Closed ports are implicitly re-bound to VCPU0. */
>               bind_evtchn_to_cpu(evtchn, 0);
>  
> -             evtchn_to_irq[evtchn] = -1;
> +             set_evtchn_to_irq(evtchn, -1);
>       }
>  
>       BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND);
> @@ -755,9 +817,12 @@ int bind_evtchn_to_irq(unsigned int evtchn)
>       int irq;
>       int ret;
>  
> +     if (evtchn >= xen_evtchn_max_channels())
> +             return -ENOMEM;
> +
>       mutex_lock(&irq_mapping_update_lock);
>  
> -     irq = evtchn_to_irq[evtchn];
> +     irq = get_evtchn_to_irq(evtchn);
>  
>       if (irq == -1) {
>               irq = xen_allocate_irq_dynamic();
> @@ -847,7 +912,7 @@ static int find_virq(unsigned int virq, unsigned int cpu)
>       int port, rc = -ENOENT;
>  
>       memset(&status, 0, sizeof(status));
> -     for (port = 0; port <= NR_EVENT_CHANNELS; port++) {
> +     for (port = 0; port < xen_evtchn_max_channels(); port++) {
>               status.dom = DOMID_SELF;
>               status.port = port;
>               rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status);
> @@ -927,8 +992,9 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
>       int irq, retval;
>  
>       irq = bind_evtchn_to_irq(evtchn);
> -     if (irq < 0)
> +     if (irq < 0){
>               return irq;
> +     }
>       retval = request_irq(irq, handler, irqflags, devname, dev_id);
>       if (retval != 0) {
>               unbind_from_irq(irq);
> @@ -1017,7 +1083,7 @@ EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
>  
>  int evtchn_make_refcounted(unsigned int evtchn)
>  {
> -     int irq = evtchn_to_irq[evtchn];
> +     int irq = get_evtchn_to_irq(evtchn);
>       struct irq_info *info;
>  
>       if (irq == -1)
> @@ -1042,12 +1108,12 @@ int evtchn_get(unsigned int evtchn)
>       struct irq_info *info;
>       int err = -ENOENT;
>  
> -     if (evtchn >= NR_EVENT_CHANNELS)
> +     if (evtchn >= xen_evtchn_max_channels())
>               return -EINVAL;
>  
>       mutex_lock(&irq_mapping_update_lock);
>  
> -     irq = evtchn_to_irq[evtchn];
> +     irq = get_evtchn_to_irq(evtchn);
>       if (irq == -1)
>               goto done;
>  
> @@ -1071,7 +1137,7 @@ EXPORT_SYMBOL_GPL(evtchn_get);
>  
>  void evtchn_put(unsigned int evtchn)
>  {
> -     int irq = evtchn_to_irq[evtchn];
> +     int irq = get_evtchn_to_irq(evtchn);
>       if (WARN_ON(irq == -1))
>               return;
>       unbind_from_irq(irq);
> @@ -1158,7 +1224,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
>       mutex_lock(&irq_mapping_update_lock);
>  
>       /* After resume the irq<->evtchn mappings are all cleared out */
> -     BUG_ON(evtchn_to_irq[evtchn] != -1);
> +     BUG_ON(get_evtchn_to_irq(evtchn) != -1);
>       /* Expect irq to have been bound before,
>          so there should be a proper type */
>       BUG_ON(info->type == IRQT_UNBOUND);
> @@ -1443,15 +1509,14 @@ void xen_irq_resume(void)
>       struct irq_info *info;
>  
>       /* New event-channel space is not 'live' yet. */
> -     for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
> +     for (evtchn = 0; evtchn < xen_evtchn_nr_channels(); evtchn++)
>               mask_evtchn(evtchn);
>  
>       /* No IRQ <-> event-channel mappings. */
>       list_for_each_entry(info, &xen_irq_list_head, list)
>               info->evtchn = 0; /* zap event-channel binding */
>  
> -     for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
> -             evtchn_to_irq[evtchn] = -1;
> +     clear_evtchn_to_irq_all();
>  
>       for_each_possible_cpu(cpu) {
>               restore_cpu_virqs(cpu);
> @@ -1548,14 +1613,12 @@ void __init xen_init_IRQ(void)
>  
>       xen_evtchn_init_nlevel();
>  
> -     evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
> -                                 GFP_KERNEL);
> +     evtchn_to_irq = kcalloc(EVTCHN_ROW(xen_evtchn_max_channels()),
> +                             sizeof(*evtchn_to_irq), GFP_KERNEL);
>       BUG_ON(!evtchn_to_irq);
> -     for (i = 0; i < NR_EVENT_CHANNELS; i++)
> -             evtchn_to_irq[i] = -1;
>  
>       /* No event channels are 'live' right now. */
> -     for (i = 0; i < NR_EVENT_CHANNELS; i++)
> +     for (i = 0; i < xen_evtchn_nr_channels(); i++)
>               mask_evtchn(i);
>  
>       pirq_needs_eoi = pirq_needs_eoi_flag;
> diff --git a/drivers/xen/events/events_internal.h 
> b/drivers/xen/events/events_internal.h
> index 32cb928..9d8b70c 100644
> --- a/drivers/xen/events/events_internal.h
> +++ b/drivers/xen/events/events_internal.h
> @@ -35,7 +35,7 @@ struct irq_info {
>       int refcnt;
>       enum xen_irq_type type; /* type */
>       unsigned irq;
> -     unsigned short evtchn;  /* event channel */
> +     unsigned int evtchn;    /* event channel */
>       unsigned short cpu;     /* cpu bound */
>  
>       union {
> @@ -55,6 +55,9 @@ struct irq_info {
>  #define PIRQ_SHAREABLE       (1 << 1)
>  
>  struct evtchn_ops {
> +     unsigned (*max_channels)(void);
> +     unsigned (*nr_channels)(void);
> +
>       int (*setup)(struct irq_info *info);
>       void (*bind_to_cpu)(struct irq_info *info, int cpu);
>  
> @@ -70,12 +73,23 @@ struct evtchn_ops {
>  
>  extern const struct evtchn_ops *evtchn_ops;
>  
> -extern int *evtchn_to_irq;
> +extern int **evtchn_to_irq;
> +int get_evtchn_to_irq(unsigned int evtchn);
>  
>  struct irq_info *info_for_irq(unsigned irq);
>  unsigned cpu_from_irq(unsigned irq);
>  unsigned cpu_from_evtchn(unsigned int evtchn);
>  
> +static inline unsigned xen_evtchn_max_channels(void)
> +{
> +     return evtchn_ops->max_channels();
> +}
> +
> +static inline unsigned xen_evtchn_nr_channels(void)
> +{
> +     return evtchn_ops->nr_channels();
> +}
> +
>  static inline int xen_evtchn_port_setup(struct irq_info *info)
>  {
>       if (evtchn_ops->setup)
> diff --git a/drivers/xen/events/n-level.c b/drivers/xen/events/n-level.c
> index 6c0662e..da8d0aa 100644
> --- a/drivers/xen/events/n-level.c
> +++ b/drivers/xen/events/n-level.c
> @@ -39,6 +39,11 @@
>  static DEFINE_PER_CPU(xen_ulong_t [NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD],
>                     cpu_evtchn_mask);
>  
> +static unsigned nlevel_max_channels(void)
> +{
> +     return NR_EVENT_CHANNELS;
> +}
> +
>  static void nlevel_bind_to_cpu(struct irq_info *info, int cpu)
>  {
>       clear_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, info->cpu)));
> @@ -212,7 +217,7 @@ static void nlevel_handle_events(int cpu)
>  
>                       /* Process port. */
>                       port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx;
> -                     irq = evtchn_to_irq[port];
> +                     irq = get_evtchn_to_irq(port);
>  
>                       if (irq != -1) {
>                               desc = irq_to_desc(irq);
> @@ -306,7 +311,7 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
>                       int word_idx = i / BITS_PER_EVTCHN_WORD;
>                       printk("  %d: event %d -> irq %d%s%s%s\n",
>                              cpu_from_evtchn(i), i,
> -                            evtchn_to_irq[i],
> +                            get_evtchn_to_irq(i),
>                              sync_test_bit(word_idx, 
> BM(&v->evtchn_pending_sel))
>                                            ? "" : " l2-clear",
>                              !sync_test_bit(i, BM(sh->evtchn_mask))
> @@ -322,6 +327,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
>  }
>  
>  static const struct evtchn_ops evtchn_ops_nlevel = {
> +     .max_channels      = nlevel_max_channels,
> +     .nr_channels       = nlevel_max_channels,
>       .bind_to_cpu       = nlevel_bind_to_cpu,
>       .clear_pending     = nlevel_clear_pending,
>       .set_pending       = nlevel_set_pending,
> -- 
> 1.7.2.5
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.