From: David Vrabel <david.vrabel@citrix.com>
To: xen-devel@lists.xen.org
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>,
Wei Liu <wei.liu2@citrix.com>,
David Vrabel <david.vrabel@citrix.com>,
Malcolm Crossley <malcolm.crossley@citrix.com>
Subject: [PATCH 10/12] xen/events: Refactor evtchn_to_irq array to be dynamically allocated
Date: Fri, 9 Aug 2013 19:15:19 +0100 [thread overview]
Message-ID: <1376072121-17786-11-git-send-email-david.vrabel@citrix.com> (raw)
In-Reply-To: <1376072121-17786-1-git-send-email-david.vrabel@citrix.com>
From: Malcolm Crossley <malcolm.crossley@citrix.com>
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
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@citrix.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
---
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 b2746f1..55d33d1 100644
--- a/drivers/xen/events/events.c
+++ b/drivers/xen/events/events.c
@@ -76,12 +76,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)
@@ -91,6 +95,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 */
+ 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)
{
@@ -101,7 +160,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)
{
@@ -112,7 +171,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);
@@ -120,7 +180,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);
@@ -129,7 +189,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);
@@ -143,8 +203,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);
@@ -156,9 +216,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)
{
@@ -185,7 +245,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);
@@ -231,7 +291,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)
@@ -257,7 +317,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);
@@ -452,7 +512,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;
bind_evtchn_to_cpu(evtchn, 0);
info->evtchn = evtchn;
@@ -473,7 +535,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);
@@ -487,7 +549,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;
}
@@ -550,7 +612,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);
@@ -754,9 +816,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();
@@ -846,7 +911,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);
@@ -926,8 +991,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);
@@ -1016,7 +1082,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)
@@ -1041,12 +1107,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;
@@ -1070,7 +1136,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);
@@ -1147,7 +1213,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);
@@ -1422,15 +1488,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);
@@ -1527,14 +1592,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 a449b69..850a0ed 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)));
@@ -205,7 +210,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);
@@ -299,7 +304,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))
@@ -315,6 +320,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
next prev parent reply other threads:[~2013-08-09 18:15 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-09 18:15 [RFC PATCHv2 00/12] Linux: FIFO-based event channel ABI David Vrabel
2013-08-09 18:15 ` [PATCH 01/12] xen/events: refactor retrigger_dynirq() and resend_irq_on_evtchn() David Vrabel
2013-08-16 17:46 ` Wei Liu
2013-09-05 17:28 ` David Vrabel
2013-08-09 18:15 ` [PATCH 02/12] xen/events: remove unnecessary init_evtchn_cpu_bindings() David Vrabel
2013-08-09 18:15 ` [PATCH 03/12] xen/events: introduce test_and_set_mask David Vrabel
2013-08-09 18:15 ` [PATCH 04/12] xen/events: replace raw bit ops with functions David Vrabel
2013-08-09 18:15 ` [PATCH 05/12] xen/events: move drivers/xen/events.c into drivers/xen/events/ David Vrabel
2013-08-09 18:15 ` [PATCH 06/12] xen/events: move 2-level specific code into its own file David Vrabel
2013-08-09 18:15 ` [PATCH 07/12] xen/events: add struct evtchn_ops for the low-level port operations David Vrabel
2013-08-16 17:47 ` Wei Liu
2013-08-19 10:39 ` David Vrabel
2013-08-19 10:52 ` Wei Liu
2013-08-09 18:15 ` [PATCH 08/12] xen/events: allow setup of irq_info to fail David Vrabel
2013-08-09 18:15 ` [PATCH 09/12] xen/events: add a evtchn_op for port setup David Vrabel
2013-08-09 18:15 ` David Vrabel [this message]
2013-08-09 18:15 ` [PATCH 11/12] xen/events: Add the hypervisor interface for the FIFO-based event channels David Vrabel
2013-08-09 18:15 ` [PATCH 12/12] xen/events: use the FIFO-based ABI if available David Vrabel
2013-08-16 17:47 ` Wei Liu
2013-08-19 11:55 ` David Vrabel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1376072121-17786-11-git-send-email-david.vrabel@citrix.com \
--to=david.vrabel@citrix.com \
--cc=boris.ostrovsky@oracle.com \
--cc=malcolm.crossley@citrix.com \
--cc=wei.liu2@citrix.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).