Skip to content

Commit d7d8ab8

Browse files
covanambjorn-helgaas
authored andcommitted
PCI: vmd: Switch to msi_create_parent_irq_domain()
Switch to msi_create_parent_irq_domain() from pci_msi_create_irq_domain() which was using legacy MSI domain setup. Signed-off-by: Nam Cao <[email protected]> [mani: reworded commit message] Signed-off-by: Manivannan Sadhasivam <[email protected]> [bhelgaas: rebase on dev_fwnode() conversion, wrap long lines, squash fix from https://lore.kernel.org/r/[email protected]] Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Link: https://patch.msgid.link/de3f1d737831b251e9cd2cbf9e4c732a5bbba13a.1750858083.git.namcao@linutronix.de
1 parent 63984ea commit d7d8ab8

File tree

2 files changed

+91
-80
lines changed

2 files changed

+91
-80
lines changed

drivers/pci/controller/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ config PCI_IXP4XX
156156
config VMD
157157
depends on PCI_MSI && X86_64 && !UML
158158
tristate "Intel Volume Management Device Driver"
159+
select IRQ_MSI_LIB
159160
help
160161
Adds support for the Intel Volume Management Device (VMD). VMD is a
161162
secondary PCI host bridge that allows PCI Express root ports,

drivers/pci/controller/vmd.c

Lines changed: 90 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/device.h>
88
#include <linux/interrupt.h>
99
#include <linux/irq.h>
10+
#include <linux/irqchip/irq-msi-lib.h>
1011
#include <linux/kernel.h>
1112
#include <linux/module.h>
1213
#include <linux/msi.h>
@@ -174,9 +175,6 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
174175
msg->arch_addr_lo.destid_0_7 = index_from_irqs(vmd, irq);
175176
}
176177

177-
/*
178-
* We rely on MSI_FLAG_USE_DEF_CHIP_OPS to set the IRQ mask/unmask ops.
179-
*/
180178
static void vmd_irq_enable(struct irq_data *data)
181179
{
182180
struct vmd_irq *vmdirq = data->chip_data;
@@ -186,16 +184,18 @@ static void vmd_irq_enable(struct irq_data *data)
186184
list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
187185
vmdirq->enabled = true;
188186
}
187+
}
189188

189+
static void vmd_pci_msi_enable(struct irq_data *data)
190+
{
191+
vmd_irq_enable(data->parent_data);
190192
data->chip->irq_unmask(data);
191193
}
192194

193195
static void vmd_irq_disable(struct irq_data *data)
194196
{
195197
struct vmd_irq *vmdirq = data->chip_data;
196198

197-
data->chip->irq_mask(data);
198-
199199
scoped_guard(raw_spinlock_irqsave, &list_lock) {
200200
if (vmdirq->enabled) {
201201
list_del_rcu(&vmdirq->node);
@@ -204,19 +204,17 @@ static void vmd_irq_disable(struct irq_data *data)
204204
}
205205
}
206206

207+
static void vmd_pci_msi_disable(struct irq_data *data)
208+
{
209+
data->chip->irq_mask(data);
210+
vmd_irq_disable(data->parent_data);
211+
}
212+
207213
static struct irq_chip vmd_msi_controller = {
208214
.name = "VMD-MSI",
209-
.irq_enable = vmd_irq_enable,
210-
.irq_disable = vmd_irq_disable,
211215
.irq_compose_msi_msg = vmd_compose_msi_msg,
212216
};
213217

214-
static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
215-
msi_alloc_info_t *arg)
216-
{
217-
return 0;
218-
}
219-
220218
/*
221219
* XXX: We can be even smarter selecting the best IRQ once we solve the
222220
* affinity problem.
@@ -250,100 +248,118 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
250248
return &vmd->irqs[best];
251249
}
252250

253-
static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
254-
unsigned int virq, irq_hw_number_t hwirq,
255-
msi_alloc_info_t *arg)
251+
static void vmd_msi_free(struct irq_domain *domain, unsigned int virq,
252+
unsigned int nr_irqs);
253+
254+
static int vmd_msi_alloc(struct irq_domain *domain, unsigned int virq,
255+
unsigned int nr_irqs, void *arg)
256256
{
257-
struct msi_desc *desc = arg->desc;
258-
struct vmd_dev *vmd = vmd_from_bus(msi_desc_to_pci_dev(desc)->bus);
259-
struct vmd_irq *vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
257+
struct msi_desc *desc = ((msi_alloc_info_t *)arg)->desc;
258+
struct vmd_dev *vmd = domain->host_data;
259+
struct vmd_irq *vmdirq;
260260

261-
if (!vmdirq)
262-
return -ENOMEM;
261+
for (int i = 0; i < nr_irqs; ++i) {
262+
vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
263+
if (!vmdirq) {
264+
vmd_msi_free(domain, virq, i);
265+
return -ENOMEM;
266+
}
263267

264-
INIT_LIST_HEAD(&vmdirq->node);
265-
vmdirq->irq = vmd_next_irq(vmd, desc);
266-
vmdirq->virq = virq;
268+
INIT_LIST_HEAD(&vmdirq->node);
269+
vmdirq->irq = vmd_next_irq(vmd, desc);
270+
vmdirq->virq = virq + i;
271+
272+
irq_domain_set_info(domain, virq + i, vmdirq->irq->virq,
273+
&vmd_msi_controller, vmdirq,
274+
handle_untracked_irq, vmd, NULL);
275+
}
267276

268-
irq_domain_set_info(domain, virq, vmdirq->irq->virq, info->chip, vmdirq,
269-
handle_untracked_irq, vmd, NULL);
270277
return 0;
271278
}
272279

273-
static void vmd_msi_free(struct irq_domain *domain,
274-
struct msi_domain_info *info, unsigned int virq)
280+
static void vmd_msi_free(struct irq_domain *domain, unsigned int virq,
281+
unsigned int nr_irqs)
275282
{
276-
struct vmd_irq *vmdirq = irq_get_chip_data(virq);
283+
struct vmd_irq *vmdirq;
284+
285+
for (int i = 0; i < nr_irqs; ++i) {
286+
vmdirq = irq_get_chip_data(virq + i);
277287

278-
synchronize_srcu(&vmdirq->irq->srcu);
288+
synchronize_srcu(&vmdirq->irq->srcu);
279289

280-
/* XXX: Potential optimization to rebalance */
281-
scoped_guard(raw_spinlock_irq, &list_lock)
282-
vmdirq->irq->count--;
290+
/* XXX: Potential optimization to rebalance */
291+
scoped_guard(raw_spinlock_irq, &list_lock)
292+
vmdirq->irq->count--;
283293

