File Index
Files and directories
Sign in
FILE

fbnic_irq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/meta/fbnic/fbnic_irq.c 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
 11static 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
 22static int __fbnic_fw_enable_mbx(struct fbnic_dev *fbd, int vector)
 23{
 24	int err;
 25
 26	/* Initialize mailbox and attempt to poll it into ready state */
 27	fbnic_mbx_init(fbd);
 28	err = fbnic_mbx_poll_tx_ready(fbd);
 29	if (err) {
 30		dev_warn(fbd->dev, "FW mailbox did not enter ready state\n");
 31		return err;
 32	}
 33
 34	/* Enable interrupt and unmask the vector */
 35	enable_irq(vector);
 36	fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
 37
 38	return 0;
 39}
 40
 41/**
 42 * fbnic_fw_request_mbx - Configure and initialize Firmware Mailbox
 43 * @fbd: Pointer to device to initialize
 44 *
 45 * This function will allocate the IRQ and then reinitialize the mailbox
 46 * starting communication between the host and firmware.
 47 *
 48 * Return: non-zero on failure.
 49 **/
 50int fbnic_fw_request_mbx(struct fbnic_dev *fbd)
 51{
 52	struct pci_dev *pdev = to_pci_dev(fbd->dev);
 53	int vector, err;
 54
 55	WARN_ON(fbd->fw_msix_vector);
 56
 57	vector = pci_irq_vector(pdev, FBNIC_FW_MSIX_ENTRY);
 58	if (vector < 0)
 59		return vector;
 60
 61	/* Request the IRQ for FW Mailbox vector. */
 62	err = request_threaded_irq(vector, NULL, &fbnic_fw_msix_intr,
 63				   IRQF_ONESHOT | IRQF_NO_AUTOEN,
 64				   dev_name(fbd->dev), fbd);
 65	if (err)
 66		return err;
 67
 68	/* Initialize mailbox and attempt to poll it into ready state */
 69	err = __fbnic_fw_enable_mbx(fbd, vector);
 70	if (err)
 71		free_irq(vector, fbd);
 72
 73	fbd->fw_msix_vector = vector;
 74
 75	return err;
 76}
 77
 78/**
 79 * fbnic_fw_disable_mbx - Temporarily place mailbox in standby state
 80 * @fbd: Pointer to device
 81 *
 82 * Shutdown the mailbox by notifying the firmware to stop sending us logs, mask
 83 * and synchronize the IRQ, and then clean up the rings.
 84 **/
 85static void fbnic_fw_disable_mbx(struct fbnic_dev *fbd)
 86{
 87	/* Disable interrupt and synchronize the IRQ */
 88	disable_irq(fbd->fw_msix_vector);
 89
 90	/* Mask the vector */
 91	fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(0), 1u << FBNIC_FW_MSIX_ENTRY);
 92
 93	/* Make sure disabling logs message is sent, must be done here to
 94	 * avoid risk of completing without a running interrupt.
 95	 */
 96	fbnic_mbx_flush_tx(fbd);
 97	fbnic_mbx_clean(fbd);
 98}
 99
