]> Git Repo - linux.git/blob - drivers/net/ethernet/meta/fbnic/fbnic_irq.c
x86/kaslr: Expose and use the end of the physical memory address space
[linux.git] / drivers / net / ethernet / meta / fbnic / fbnic_irq.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3
4 #include <linux/pci.h>
5 #include <linux/types.h>
6
7 #include "fbnic.h"
8 #include "fbnic_netdev.h"
9 #include "fbnic_txrx.h"
10
11 static irqreturn_t fbnic_fw_msix_intr(int __always_unused irq, void *data)
12 {
13         struct fbnic_dev *fbd = (struct fbnic_dev *)data;
14
15         fbnic_mbx_poll(fbd);
16
17         fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
18
19         return IRQ_HANDLED;
20 }
21
22 /**
23  * fbnic_fw_enable_mbx - Configure and initialize Firmware Mailbox
24  * @fbd: Pointer to device to initialize
25  *
26  * This function will initialize the firmware mailbox rings, enable the IRQ
27  * and initialize the communication between the Firmware and the host. The
28  * firmware is expected to respond to the initialization by sending an
29  * interrupt essentially notifying the host that it has seen the
30  * initialization and is now synced up.
31  *
32  * Return: non-zero on failure.
33  **/
34 int fbnic_fw_enable_mbx(struct fbnic_dev *fbd)
35 {
36         u32 vector = fbd->fw_msix_vector;
37         int err;
38
39         /* Request the IRQ for FW Mailbox vector. */
40         err = request_threaded_irq(vector, NULL, &fbnic_fw_msix_intr,
41                                    IRQF_ONESHOT, dev_name(fbd->dev), fbd);
42         if (err)
43                 return err;
44
45         /* Initialize mailbox and attempt to poll it into ready state */
46         fbnic_mbx_init(fbd);
47         err = fbnic_mbx_poll_tx_ready(fbd);
48         if (err) {
49                 dev_warn(fbd->dev, "FW mailbox did not enter ready state\n");
50                 free_irq(vector, fbd);
51                 return err;
52         }
53
54         /* Enable interrupts */
55         fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
56
57         return 0;
58 }
59
60 /**
61  * fbnic_fw_disable_mbx - Disable mailbox and place it in standby state
62  * @fbd: Pointer to device to disable
63  *
64  * This function will disable the mailbox interrupt, free any messages still
65  * in the mailbox and place it into a standby state. The firmware is
66  * expected to see the update and assume that the host is in the reset state.
67  **/
68 void fbnic_fw_disable_mbx(struct fbnic_dev *fbd)
69 {
70         /* Disable interrupt and free vector */
71         fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(0), 1u << FBNIC_FW_MSIX_ENTRY);
72
73         /* Free the vector */
74         free_irq(fbd->fw_msix_vector, fbd);
75
76         /* Make sure disabling logs message is sent, must be done here to
77          * avoid risk of completing without a running interrupt.
78          */
79         fbnic_mbx_flush_tx(fbd);
80
81         /* Reset the mailboxes to the initialized state */
82         fbnic_mbx_clean(fbd);
83 }
84
85 static irqreturn_t fbnic_pcs_msix_intr(int __always_unused irq, void *data)
86 {
87         struct fbnic_dev *fbd = data;
88         struct fbnic_net *fbn;
89
90         if (fbd->mac->pcs_get_link_event(fbd) == FBNIC_LINK_EVENT_NONE) {
91                 fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0),
92                            1u << FBNIC_PCS_MSIX_ENTRY);
93                 return IRQ_HANDLED;
94         }
95
96         fbn = netdev_priv(fbd->netdev);
97
98         phylink_pcs_change(&fbn->phylink_pcs, false);
99
100         return IRQ_HANDLED;
101 }
102
103 /**
104  * fbnic_pcs_irq_enable - Configure the MAC to enable it to advertise link
105  * @fbd: Pointer to device to initialize
106  *
107  * This function provides basic bringup for the MAC/PCS IRQ. For now the IRQ
108  * will remain disabled until we start the MAC/PCS/PHY logic via phylink.
109  *
110  * Return: non-zero on failure.
111  **/
112 int fbnic_pcs_irq_enable(struct fbnic_dev *fbd)
113 {
114         u32 vector = fbd->pcs_msix_vector;
115         int err;
116
117         /* Request the IRQ for MAC link vector.
118          * Map MAC cause to it, and unmask it
119          */
120         err = request_irq(vector, &fbnic_pcs_msix_intr, 0,
121                           fbd->netdev->name, fbd);
122         if (err)
123                 return err;
124
125         fbnic_wr32(fbd, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX),
126                    FBNIC_PCS_MSIX_ENTRY | FBNIC_INTR_MSIX_CTRL_ENABLE);
127
128         return 0;
129 }
130
131 /**
132  * fbnic_pcs_irq_disable - Teardown the MAC IRQ to prepare for stopping
133  * @fbd: Pointer to device that is stopping
134  *
135  * This function undoes the work done in fbnic_pcs_irq_enable and prepares
136  * the device to no longer receive traffic on the host interface.
137  **/
138 void fbnic_pcs_irq_disable(struct fbnic_dev *fbd)
139 {
140         /* Disable interrupt */
141         fbnic_wr32(fbd, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX),
142                    FBNIC_PCS_MSIX_ENTRY);
143         fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(0), 1u << FBNIC_PCS_MSIX_ENTRY);
144
145         /* Free the vector */
146         free_irq(fbd->pcs_msix_vector, fbd);
147 }
148
149 int fbnic_request_irq(struct fbnic_dev *fbd, int nr, irq_handler_t handler,
150                       unsigned long flags, const char *name, void *data)
151 {
152         struct pci_dev *pdev = to_pci_dev(fbd->dev);
153         int irq = pci_irq_vector(pdev, nr);
154
155         if (irq < 0)
156                 return irq;
157
158         return request_irq(irq, handler, flags, name, data);
159 }
160
161 void fbnic_free_irq(struct fbnic_dev *fbd, int nr, void *data)
162 {
163         struct pci_dev *pdev = to_pci_dev(fbd->dev);
164         int irq = pci_irq_vector(pdev, nr);
165
166         if (irq < 0)
167                 return;
168
169         free_irq(irq, data);
170 }
171
172 void fbnic_free_irqs(struct fbnic_dev *fbd)
173 {
174         struct pci_dev *pdev = to_pci_dev(fbd->dev);
175
176         fbd->pcs_msix_vector = 0;
177         fbd->fw_msix_vector = 0;
178
179         fbd->num_irqs = 0;
180
181         pci_free_irq_vectors(pdev);
182 }
183
184 int fbnic_alloc_irqs(struct fbnic_dev *fbd)
185 {
186         unsigned int wanted_irqs = FBNIC_NON_NAPI_VECTORS;
187         struct pci_dev *pdev = to_pci_dev(fbd->dev);
188         int num_irqs;
189
190         wanted_irqs += min_t(unsigned int, num_online_cpus(), FBNIC_MAX_RXQS);
191         num_irqs = pci_alloc_irq_vectors(pdev, FBNIC_NON_NAPI_VECTORS + 1,
192                                          wanted_irqs, PCI_IRQ_MSIX);
193         if (num_irqs < 0) {
194                 dev_err(fbd->dev, "Failed to allocate MSI-X entries\n");
195                 return num_irqs;
196         }
197
198         if (num_irqs < wanted_irqs)
199                 dev_warn(fbd->dev, "Allocated %d IRQs, expected %d\n",
200                          num_irqs, wanted_irqs);
201
202         fbd->num_irqs = num_irqs;
203
204         fbd->pcs_msix_vector = pci_irq_vector(pdev, FBNIC_PCS_MSIX_ENTRY);
205         fbd->fw_msix_vector = pci_irq_vector(pdev, FBNIC_FW_MSIX_ENTRY);
206
207         return 0;
208 }
This page took 0.043478 seconds and 4 git commands to generate.