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