cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

enetc_msg.c (3911B)


      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}