Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
 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 **/
 34int 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 **/
 68void 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
 85static 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 **/
112int 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 **/
138void 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
149int 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
161void 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
172void 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
184int 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}