1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-02-25 GuEe-GUI the first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13
14 #define NVME_REG_BAR 0
15
16 struct pci_nvme_quirk
17 {
18 const struct rt_nvme_ops *ops;
19 };
20
21 struct pci_nvme_controller
22 {
23 struct rt_nvme_controller parent;
24 const struct pci_nvme_quirk *quirk;
25
26 rt_bool_t is_msi;
27 struct rt_pci_msix_entry msix_entries[RT_USING_NVME_QUEUE];
28 };
29
30 static const struct rt_nvme_ops pci_nvme_std_ops =
31 {
32 .name = "PCI",
33 };
34
pci_nvme_probe(struct rt_pci_device * pdev)35 static rt_err_t pci_nvme_probe(struct rt_pci_device *pdev)
36 {
37 rt_err_t err;
38 rt_ssize_t msi_nr;
39 struct rt_nvme_controller *nvme;
40 struct pci_nvme_controller *pci_nvme = rt_calloc(1, sizeof(*pci_nvme));
41 const struct pci_nvme_quirk *quirk = pdev->id->data;
42
43 if (!pci_nvme)
44 {
45 return -RT_ENOMEM;
46 }
47
48 pci_nvme->quirk = quirk;
49 nvme = &pci_nvme->parent;
50 nvme->dev = &pdev->parent;
51 nvme->regs = rt_pci_iomap(pdev, NVME_REG_BAR);
52
53 if (!nvme->regs)
54 {
55 err = -RT_EIO;
56 goto _fail;
57 }
58
59 nvme->ops = quirk && quirk->ops ? quirk->ops : &pci_nvme_std_ops;
60
61 if ((msi_nr = rt_pci_msix_vector_count(pdev)) <= 0)
62 {
63 msi_nr = rt_pci_msi_vector_count(pdev);
64 }
65 if (msi_nr > 0)
66 {
67 nvme->irqs_nr = RT_ARRAY_SIZE(pci_nvme->msix_entries);
68 nvme->irqs_nr = rt_min_t(rt_size_t, msi_nr, nvme->irqs_nr);
69 }
70
71 if (nvme->irqs_nr > 0)
72 {
73 rt_pci_msix_entry_index_linear(pci_nvme->msix_entries, nvme->irqs_nr);
74
75 if (rt_pci_msix_enable(pdev, pci_nvme->msix_entries, nvme->irqs_nr) > 0)
76 {
77 pci_nvme->is_msi = RT_TRUE;
78
79 for (int i = 0; i < nvme->irqs_nr; ++i)
80 {
81 nvme->irqs[i] = pci_nvme->msix_entries[i].irq;
82 }
83 }
84 }
85
86 if (!pci_nvme->is_msi)
87 {
88 nvme->irqs_nr = 1;
89 nvme->irqs[0] = pdev->irq;
90 rt_pci_irq_unmask(pdev);
91 }
92
93 rt_pci_set_master(pdev);
94
95 if ((err = rt_nvme_controller_register(nvme)))
96 {
97 goto _disable;
98 }
99
100 pdev->parent.user_data = pci_nvme;
101
102 return RT_EOK;
103
104 _disable:
105 if (pci_nvme->is_msi)
106 {
107 rt_pci_msix_disable(pdev);
108 }
109 else
110 {
111 rt_pci_irq_mask(pdev);
112 }
113 rt_pci_clear_master(pdev);
114 rt_iounmap(nvme->regs);
115
116 _fail:
117 rt_free(pci_nvme);
118
119 return err;
120 }
121
pci_nvme_remove(struct rt_pci_device * pdev)122 static rt_err_t pci_nvme_remove(struct rt_pci_device *pdev)
123 {
124 struct rt_nvme_controller *nvme;
125 struct pci_nvme_controller *pci_nvme = pdev->parent.user_data;
126
127 nvme = &pci_nvme->parent;
128
129 rt_nvme_controller_unregister(nvme);
130
131 if (pci_nvme->is_msi)
132 {
133 rt_pci_msix_disable(pdev);
134 }
135 else
136 {
137 /* INTx is shared, don't mask all */
138 rt_hw_interrupt_umask(pdev->irq);
139 rt_pci_irq_mask(pdev);
140 }
141
142 rt_pci_clear_master(pdev);
143
144 rt_iounmap(nvme->regs);
145 rt_free(pci_nvme);
146
147 return RT_EOK;
148 }
149
pci_nvme_shutdown(struct rt_pci_device * pdev)150 static rt_err_t pci_nvme_shutdown(struct rt_pci_device *pdev)
151 {
152 return pci_nvme_remove(pdev);
153 }
154
155 static const struct rt_pci_device_id pci_nvme_ids[] =
156 {
157 { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0010) },
158 { RT_PCI_DEVICE_CLASS(PCIS_STORAGE_EXPRESS, ~0) },
159 { /* sentinel */ }
160 };
161
162 static struct rt_pci_driver pci_nvme_driver =
163 {
164 .name = "nvme-pci",
165
166 .ids = pci_nvme_ids,
167 .probe = pci_nvme_probe,
168 .remove = pci_nvme_remove,
169 .shutdown = pci_nvme_shutdown,
170 };
171 RT_PCI_DRIVER_EXPORT(pci_nvme_driver);
172