1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2017-2019 NXP */
3 
4 #include "enetc_pf.h"
5 
6 static 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 
13 static 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 
20 static 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 
31 static 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 */
64 static 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 
93 static 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 
107 int 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 
140 err_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 
149 void 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