284-
kfree(vmdirq);
294+
kfree(vmdirq);
295+
}
285296
}
286297

287-
static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev,
288-
int nvec, msi_alloc_info_t *arg)
298+
static const struct irq_domain_ops vmd_msi_domain_ops = {
299+
.alloc = vmd_msi_alloc,
300+
.free = vmd_msi_free,
301+
};
302+
303+
static bool vmd_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
304+
struct irq_domain *real_parent,
305+
struct msi_domain_info *info)
289306
{
290-
struct pci_dev *pdev = to_pci_dev(dev);
291-
struct vmd_dev *vmd = vmd_from_bus(pdev->bus);
307+
if (WARN_ON_ONCE(info->bus_token != DOMAIN_BUS_PCI_DEVICE_MSIX))
308+
return false;
292309

293-
if (nvec > vmd->msix_count)
294-
return vmd->msix_count;
310+
if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
311+
return false;
295312

296-
memset(arg, 0, sizeof(*arg));
297-
return 0;
313+
info->chip->irq_enable = vmd_pci_msi_enable;
314+
info->chip->irq_disable = vmd_pci_msi_disable;
315+
return true;
298316
}
299317

300-
static void vmd_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
301-
{
302-
arg->desc = desc;
303-
}
304-
305-
static struct msi_domain_ops vmd_msi_domain_ops = {
306-
.get_hwirq = vmd_get_hwirq,
307-
.msi_init = vmd_msi_init,
308-
.msi_free = vmd_msi_free,
309-
.msi_prepare = vmd_msi_prepare,
310-
.set_desc = vmd_set_desc,
311-
};
318+
#define VMD_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | MSI_FLAG_PCI_MSIX)
319+
#define VMD_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_NO_AFFINITY)
312320

313-
static struct msi_domain_info vmd_msi_domain_info = {
314-
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
315-
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
316-
.ops = &vmd_msi_domain_ops,
317-
.chip = &vmd_msi_controller,
321+
static const struct msi_parent_ops vmd_msi_parent_ops = {
322+
.supported_flags = VMD_MSI_FLAGS_SUPPORTED,
323+
.required_flags = VMD_MSI_FLAGS_REQUIRED,
324+
.bus_select_token = DOMAIN_BUS_VMD_MSI,
325+
.bus_select_mask = MATCH_PCI_MSI,
326+
.prefix = "VMD-",
327+
.init_dev_msi_info = vmd_init_dev_msi_info,
318328
};
319329

320-
static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
321-
{
322-
u16 reg;
323-
324-
pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, &reg);
325-
reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) :
326-
(reg | VMCONFIG_MSI_REMAP);
327-
pci_write_config_word(vmd->dev, PCI_REG_VMCONFIG, reg);
328-
}
329-
330330
static int vmd_create_irq_domain(struct vmd_dev *vmd)
331331
{
332-
struct fwnode_handle *fn;
332+
struct irq_domain_info info = {
333+
.size = vmd->msix_count,
334+
.ops = &vmd_msi_domain_ops,
335+
.host_data = vmd,
336+
};
333337

334-
fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
335-
if (!fn)
338+
info.fwnode = irq_domain_alloc_named_id_fwnode("VMD-MSI",
339+
vmd->sysdata.domain);
340+
if (!info.fwnode)
336341
return -ENODEV;
337342

338-
vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, NULL);
343+
vmd->irq_domain = msi_create_parent_irq_domain(&info,
344+
&vmd_msi_parent_ops);
339345
if (!vmd->irq_domain) {
340-
irq_domain_free_fwnode(fn);
346+
irq_domain_free_fwnode(info.fwnode);
341347
return -ENODEV;
342348
}
343349

344350
return 0;
345351
}
346352

353+
static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
354+
{
355+
u16 reg;
356+
357+
pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, &reg);
358+
reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) :
359+
(reg | VMCONFIG_MSI_REMAP);
360+
pci_write_config_word(vmd->dev, PCI_REG_VMCONFIG, reg);
361+
}
362+
347363
static void vmd_remove_irq_domain(struct vmd_dev *vmd)
348364
{
349365
/*
@@ -874,12 +890,6 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
874890
ret = vmd_create_irq_domain(vmd);
875891
if (ret)
876892
return ret;
877-
878-
/*
879-
* Override the IRQ domain bus token so the domain can be
880-
* distinguished from a regular PCI/MSI domain.
881-
*/
882-
irq_domain_update_bus_token(vmd->irq_domain, DOMAIN_BUS_VMD_MSI);
883893
} else {
884894
vmd_set_msi_remapping(vmd, false);
885895
}

0 commit comments

Comments
 (0)