xref: /linux/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c (revision 40735e7543f94fc88f58d94fd5f88daa4a2f2c6e)
1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright (c) 2024 Hisilicon Limited.
3 
4 #include <linux/interrupt.h>
5 #include "hbg_irq.h"
6 #include "hbg_hw.h"
7 
8 static void hbg_irq_handle_err(struct hbg_priv *priv,
9 			       struct hbg_irq_info *irq_info)
10 {
11 	if (irq_info->need_print)
12 		dev_err(&priv->pdev->dev,
13 			"receive error interrupt: %s\n", irq_info->name);
14 }
15 
16 static void hbg_irq_handle_tx(struct hbg_priv *priv,
17 			      struct hbg_irq_info *irq_info)
18 {
19 	napi_schedule(&priv->tx_ring.napi);
20 }
21 
22 #define HBG_TXRX_IRQ_I(name, handle) \
23 	{#name, HBG_INT_MSK_##name##_B, false, false, 0, handle}
24 #define HBG_ERR_IRQ_I(name, need_print) \
25 	{#name, HBG_INT_MSK_##name##_B, true, need_print, 0, hbg_irq_handle_err}
26 
27 static struct hbg_irq_info hbg_irqs[] = {
28 	HBG_TXRX_IRQ_I(RX, NULL),
29 	HBG_TXRX_IRQ_I(TX, hbg_irq_handle_tx),
30 	HBG_ERR_IRQ_I(MAC_MII_FIFO_ERR, true),
31 	HBG_ERR_IRQ_I(MAC_PCS_RX_FIFO_ERR, true),
32 	HBG_ERR_IRQ_I(MAC_PCS_TX_FIFO_ERR, true),
33 	HBG_ERR_IRQ_I(MAC_APP_RX_FIFO_ERR, true),
34 	HBG_ERR_IRQ_I(MAC_APP_TX_FIFO_ERR, true),
35 	HBG_ERR_IRQ_I(SRAM_PARITY_ERR, true),
36 	HBG_ERR_IRQ_I(TX_AHB_ERR, true),
37 	HBG_ERR_IRQ_I(RX_BUF_AVL, false),
38 	HBG_ERR_IRQ_I(REL_BUF_ERR, true),
39 	HBG_ERR_IRQ_I(TXCFG_AVL, false),
40 	HBG_ERR_IRQ_I(TX_DROP, false),
41 	HBG_ERR_IRQ_I(RX_DROP, false),
42 	HBG_ERR_IRQ_I(RX_AHB_ERR, true),
43 	HBG_ERR_IRQ_I(MAC_FIFO_ERR, false),
44 	HBG_ERR_IRQ_I(RBREQ_ERR, false),
45 	HBG_ERR_IRQ_I(WE_ERR, false),
46 };
47 
48 static irqreturn_t hbg_irq_handle(int irq_num, void *p)
49 {
50 	struct hbg_irq_info *info;
51 	struct hbg_priv *priv = p;
52 	u32 status;
53 	u32 i;
54 
55 	status = hbg_hw_get_irq_status(priv);
56 	for (i = 0; i < priv->vectors.info_array_len; i++) {
57 		info = &priv->vectors.info_array[i];
58 		if (status & info->mask) {
59 			if (!hbg_hw_irq_is_enabled(priv, info->mask))
60 				continue;
61 
62 			hbg_hw_irq_enable(priv, info->mask, false);
63 			hbg_hw_irq_clear(priv, info->mask);
64 
65 			info->count++;
66 			if (info->irq_handle)
67 				info->irq_handle(priv, info);
68 
69 			if (info->re_enable)
70 				hbg_hw_irq_enable(priv, info->mask, true);
71 		}
72 	}
73 
74 	return IRQ_HANDLED;
75 }
76 
77 static const char *irq_names_map[HBG_VECTOR_NUM] = { "tx", "rx",
78 						     "err", "mdio" };
79 
80 int hbg_irq_init(struct hbg_priv *priv)
81 {
82 	struct hbg_vector *vectors = &priv->vectors;
83 	struct device *dev = &priv->pdev->dev;
84 	int ret, id;
85 	u32 i;
86 
87 	/* used pcim_enable_device(),  so the vectors become device managed */
88 	ret = pci_alloc_irq_vectors(priv->pdev, HBG_VECTOR_NUM, HBG_VECTOR_NUM,
89 				    PCI_IRQ_MSI | PCI_IRQ_MSIX);
90 	if (ret < 0)
91 		return dev_err_probe(dev, ret, "failed to allocate vectors\n");
92 
93 	if (ret != HBG_VECTOR_NUM)
94 		return dev_err_probe(dev, -EINVAL,
95 				     "requested %u MSI, but allocated %d MSI\n",
96 				     HBG_VECTOR_NUM, ret);
97 
98 	/* mdio irq not requested, so the number of requested interrupts
99 	 * is HBG_VECTOR_NUM - 1.
100 	 */
101 	for (i = 0; i < HBG_VECTOR_NUM - 1; i++) {
102 		id = pci_irq_vector(priv->pdev, i);
103 		if (id < 0)
104 			return dev_err_probe(dev, id, "failed to get irq id\n");
105 
106 		snprintf(vectors->name[i], sizeof(vectors->name[i]), "%s-%s-%s",
107 			 dev_driver_string(dev), pci_name(priv->pdev),
108 			 irq_names_map[i]);
109 
110 		ret = devm_request_irq(dev, id, hbg_irq_handle, 0,
111 				       vectors->name[i], priv);
112 		if (ret)
113 			return dev_err_probe(dev, ret,
114 					     "failed to request irq: %s\n",
115 					     irq_names_map[i]);
116 	}
117 
118 	vectors->info_array = hbg_irqs;
119 	vectors->info_array_len = ARRAY_SIZE(hbg_irqs);
120 	return 0;
121 }
122