100/**
101 * fbnic_fw_free_mbx - Disable mailbox and place it in standby state
102 * @fbd: Pointer to device to disable
103 *
104 * This function will disable the mailbox interrupt, free any messages still
105 * in the mailbox and place it into a disabled state. The firmware is
106 * expected to see the update and assume that the host is in the reset state.
107 **/
108void fbnic_fw_free_mbx(struct fbnic_dev *fbd)
109{
110	/* Vector has already been freed */
111	if (!fbd->fw_msix_vector)
112		return;
113
114	fbnic_fw_disable_mbx(fbd);
115
116	/* Free the vector */
117	free_irq(fbd->fw_msix_vector, fbd);
118	fbd->fw_msix_vector = 0;
119}
120
121static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data)
122{
123	struct fbnic_dev *fbd = data;
124	struct fbnic_net *fbn;
125
126	if (fbd->mac->get_link_event(fbd) == FBNIC_LINK_EVENT_NONE) {
127		fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0),
128			   1u << FBNIC_PCS_MSIX_ENTRY);
129		return IRQ_HANDLED;
130	}
131
132	fbn = netdev_priv(fbd->netdev);
133
134	/* Record link down events */
135	if (!fbd->mac->get_link(fbd, fbn->aui, fbn->fec))
136		phylink_pcs_change(fbn->pcs, false);
137
138	return IRQ_HANDLED;
139}
140
141/**
142 * fbnic_mac_request_irq - Configure the MAC to enable it to advertise link
143 * @fbd: Pointer to device to initialize
144 *
145 * This function provides basic bringup for the MAC/PHY IRQ. For now the IRQ
146 * will remain disabled until we start the MAC/PCS/PHY logic via phylink.
147 *
148 * Return: non-zero on failure.
149 **/
150int fbnic_mac_request_irq(struct fbnic_dev *fbd)
151{
152	struct pci_dev *pdev = to_pci_dev(fbd->dev);
153	int vector, err;
154
155	WARN_ON(fbd->mac_msix_vector);
156
157	vector = pci_irq_vector(pdev, FBNIC_PCS_MSIX_ENTRY);
158	if (vector < 0)
159		return vector;
160
161	/* Request the IRQ for PCS link vector.
162	 * Map PCS cause to it, and unmask it
163	 */
164	err = request_irq(vector, &fbnic_mac_msix_intr, 0,
165			  fbd->netdev->name, fbd);
166	if (err)
167		return err;
168
169	/* Map and enable interrupt, unmask vector after link is configured */
170	fbnic_wr32(fbd, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX),
171		   FBNIC_PCS_MSIX_ENTRY | FBNIC_INTR_MSIX_CTRL_ENABLE);
172
173	fbd->mac_msix_vector = vector;
174
175	return 0;
176}
177
178/**
179 * fbnic_mac_free_irq - Teardown the MAC IRQ to prepare for stopping
180 * @fbd: Pointer to device that is stopping
181 *
182 * This function undoes the work done in fbnic_mac_request_irq and prepares
183 * the device to no longer receive traffic on the host interface.
184 **/
185void fbnic_mac_free_irq(struct fbnic_dev *fbd)
186{
187	/* Vector has already been freed */
188	if (!fbd->mac_msix_vector)
189		return;
190
191	/* Disable interrupt */
192	fbnic_wr32(fbd, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX),
193		   FBNIC_PCS_MSIX_ENTRY);
194	fbnic_wrfl(fbd);
195
196	/* Synchronize IRQ to prevent race that would unmask vector */
197	synchronize_irq(fbd->mac_msix_vector);
198
199	/* Mask the vector */
200	fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(0), 1u << FBNIC_PCS_MSIX_ENTRY);
201
202	/* Free the vector */
203	free_irq(fbd->mac_msix_vector, fbd);
204	fbd->mac_msix_vector = 0;
205}
206
207void fbnic_synchronize_irq(struct fbnic_dev *fbd, int nr)
208{
209	struct pci_dev *pdev = to_pci_dev(fbd->dev);
210	int irq = pci_irq_vector(pdev, nr);
211
212	if (irq < 0)
213		return;
214
215	synchronize_irq(irq);
216}
217
218int fbnic_request_irq(struct fbnic_dev *fbd, int nr, irq_handler_t handler,
219		      unsigned long flags, const char *name, void *data)
220{
221	struct pci_dev *pdev = to_pci_dev(fbd->dev);
222	int irq = pci_irq_vector(pdev, nr);
223
224	if (irq < 0)
225		return irq;
226
227	return request_irq(irq, handler, flags, name, data);
228}
229
230void fbnic_free_irq(struct fbnic_dev *fbd, int nr, void *data)
231{
232	struct pci_dev *pdev = to_pci_dev(fbd->dev);
233	int irq = pci_irq_vector(pdev, nr);
234
235	if (irq < 0)
236		return;
237
238	free_irq(irq, data);
239}
240
241void fbnic_napi_name_irqs(struct fbnic_dev *fbd)
242{
243	unsigned int i;
244
245	for (i = 0; i < ARRAY_SIZE(fbd->napi_irq); i++)
246		snprintf(fbd->napi_irq[i].name,
247			 sizeof(fbd->napi_irq[i].name),
248			 "%s-TxRx-%u", fbd->netdev->name, i);
249}
250
251int fbnic_napi_request_irq(struct fbnic_dev *fbd,
252			   struct fbnic_napi_vector *nv)
253{
254	struct fbnic_net *fbn = netdev_priv(fbd->netdev);
255	int i = fbnic_napi_idx(nv);
256	int err;
257
258	if (!fbd->napi_irq[i].users) {
259		err = fbnic_request_irq(fbd, nv->v_idx,
260					fbnic_msix_clean_rings,	0,
261					fbd->napi_irq[i].name,
262					&fbn->napi[i]);
263		if (err)
264			return err;
265	}
266
267	fbd->napi_irq[i].users++;
268	return 0;
269}
270
271void fbnic_napi_free_irq(struct fbnic_dev *fbd,
272			 struct fbnic_napi_vector *nv)
273{
274	struct fbnic_net *fbn = netdev_priv(fbd->netdev);
275	int i = fbnic_napi_idx(nv);
276
277	if (--fbd->napi_irq[i].users)
278		return;
279
280	fbnic_free_irq(fbd, nv->v_idx, &fbn->napi[i]);
281}
282
283void fbnic_free_irqs(struct fbnic_dev *fbd)
284{
285	struct pci_dev *pdev = to_pci_dev(fbd->dev);
286
287	fbd->num_irqs = 0;
288
289	pci_free_irq_vectors(pdev);
290}
291
292int fbnic_alloc_irqs(struct fbnic_dev *fbd)
293{
294	unsigned int wanted_irqs = FBNIC_NON_NAPI_VECTORS;
295	struct pci_dev *pdev = to_pci_dev(fbd->dev);
296	int num_irqs;
297
298	wanted_irqs += min_t(unsigned int, num_online_cpus(), FBNIC_MAX_RXQS);
299	num_irqs = pci_alloc_irq_vectors(pdev, FBNIC_NON_NAPI_VECTORS + 1,
300					 wanted_irqs, PCI_IRQ_MSIX);
301	if (num_irqs < 0) {
302		dev_err(fbd->dev, "Failed to allocate MSI-X entries\n");
303		return num_irqs;
304	}
305
306	if (num_irqs < wanted_irqs)
307		dev_warn(fbd->dev, "Allocated %d IRQs, expected %d\n",
308			 num_irqs, wanted_irqs);
309
310	fbd->num_irqs = num_irqs;
311
312	return 0;
313}
~/ Read-only file preview.