Linux Audio

Check our new training course

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