brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · 9143621 Raw
209 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 Mailbox24 * @fbd: Pointer to device to initialize25 *26 * This function will initialize the firmware mailbox rings, enable the IRQ27 * and initialize the communication between the Firmware and the host. The28 * firmware is expected to respond to the initialization by sending an29 * interrupt essentially notifying the host that it has seen the30 * 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 state62 * @fbd: Pointer to device to disable63 *64 * This function will disable the mailbox interrupt, free any messages still65 * in the mailbox and place it into a standby state. The firmware is66 * 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 to77	 * 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 link105 * @fbd: Pointer to device to initialize106 *107 * This function provides basic bringup for the MAC/PCS IRQ. For now the IRQ108 * 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 it119	 */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 stopping133 * @fbd: Pointer to device that is stopping134 *135 * This function undoes the work done in fbnic_pcs_irq_enable and prepares136 * 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}209