xref: /openbmc/linux/drivers/net/ethernet/freescale/enetc/enetc_msg.c (revision 597473720f4dc69749542bfcfed4a927a43d935e)
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