1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-10-24 GuEe-GUI first version
9 */
10
11 #include <drivers/pci_msi.h>
12
13 #define DBG_TAG "pci.msi.irq"
14 #define DBG_LVL DBG_INFO
15 #include <rtdbg.h>
16
17 static RT_DEFINE_SPINLOCK(msi_irq_map_lock);
18 static RT_BITMAP_DECLARE(msi_irq_map, MAX_HANDLERS) = {};
19
rt_pci_msi_setup_irqs(struct rt_pci_device * pdev,int nvec,int type)20 rt_err_t rt_pci_msi_setup_irqs(struct rt_pci_device *pdev, int nvec, int type)
21 {
22 int irq, index = 0, irq_nr = 0;
23 rt_err_t err = RT_EOK;
24 struct rt_pic_irq *pirq;
25 struct rt_pic *msi_pic;
26 struct rt_pci_msi_desc *desc;
27
28 if (!pdev)
29 {
30 return -RT_EINVAL;
31 }
32
33 msi_pic = pdev->msi_pic;
34
35 if (type == PCIY_MSI)
36 {
37 int last_irq = -1, irq_idx;
38 rt_size_t irq_nr;
39
40 desc = rt_pci_msi_first_desc(pdev);
41 irq_nr = 1 << desc->msi.cap.multi_msg_use;
42
43 rt_hw_spin_lock(&msi_irq_map_lock.lock);
44
45 _retry:
46 for (int i = 0; i < irq_nr; ++i)
47 {
48 if ((irq = msi_pic->ops->irq_alloc_msi(msi_pic, desc)) < 0)
49 {
50 err = irq;
51
52 LOG_E("Setup %s[%d] IRQ error = %s", "MSI", i, rt_strerror(err));
53
54 break;
55 }
56
57 if (last_irq >= 0 && last_irq + 1 != irq)
58 {
59 for (int idx = 0; idx < i; ++i, --last_irq)
60 {
61 rt_bitmap_set_bit(msi_irq_map, last_irq);
62 }
63
64 last_irq = irq;
65 goto _retry;
66 }
67
68 last_irq = irq;
69 }
70
71 if (!err)
72 {
73 /* Get the first irq */
74 desc->irq = irq - (irq_nr - 1);
75 }
76
77 rt_bitmap_for_each_set_bit(msi_irq_map, irq_idx, MAX_HANDLERS)
78 {
79 msi_pic->ops->irq_free_msi(msi_pic, irq_idx);
80
81 /* Free bit so the next user doesn't need to bzero */
82 rt_bitmap_clear_bit(msi_irq_map, irq_idx);
83 }
84
85 rt_hw_spin_unlock(&msi_irq_map_lock.lock);
86
87 if (!err)
88 {
89 for (int idx = 0; idx < nvec; ++idx)
90 {
91 pirq = rt_pic_find_pirq(msi_pic, irq + idx);
92 pirq->msi_desc = desc;
93
94 msi_pic->ops->irq_compose_msi_msg(pirq, &desc->msg);
95
96 rt_pci_msi_write_msg(desc, &desc->msg);
97 }
98 }
99 }
100 else if (type == PCIY_MSIX)
101 {
102 rt_pci_msi_for_each_desc(pdev, desc)
103 {
104 if ((irq = msi_pic->ops->irq_alloc_msi(msi_pic, desc)) < 0)
105 {
106 err = irq;
107
108 LOG_E("Setup %s[%d] IRQ error = %s", "MSI-X",
109 desc->msix.index, rt_strerror(err));
110
111 break;
112 }
113
114 desc->irq = irq;
115 pirq = rt_pic_find_pirq(msi_pic, irq);
116 pirq->msi_desc = desc;
117
118 msi_pic->ops->irq_compose_msi_msg(pirq, &desc->msg);
119
120 rt_pci_msi_write_msg(desc, &desc->msg);
121
122 ++irq_nr;
123 }
124
125 if (err)
126 {
127 rt_pci_msi_for_each_desc(pdev, desc)
128 {
129 if (index >= irq_nr)
130 {
131 break;
132 }
133
134 msi_pic->ops->irq_free_msi(msi_pic, desc->irq);
135
136 ++index;
137 }
138 }
139 }
140 else
141 {
142 err = -RT_EINVAL;
143 }
144
145 return err;
146 }
147