Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / net / ethernet / meta / fbnic / fbnic_irq.c
blob9143621959203a10949ff525ba1fc98f8f6e8c5b
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
4 #include <linux/pci.h>
5 #include <linux/types.h>
7 #include "fbnic.h"
8 #include "fbnic_netdev.h"
9 #include "fbnic_txrx.h"
11 static irqreturn_t fbnic_fw_msix_intr(int __always_unused irq, void *data)
13 struct fbnic_dev *fbd = (struct fbnic_dev *)data;
15 fbnic_mbx_poll(fbd);
17 fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
19 return IRQ_HANDLED;
22 /**
23 * fbnic_fw_enable_mbx - Configure and initialize Firmware Mailbox
24 * @fbd: Pointer to device to initialize
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.
32 * Return: non-zero on failure.
33 **/
34 int fbnic_fw_enable_mbx(struct fbnic_dev *fbd)
36 u32 vector = fbd->fw_msix_vector;
37 int err;
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;
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;
54 /* Enable interrupts */
55 fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
57 return 0;
60 /**
61 * fbnic_fw_disable_mbx - Disable mailbox and place it in standby state
62 * @fbd: Pointer to device to disable
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)
70 /* Disable interrupt and free vector */
71 fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(0), 1u << FBNIC_FW_MSIX_ENTRY);
73 /* Free the vector */
74 free_irq(fbd->fw_msix_vector, fbd);
76 /* Make sure disabling logs message is sent, must be done here to
77 * avoid risk of completing without a running interrupt.
79 fbnic_mbx_flush_tx(fbd);
81 /* Reset the mailboxes to the initialized state */
82 fbnic_mbx_clean(fbd);
85 static irqreturn_t fbnic_pcs_msix_intr(int __always_unused irq, void *data)
87 struct fbnic_dev *fbd = data;
88 struct fbnic_net *fbn;
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;
96 fbn = netdev_priv(fbd->netdev);
98 phylink_pcs_change(&fbn->phylink_pcs, false);
100 return IRQ_HANDLED;
104 * fbnic_pcs_irq_enable - Configure the MAC to enable it to advertise link
105 * @fbd: Pointer to device to initialize
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.
110 * Return: non-zero on failure.
112 int fbnic_pcs_irq_enable(struct fbnic_dev *fbd)
114 u32 vector = fbd->pcs_msix_vector;
115 int err;
117 /* Request the IRQ for MAC link vector.
118 * Map MAC cause to it, and unmask it
120 err = request_irq(vector, &fbnic_pcs_msix_intr, 0,
121 fbd->netdev->name, fbd);
122 if (err)
123 return err;
125 fbnic_wr32(fbd, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX),
126 FBNIC_PCS_MSIX_ENTRY | FBNIC_INTR_MSIX_CTRL_ENABLE);
128 return 0;
132 * fbnic_pcs_irq_disable - Teardown the MAC IRQ to prepare for stopping
133 * @fbd: Pointer to device that is stopping
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.
138 void fbnic_pcs_irq_disable(struct fbnic_dev *fbd)
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);
145 /* Free the vector */
146 free_irq(fbd->pcs_msix_vector, fbd);
149 int fbnic_request_irq(struct fbnic_dev *fbd, int nr, irq_handler_t handler,
150 unsigned long flags, const char *name, void *data)
152 struct pci_dev *pdev = to_pci_dev(fbd->dev);
153 int irq = pci_irq_vector(pdev, nr);
155 if (irq < 0)
156 return irq;
158 return request_irq(irq, handler, flags, name, data);
161 void fbnic_free_irq(struct fbnic_dev *fbd, int nr, void *data)
163 struct pci_dev *pdev = to_pci_dev(fbd->dev);
164 int irq = pci_irq_vector(pdev, nr);
166 if (irq < 0)
167 return;
169 free_irq(irq, data);
172 void fbnic_free_irqs(struct fbnic_dev *fbd)
174 struct pci_dev *pdev = to_pci_dev(fbd->dev);
176 fbd->pcs_msix_vector = 0;
177 fbd->fw_msix_vector = 0;
179 fbd->num_irqs = 0;
181 pci_free_irq_vectors(pdev);
184 int fbnic_alloc_irqs(struct fbnic_dev *fbd)
186 unsigned int wanted_irqs = FBNIC_NON_NAPI_VECTORS;
187 struct pci_dev *pdev = to_pci_dev(fbd->dev);
188 int num_irqs;
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;
198 if (num_irqs < wanted_irqs)
199 dev_warn(fbd->dev, "Allocated %d IRQs, expected %d\n",
200 num_irqs, wanted_irqs);
202 fbd->num_irqs = num_irqs;
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);
207 return 0;