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 void fbnic_synchronize_irq(struct fbnic_dev *fbd, int nr) 150 { 151 struct pci_dev *pdev = to_pci_dev(fbd->dev); 152 int irq = pci_irq_vector(pdev, nr); 153 154 if (irq < 0) 155 return; 156 157 synchronize_irq(irq); 158 } 159 160 int fbnic_request_irq(struct fbnic_dev *fbd, int nr, irq_handler_t handler, 161 unsigned long flags, const char *name, 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 irq; 168 169 return request_irq(irq, handler, flags, name, data); 170 } 171 172 void fbnic_free_irq(struct fbnic_dev *fbd, int nr, void *data) 173 { 174 struct pci_dev *pdev = to_pci_dev(fbd->dev); 175 int irq = pci_irq_vector(pdev, nr); 176 177 if (irq < 0) 178 return; 179 180 free_irq(irq, data); 181 } 182 183 void fbnic_napi_name_irqs(struct fbnic_dev *fbd) 184 { 185 unsigned int i; 186 187 for (i = 0; i < ARRAY_SIZE(fbd->napi_irq); i++) 188 snprintf(fbd->napi_irq[i].name, 189 sizeof(fbd->napi_irq[i].name), 190 "%s-TxRx-%u", fbd->netdev->name, i); 191 } 192 193 int fbnic_napi_request_irq(struct fbnic_dev *fbd, 194 struct fbnic_napi_vector *nv) 195 { 196 struct fbnic_net *fbn = netdev_priv(fbd->netdev); 197 int i = fbnic_napi_idx(nv); 198 int err; 199 200 if (!fbd->napi_irq[i].users) { 201 err = fbnic_request_irq(fbd, nv->v_idx, 202 fbnic_msix_clean_rings, 0, 203 fbd->napi_irq[i].name, 204 &fbn->napi[i]); 205 if (err) 206 return err; 207 } 208 209 fbd->napi_irq[i].users++; 210 return 0; 211 } 212 213 void fbnic_napi_free_irq(struct fbnic_dev *fbd, 214 struct fbnic_napi_vector *nv) 215 { 216 struct fbnic_net *fbn = netdev_priv(fbd->netdev); 217 int i = fbnic_napi_idx(nv); 218 219 if (--fbd->napi_irq[i].users) 220 return; 221 222 fbnic_free_irq(fbd, nv->v_idx, &fbn->napi[i]); 223 } 224 225 void fbnic_free_irqs(struct fbnic_dev *fbd) 226 { 227 struct pci_dev *pdev = to_pci_dev(fbd->dev); 228 229 fbd->pcs_msix_vector = 0; 230 fbd->fw_msix_vector = 0; 231 232 fbd->num_irqs = 0; 233 234 pci_free_irq_vectors(pdev); 235 } 236 237 int fbnic_alloc_irqs(struct fbnic_dev *fbd) 238 { 239 unsigned int wanted_irqs = FBNIC_NON_NAPI_VECTORS; 240 struct pci_dev *pdev = to_pci_dev(fbd->dev); 241 int num_irqs; 242 243 wanted_irqs += min_t(unsigned int, num_online_cpus(), FBNIC_MAX_RXQS); 244 num_irqs = pci_alloc_irq_vectors(pdev, FBNIC_NON_NAPI_VECTORS + 1, 245 wanted_irqs, PCI_IRQ_MSIX); 246 if (num_irqs < 0) { 247 dev_err(fbd->dev, "Failed to allocate MSI-X entries\n"); 248 return num_irqs; 249 } 250 251 if (num_irqs < wanted_irqs) 252 dev_warn(fbd->dev, "Allocated %d IRQs, expected %d\n", 253 num_irqs, wanted_irqs); 254 255 fbd->num_irqs = num_irqs; 256 257 fbd->pcs_msix_vector = pci_irq_vector(pdev, FBNIC_PCS_MSIX_ENTRY); 258 fbd->fw_msix_vector = pci_irq_vector(pdev, FBNIC_FW_MSIX_ENTRY); 259 260 return 0; 261 } 262