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