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 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 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 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 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 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 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