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 } 209