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