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