Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/platform-msi.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* MSI framework for platform devices
4
*
5
* Copyright (C) 2015 ARM Limited, All Rights Reserved.
6
* Author: Marc Zyngier <[email protected]>
7
* Copyright (C) 2022 Linutronix GmbH
8
*/
9
10
#include <linux/device.h>
11
#include <linux/irqdomain.h>
12
#include <linux/msi.h>
13
14
/*
15
* This indirection can go when platform_device_msi_init_and_alloc_irqs()
16
* is switched to a proper irq_chip::irq_write_msi_msg() callback. Keep it
17
* simple for now.
18
*/
19
static void platform_msi_write_msi_msg(struct irq_data *d, struct msi_msg *msg)
20
{
21
irq_write_msi_msg_t cb = d->chip_data;
22
23
cb(irq_data_get_msi_desc(d), msg);
24
}
25
26
static void platform_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
27
{
28
arg->desc = desc;
29
arg->hwirq = desc->msi_index;
30
}
31
32
static const struct msi_domain_template platform_msi_template = {
33
.chip = {
34
.name = "pMSI",
35
.irq_mask = irq_chip_mask_parent,
36
.irq_unmask = irq_chip_unmask_parent,
37
.irq_write_msi_msg = platform_msi_write_msi_msg,
38
/* The rest is filled in by the platform MSI parent */
39
},
40
41
.ops = {
42
.set_desc = platform_msi_set_desc,
43
},
44
45
.info = {
46
.bus_token = DOMAIN_BUS_DEVICE_MSI,
47
},
48
};
49
50
/**
51
* platform_device_msi_init_and_alloc_irqs - Initialize platform device MSI
52
* and allocate interrupts for @dev
53
* @dev: The device for which to allocate interrupts
54
* @nvec: The number of interrupts to allocate
55
* @write_msi_msg: Callback to write an interrupt message for @dev
56
*
57
* Returns:
58
* Zero for success, or an error code in case of failure
59
*
60
* This creates a MSI domain on @dev which has @dev->msi.domain as
61
* parent. The parent domain sets up the new domain. The domain has
62
* a fixed size of @nvec. The domain is managed by devres and will
63
* be removed when the device is removed.
64
*
65
* Note: For migration purposes this falls back to the original platform_msi code
66
* up to the point where all platforms have been converted to the MSI
67
* parent model.
68
*/
69
int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec,
70
irq_write_msi_msg_t write_msi_msg)
71
{
72
struct irq_domain *domain = dev->msi.domain;
73
74
if (!domain || !write_msi_msg)
75
return -EINVAL;
76
77
/*
78
* @write_msi_msg is stored in the resulting msi_domain_info::data.
79
* The underlying domain creation mechanism will assign that
80
* callback to the resulting irq chip.
81
*/
82
if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN,
83
&platform_msi_template,
84
nvec, NULL, write_msi_msg))
85
return -ENODEV;
86
87
return msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1);
88
}
89
EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);
90
91
/**
92
* platform_device_msi_free_irqs_all - Free all interrupts for @dev
93
* @dev: The device for which to free interrupts
94
*/
95
void platform_device_msi_free_irqs_all(struct device *dev)
96
{
97
msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
98
msi_remove_device_irq_domain(dev, MSI_DEFAULT_DOMAIN);
99
}
100
EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all);
101
102