1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2017-2019 NXP */
3
4 #include "enetc_pf.h"
5
enetc_msg_disable_mr_int(struct enetc_hw * hw)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
enetc_msg_enable_mr_int(struct enetc_hw * hw)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
enetc_msg_psi_msix(int irq,void * data)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
enetc_msg_task(struct work_struct * work)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 */
enetc_msg_alloc_mbx(struct enetc_si * si,int idx)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
enetc_msg_free_mbx(struct enetc_si * si,int idx)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
enetc_msg_psi_init(struct enetc_pf * pf)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
enetc_msg_psi_free(struct enetc_pf * pf)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