1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
5 #include <linux/types.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
;
17 fbnic_wr32(fbd
, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY
);
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.
34 int fbnic_fw_enable_mbx(struct fbnic_dev
*fbd
)
36 u32 vector
= fbd
->fw_msix_vector
;
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
);
45 /* Initialize mailbox and attempt to poll it into ready state */
47 err
= fbnic_mbx_poll_tx_ready(fbd
);
49 dev_warn(fbd
->dev
, "FW mailbox did not enter ready state\n");
50 free_irq(vector
, fbd
);
54 /* Enable interrupts */
55 fbnic_wr32(fbd
, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY
);
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.
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
);
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 */
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
);
96 fbn
= netdev_priv(fbd
->netdev
);
98 phylink_pcs_change(&fbn
->phylink_pcs
, false);
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
;
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
);
125 fbnic_wr32(fbd
, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX
),
126 FBNIC_PCS_MSIX_ENTRY
| FBNIC_INTR_MSIX_CTRL_ENABLE
);
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
);
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
);
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;
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
);
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
);
194 dev_err(fbd
->dev
, "Failed to allocate MSI-X entries\n");
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
);