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