brintos

brintos / linux-shallow public Read only

0
0
Text · 3.8 KiB · 40d22eb Raw
165 lines · c
1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)2/* Copyright 2017-2019 NXP */3 4#include "enetc_pf.h"5 6static void enetc_msg_disable_mr_int(struct enetc_hw *hw)7{8	u32 psiier = enetc_rd(hw, ENETC_PSIIER);9	/* disable MR int source(s) */10	enetc_wr(hw, ENETC_PSIIER, psiier & ~ENETC_PSIIER_MR_MASK);11}12 13static void enetc_msg_enable_mr_int(struct enetc_hw *hw)14{15	u32 psiier = enetc_rd(hw, ENETC_PSIIER);16 17	enetc_wr(hw, ENETC_PSIIER, psiier | ENETC_PSIIER_MR_MASK);18}19 20static irqreturn_t enetc_msg_psi_msix(int irq, void *data)21{22	struct enetc_si *si = (struct enetc_si *)data;23	struct enetc_pf *pf = enetc_si_priv(si);24 25	enetc_msg_disable_mr_int(&si->hw);26	schedule_work(&pf->msg_task);27 28	return IRQ_HANDLED;29}30 31static void enetc_msg_task(struct work_struct *work)32{33	struct enetc_pf *pf = container_of(work, struct enetc_pf, msg_task);34	struct enetc_hw *hw = &pf->si->hw;35	unsigned long mr_mask;36	int i;37 38	for (;;) {39		mr_mask = enetc_rd(hw, ENETC_PSIMSGRR) & ENETC_PSIMSGRR_MR_MASK;40		if (!mr_mask) {41			/* re-arm MR interrupts, w1c the IDR reg */42			enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIIER_MR_MASK);43			enetc_msg_enable_mr_int(hw);44			return;45		}46 47		for (i = 0; i < pf->num_vfs; i++) {48			u32 psimsgrr;49			u16 msg_code;50 51			if (!(ENETC_PSIMSGRR_MR(i) & mr_mask))52				continue;53 54			enetc_msg_handle_rxmsg(pf, i, &msg_code);55 56			psimsgrr = ENETC_SIMSGSR_SET_MC(msg_code);57			psimsgrr |= ENETC_PSIMSGRR_MR(i); /* w1c */58			enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr);59		}60	}61}62 63/* Init */64static int enetc_msg_alloc_mbx(struct enetc_si *si, int idx)65{66	struct enetc_pf *pf = enetc_si_priv(si);67	struct device *dev = &si->pdev->dev;68	struct enetc_hw *hw = &si->hw;69	struct enetc_msg_swbd *msg;70	u32 val;71 72	msg = &pf->rxmsg[idx];73	/* allocate and set receive buffer */74	msg->size = ENETC_DEFAULT_MSG_SIZE;75 76	msg->vaddr = dma_alloc_coherent(dev, msg->size, &msg->dma,77					GFP_KERNEL);78	if (!msg->vaddr) {79		dev_err(dev, "msg: fail to alloc dma buffer of size: %d\n",80			msg->size);81		return -ENOMEM;82	}83 84	/* set multiple of 32 bytes */85	val = lower_32_bits(msg->dma);86	enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), val);87	val = upper_32_bits(msg->dma);88	enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), val);89 90	return 0;91}92 93static void enetc_msg_free_mbx(struct enetc_si *si, int idx)94{95	struct enetc_pf *pf = enetc_si_priv(si);96	struct enetc_hw *hw = &si->hw;97	struct enetc_msg_swbd *msg;98 99	msg = &pf->rxmsg[idx];100	dma_free_coherent(&si->pdev->dev, msg->size, msg->vaddr, msg->dma);101	memset(msg, 0, sizeof(*msg));102 103	enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), 0);104	enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), 0);105}106 107int enetc_msg_psi_init(struct enetc_pf *pf)108{109	struct enetc_si *si = pf->si;110	int vector, i, err;111 112	/* register message passing interrupt handler */113	snprintf(pf->msg_int_name, sizeof(pf->msg_int_name), "%s-vfmsg",114		 si->ndev->name);115	vector = pci_irq_vector(si->pdev, ENETC_SI_INT_IDX);116	err = request_irq(vector, enetc_msg_psi_msix, 0, pf->msg_int_name, si);117	if (err) {118		dev_err(&si->pdev->dev,119			"PSI messaging: request_irq() failed!\n");120		return err;121	}122 123	/* set one IRQ entry for PSI message receive notification (SI int) */124	enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);125 126	/* initialize PSI mailbox */127	INIT_WORK(&pf->msg_task, enetc_msg_task);128 129	for (i = 0; i < pf->num_vfs; i++) {130		err = enetc_msg_alloc_mbx(si, i);131		if (err)132			goto err_init_mbx;133	}134 135	/* enable MR interrupts */136	enetc_msg_enable_mr_int(&si->hw);137 138	return 0;139 140err_init_mbx:141	for (i--; i >= 0; i--)142		enetc_msg_free_mbx(si, i);143 144	free_irq(vector, si);145 146	return err;147}148 149void enetc_msg_psi_free(struct enetc_pf *pf)150{151	struct enetc_si *si = pf->si;152	int i;153 154	cancel_work_sync(&pf->msg_task);155 156	/* disable MR interrupts */157	enetc_msg_disable_mr_int(&si->hw);158 159	for (i = 0; i < pf->num_vfs; i++)160		enetc_msg_free_mbx(si, i);161 162	/* de-register message passing interrupt handler */163	free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si);164}165