1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2017 IBM Corp.
3 #include <linux/interrupt.h>
4 #include <asm/pnv-ocxl.h>
5 #include "ocxl_internal.h"
14 irqreturn_t (*handler
)(void *private);
15 void (*free_private
)(void *private);
19 int ocxl_irq_offset_to_id(struct ocxl_context
*ctx
, u64 offset
)
21 return (offset
- ctx
->afu
->irq_base_offset
) >> PAGE_SHIFT
;
24 u64
ocxl_irq_id_to_offset(struct ocxl_context
*ctx
, int irq_id
)
26 return ctx
->afu
->irq_base_offset
+ (irq_id
<< PAGE_SHIFT
);
29 int ocxl_irq_set_handler(struct ocxl_context
*ctx
, int irq_id
,
30 irqreturn_t (*handler
)(void *private),
31 void (*free_private
)(void *private),
37 mutex_lock(&ctx
->irq_lock
);
38 irq
= idr_find(&ctx
->irq_idr
, irq_id
);
44 irq
->handler
= handler
;
45 irq
->private = private;
46 irq
->free_private
= free_private
;
49 // Fall through to unlock
52 mutex_unlock(&ctx
->irq_lock
);
55 EXPORT_SYMBOL_GPL(ocxl_irq_set_handler
);
57 static irqreturn_t
afu_irq_handler(int virq
, void *data
)
59 struct afu_irq
*irq
= (struct afu_irq
*) data
;
61 trace_ocxl_afu_irq_receive(virq
);
64 return irq
->handler(irq
->private);
66 return IRQ_HANDLED
; // Just drop it on the ground
69 static int setup_afu_irq(struct ocxl_context
*ctx
, struct afu_irq
*irq
)
73 irq
->virq
= irq_create_mapping(NULL
, irq
->hw_irq
);
75 pr_err("irq_create_mapping failed\n");
78 pr_debug("hw_irq %d mapped to virq %u\n", irq
->hw_irq
, irq
->virq
);
80 irq
->name
= kasprintf(GFP_KERNEL
, "ocxl-afu-%u", irq
->virq
);
82 irq_dispose_mapping(irq
->virq
);
86 rc
= request_irq(irq
->virq
, afu_irq_handler
, 0, irq
->name
, irq
);
90 irq_dispose_mapping(irq
->virq
);
91 pr_err("request_irq failed: %d\n", rc
);
97 static void release_afu_irq(struct afu_irq
*irq
)
99 free_irq(irq
->virq
, irq
);
100 irq_dispose_mapping(irq
->virq
);
104 int ocxl_afu_irq_alloc(struct ocxl_context
*ctx
, int *irq_id
)
109 irq
= kzalloc(sizeof(struct afu_irq
), GFP_KERNEL
);
114 * We limit the number of afu irqs per context and per link to
115 * avoid a single process or user depleting the pool of IPIs
118 mutex_lock(&ctx
->irq_lock
);
120 irq
->id
= idr_alloc(&ctx
->irq_idr
, irq
, 0, MAX_IRQ_PER_CONTEXT
,
127 rc
= ocxl_link_irq_alloc(ctx
->afu
->fn
->link
, &irq
->hw_irq
,
132 rc
= setup_afu_irq(ctx
, irq
);
136 trace_ocxl_afu_irq_alloc(ctx
->pasid
, irq
->id
, irq
->virq
, irq
->hw_irq
);
137 mutex_unlock(&ctx
->irq_lock
);
144 ocxl_link_free_irq(ctx
->afu
->fn
->link
, irq
->hw_irq
);
146 idr_remove(&ctx
->irq_idr
, irq
->id
);
148 mutex_unlock(&ctx
->irq_lock
);
152 EXPORT_SYMBOL_GPL(ocxl_afu_irq_alloc
);
154 static void afu_irq_free(struct afu_irq
*irq
, struct ocxl_context
*ctx
)
156 trace_ocxl_afu_irq_free(ctx
->pasid
, irq
->id
);
158 unmap_mapping_range(ctx
->mapping
,
159 ocxl_irq_id_to_offset(ctx
, irq
->id
),
161 release_afu_irq(irq
);
162 if (irq
->free_private
)
163 irq
->free_private(irq
->private);
164 ocxl_link_free_irq(ctx
->afu
->fn
->link
, irq
->hw_irq
);
168 int ocxl_afu_irq_free(struct ocxl_context
*ctx
, int irq_id
)
172 mutex_lock(&ctx
->irq_lock
);
174 irq
= idr_find(&ctx
->irq_idr
, irq_id
);
176 mutex_unlock(&ctx
->irq_lock
);
179 idr_remove(&ctx
->irq_idr
, irq
->id
);
180 afu_irq_free(irq
, ctx
);
181 mutex_unlock(&ctx
->irq_lock
);
184 EXPORT_SYMBOL_GPL(ocxl_afu_irq_free
);
186 void ocxl_afu_irq_free_all(struct ocxl_context
*ctx
)
191 mutex_lock(&ctx
->irq_lock
);
192 idr_for_each_entry(&ctx
->irq_idr
, irq
, id
)
193 afu_irq_free(irq
, ctx
);
194 mutex_unlock(&ctx
->irq_lock
);
197 u64
ocxl_afu_irq_get_addr(struct ocxl_context
*ctx
, int irq_id
)
202 mutex_lock(&ctx
->irq_lock
);
203 irq
= idr_find(&ctx
->irq_idr
, irq_id
);
205 addr
= irq
->trigger_page
;
206 mutex_unlock(&ctx
->irq_lock
);
209 EXPORT_SYMBOL_GPL(ocxl_afu_irq_get_addr
);