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