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