GNU Linux-libre 4.14.259-gnu1
[releases.git] / drivers / net / ethernet / aquantia / atlantic / aq_pci_func.c
1 /*
2  * aQuantia Corporation Network Driver
3  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  */
9
10 /* File aq_pci_func.c: Definition of PCI functions. */
11
12 #include "aq_pci_func.h"
13 #include "aq_nic.h"
14 #include "aq_vec.h"
15 #include "aq_hw.h"
16 #include <linux/interrupt.h>
17
18 struct aq_pci_func_s {
19         struct pci_dev *pdev;
20         struct aq_nic_s *port[AQ_CFG_PCI_FUNC_PORTS];
21         void __iomem *mmio;
22         void *aq_vec[AQ_CFG_PCI_FUNC_MSIX_IRQS];
23         resource_size_t mmio_pa;
24         unsigned int msix_entry_mask;
25         unsigned int ports;
26         bool is_pci_enabled;
27         bool is_regions;
28         bool is_pci_using_dac;
29         struct aq_hw_caps_s aq_hw_caps;
30 };
31
32 struct aq_pci_func_s *aq_pci_func_alloc(struct aq_hw_ops *aq_hw_ops,
33                                         struct pci_dev *pdev,
34                                         const struct net_device_ops *ndev_ops,
35                                         const struct ethtool_ops *eth_ops)
36 {
37         struct aq_pci_func_s *self = NULL;
38         int err = 0;
39         unsigned int port = 0U;
40
41         if (!aq_hw_ops) {
42                 err = -EFAULT;
43                 goto err_exit;
44         }
45         self = kzalloc(sizeof(*self), GFP_KERNEL);
46         if (!self) {
47                 err = -ENOMEM;
48                 goto err_exit;
49         }
50
51         pci_set_drvdata(pdev, self);
52         self->pdev = pdev;
53
54         err = aq_hw_ops->get_hw_caps(NULL, &self->aq_hw_caps, pdev->device,
55                                      pdev->subsystem_device);
56         if (err < 0)
57                 goto err_exit;
58
59         self->ports = self->aq_hw_caps.ports;
60
61         for (port = 0; port < self->ports; ++port) {
62                 struct aq_nic_s *aq_nic = aq_nic_alloc_cold(ndev_ops, eth_ops,
63                                                             pdev, self,
64                                                             port, aq_hw_ops);
65
66                 if (!aq_nic) {
67                         err = -ENOMEM;
68                         goto err_exit;
69                 }
70                 self->port[port] = aq_nic;
71         }
72
73 err_exit:
74         if (err < 0) {
75                 if (self)
76                         aq_pci_func_free(self);
77                 self = NULL;
78         }
79
80         (void)err;
81         return self;
82 }
83
84 int aq_pci_func_init(struct aq_pci_func_s *self)
85 {
86         int err = 0;
87         unsigned int bar = 0U;
88         unsigned int port = 0U;
89         unsigned int numvecs = 0U;
90
91         err = pci_enable_device(self->pdev);
92         if (err < 0)
93                 goto err_exit;
94
95         self->is_pci_enabled = true;
96
97         err = pci_set_dma_mask(self->pdev, DMA_BIT_MASK(64));
98         if (!err) {
99                 err = pci_set_consistent_dma_mask(self->pdev, DMA_BIT_MASK(64));
100                 self->is_pci_using_dac = 1;
101         }
102         if (err) {
103                 err = pci_set_dma_mask(self->pdev, DMA_BIT_MASK(32));
104                 if (!err)
105                         err = pci_set_consistent_dma_mask(self->pdev,
106                                                           DMA_BIT_MASK(32));
107                 self->is_pci_using_dac = 0;
108         }
109         if (err != 0) {
110                 err = -ENOSR;
111                 goto err_exit;
112         }
113
114         err = pci_request_regions(self->pdev, AQ_CFG_DRV_NAME "_mmio");
115         if (err < 0)
116                 goto err_exit;
117
118         self->is_regions = true;
119
120         pci_set_master(self->pdev);
121
122         for (bar = 0; bar < 4; ++bar) {
123                 if (IORESOURCE_MEM & pci_resource_flags(self->pdev, bar)) {
124                         resource_size_t reg_sz;
125
126                         self->mmio_pa = pci_resource_start(self->pdev, bar);
127                         if (self->mmio_pa == 0U) {
128                                 err = -EIO;
129                                 goto err_exit;
130                         }
131
132                         reg_sz = pci_resource_len(self->pdev, bar);
133                         if ((reg_sz <= 24 /*ATL_REGS_SIZE*/)) {
134                                 err = -EIO;
135                                 goto err_exit;
136                         }
137
138                         self->mmio = ioremap_nocache(self->mmio_pa, reg_sz);
139                         if (!self->mmio) {
140                                 err = -EIO;
141                                 goto err_exit;
142                         }
143                         break;
144                 }
145         }
146
147         numvecs = min((u8)AQ_CFG_VECS_DEF, self->aq_hw_caps.msix_irqs);
148         numvecs = min(numvecs, num_online_cpus());
149
150         /* enable interrupts */
151 #if !AQ_CFG_FORCE_LEGACY_INT
152         err = pci_alloc_irq_vectors(self->pdev, numvecs, numvecs, PCI_IRQ_MSIX);
153
154         if (err < 0) {
155                 err = pci_alloc_irq_vectors(self->pdev, 1, 1,
156                                 PCI_IRQ_MSI | PCI_IRQ_LEGACY);
157                 if (err < 0)
158                         goto err_exit;
159         }
160 #endif /* AQ_CFG_FORCE_LEGACY_INT */
161
162         /* net device init */
163         for (port = 0; port < self->ports; ++port) {
164                 if (!self->port[port])
165                         continue;
166
167                 err = aq_nic_cfg_start(self->port[port]);
168                 if (err < 0)
169                         goto err_exit;
170
171                 err = aq_nic_ndev_init(self->port[port]);
172                 if (err < 0)
173                         goto err_exit;
174
175                 err = aq_nic_ndev_register(self->port[port]);
176                 if (err < 0)
177                         goto err_exit;
178         }
179
180 err_exit:
181         if (err < 0)
182                 aq_pci_func_deinit(self);
183         return err;
184 }
185
186 int aq_pci_func_alloc_irq(struct aq_pci_func_s *self, unsigned int i,
187                           char *name, void *aq_vec, cpumask_t *affinity_mask)
188 {
189         struct pci_dev *pdev = self->pdev;
190         int err = 0;
191
192         if (pdev->msix_enabled || pdev->msi_enabled)
193                 err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr, 0,
194                                   name, aq_vec);
195         else
196                 err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr_legacy,
197                                   IRQF_SHARED, name, aq_vec);
198
199         if (err >= 0) {
200                 self->msix_entry_mask |= (1 << i);
201                 self->aq_vec[i] = aq_vec;
202
203                 if (pdev->msix_enabled)
204                         irq_set_affinity_hint(pci_irq_vector(pdev, i),
205                                               affinity_mask);
206         }
207
208         return err;
209 }
210
211 void aq_pci_func_free_irqs(struct aq_pci_func_s *self)
212 {
213         struct pci_dev *pdev = self->pdev;
214         unsigned int i = 0U;
215
216         for (i = 32U; i--;) {
217                 if (!((1U << i) & self->msix_entry_mask))
218                         continue;
219
220                 if (pdev->msix_enabled)
221                         irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL);
222                 free_irq(pci_irq_vector(pdev, i), self->aq_vec[i]);
223                 self->msix_entry_mask &= ~(1U << i);
224         }
225 }
226
227 void __iomem *aq_pci_func_get_mmio(struct aq_pci_func_s *self)
228 {
229         return self->mmio;
230 }
231
232 unsigned int aq_pci_func_get_irq_type(struct aq_pci_func_s *self)
233 {
234         if (self->pdev->msix_enabled)
235                 return AQ_HW_IRQ_MSIX;
236         if (self->pdev->msi_enabled)
237                 return AQ_HW_IRQ_MSIX;
238         return AQ_HW_IRQ_LEGACY;
239 }
240
241 void aq_pci_func_deinit(struct aq_pci_func_s *self)
242 {
243         if (!self)
244                 goto err_exit;
245
246         aq_pci_func_free_irqs(self);
247         pci_free_irq_vectors(self->pdev);
248
249         if (self->is_regions)
250                 pci_release_regions(self->pdev);
251
252         if (self->is_pci_enabled)
253                 pci_disable_device(self->pdev);
254
255 err_exit:;
256 }
257
258 void aq_pci_func_free(struct aq_pci_func_s *self)
259 {
260         unsigned int port = 0U;
261
262         if (!self)
263                 goto err_exit;
264
265         for (port = 0; port < self->ports; ++port) {
266                 if (!self->port[port])
267                         continue;
268
269                 aq_nic_ndev_free(self->port[port]);
270         }
271
272         if (self->mmio)
273                 iounmap(self->mmio);
274
275         kfree(self);
276
277 err_exit:;
278 }
279
280 int aq_pci_func_change_pm_state(struct aq_pci_func_s *self,
281                                 pm_message_t *pm_msg)
282 {
283         int err = 0;
284         unsigned int port = 0U;
285
286         if (!self) {
287                 err = -EFAULT;
288                 goto err_exit;
289         }
290         for (port = 0; port < self->ports; ++port) {
291                 if (!self->port[port])
292                         continue;
293
294                 (void)aq_nic_change_pm_state(self->port[port], pm_msg);
295         }
296
297 err_exit:
298         return err;
299 }