14d089035SJijie Shao // SPDX-License-Identifier: GPL-2.0+ 24d089035SJijie Shao // Copyright (c) 2024 Hisilicon Limited. 34d089035SJijie Shao 44d089035SJijie Shao #include <linux/interrupt.h> 54d089035SJijie Shao #include "hbg_irq.h" 64d089035SJijie Shao #include "hbg_hw.h" 74d089035SJijie Shao 84d089035SJijie Shao static void hbg_irq_handle_err(struct hbg_priv *priv, 94d089035SJijie Shao struct hbg_irq_info *irq_info) 104d089035SJijie Shao { 114d089035SJijie Shao if (irq_info->need_print) 124d089035SJijie Shao dev_err(&priv->pdev->dev, 134d089035SJijie Shao "receive error interrupt: %s\n", irq_info->name); 144d089035SJijie Shao } 154d089035SJijie Shao 1640735e75SJijie Shao static void hbg_irq_handle_tx(struct hbg_priv *priv, 1740735e75SJijie Shao struct hbg_irq_info *irq_info) 1840735e75SJijie Shao { 1940735e75SJijie Shao napi_schedule(&priv->tx_ring.napi); 2040735e75SJijie Shao } 2140735e75SJijie Shao 22*f72e2559SJijie Shao static void hbg_irq_handle_rx(struct hbg_priv *priv, 23*f72e2559SJijie Shao struct hbg_irq_info *irq_info) 24*f72e2559SJijie Shao { 25*f72e2559SJijie Shao napi_schedule(&priv->rx_ring.napi); 26*f72e2559SJijie Shao } 27*f72e2559SJijie Shao 284d089035SJijie Shao #define HBG_TXRX_IRQ_I(name, handle) \ 294d089035SJijie Shao {#name, HBG_INT_MSK_##name##_B, false, false, 0, handle} 304d089035SJijie Shao #define HBG_ERR_IRQ_I(name, need_print) \ 314d089035SJijie Shao {#name, HBG_INT_MSK_##name##_B, true, need_print, 0, hbg_irq_handle_err} 324d089035SJijie Shao 334d089035SJijie Shao static struct hbg_irq_info hbg_irqs[] = { 34*f72e2559SJijie Shao HBG_TXRX_IRQ_I(RX, hbg_irq_handle_rx), 3540735e75SJijie Shao HBG_TXRX_IRQ_I(TX, hbg_irq_handle_tx), 364d089035SJijie Shao HBG_ERR_IRQ_I(MAC_MII_FIFO_ERR, true), 374d089035SJijie Shao HBG_ERR_IRQ_I(MAC_PCS_RX_FIFO_ERR, true), 384d089035SJijie Shao HBG_ERR_IRQ_I(MAC_PCS_TX_FIFO_ERR, true), 394d089035SJijie Shao HBG_ERR_IRQ_I(MAC_APP_RX_FIFO_ERR, true), 404d089035SJijie Shao HBG_ERR_IRQ_I(MAC_APP_TX_FIFO_ERR, true), 414d089035SJijie Shao HBG_ERR_IRQ_I(SRAM_PARITY_ERR, true), 424d089035SJijie Shao HBG_ERR_IRQ_I(TX_AHB_ERR, true), 434d089035SJijie Shao HBG_ERR_IRQ_I(RX_BUF_AVL, false), 444d089035SJijie Shao HBG_ERR_IRQ_I(REL_BUF_ERR, true), 454d089035SJijie Shao HBG_ERR_IRQ_I(TXCFG_AVL, false), 464d089035SJijie Shao HBG_ERR_IRQ_I(TX_DROP, false), 474d089035SJijie Shao HBG_ERR_IRQ_I(RX_DROP, false), 484d089035SJijie Shao HBG_ERR_IRQ_I(RX_AHB_ERR, true), 494d089035SJijie Shao HBG_ERR_IRQ_I(MAC_FIFO_ERR, false), 504d089035SJijie Shao HBG_ERR_IRQ_I(RBREQ_ERR, false), 514d089035SJijie Shao HBG_ERR_IRQ_I(WE_ERR, false), 524d089035SJijie Shao }; 534d089035SJijie Shao 544d089035SJijie Shao static irqreturn_t hbg_irq_handle(int irq_num, void *p) 554d089035SJijie Shao { 564d089035SJijie Shao struct hbg_irq_info *info; 574d089035SJijie Shao struct hbg_priv *priv = p; 584d089035SJijie Shao u32 status; 594d089035SJijie Shao u32 i; 604d089035SJijie Shao 614d089035SJijie Shao status = hbg_hw_get_irq_status(priv); 624d089035SJijie Shao for (i = 0; i < priv->vectors.info_array_len; i++) { 634d089035SJijie Shao info = &priv->vectors.info_array[i]; 644d089035SJijie Shao if (status & info->mask) { 654d089035SJijie Shao if (!hbg_hw_irq_is_enabled(priv, info->mask)) 664d089035SJijie Shao continue; 674d089035SJijie Shao 684d089035SJijie Shao hbg_hw_irq_enable(priv, info->mask, false); 694d089035SJijie Shao hbg_hw_irq_clear(priv, info->mask); 704d089035SJijie Shao 714d089035SJijie Shao info->count++; 724d089035SJijie Shao if (info->irq_handle) 734d089035SJijie Shao info->irq_handle(priv, info); 744d089035SJijie Shao 754d089035SJijie Shao if (info->re_enable) 764d089035SJijie Shao hbg_hw_irq_enable(priv, info->mask, true); 774d089035SJijie Shao } 784d089035SJijie Shao } 794d089035SJijie Shao 804d089035SJijie Shao return IRQ_HANDLED; 814d089035SJijie Shao } 824d089035SJijie Shao 834d089035SJijie Shao static const char *irq_names_map[HBG_VECTOR_NUM] = { "tx", "rx", 844d089035SJijie Shao "err", "mdio" }; 854d089035SJijie Shao 864d089035SJijie Shao int hbg_irq_init(struct hbg_priv *priv) 874d089035SJijie Shao { 884d089035SJijie Shao struct hbg_vector *vectors = &priv->vectors; 894d089035SJijie Shao struct device *dev = &priv->pdev->dev; 904d089035SJijie Shao int ret, id; 914d089035SJijie Shao u32 i; 924d089035SJijie Shao 934d089035SJijie Shao /* used pcim_enable_device(), so the vectors become device managed */ 944d089035SJijie Shao ret = pci_alloc_irq_vectors(priv->pdev, HBG_VECTOR_NUM, HBG_VECTOR_NUM, 954d089035SJijie Shao PCI_IRQ_MSI | PCI_IRQ_MSIX); 964d089035SJijie Shao if (ret < 0) 974d089035SJijie Shao return dev_err_probe(dev, ret, "failed to allocate vectors\n"); 984d089035SJijie Shao 994d089035SJijie Shao if (ret != HBG_VECTOR_NUM) 1004d089035SJijie Shao return dev_err_probe(dev, -EINVAL, 1014d089035SJijie Shao "requested %u MSI, but allocated %d MSI\n", 1024d089035SJijie Shao HBG_VECTOR_NUM, ret); 1034d089035SJijie Shao 1044d089035SJijie Shao /* mdio irq not requested, so the number of requested interrupts 1054d089035SJijie Shao * is HBG_VECTOR_NUM - 1. 1064d089035SJijie Shao */ 1074d089035SJijie Shao for (i = 0; i < HBG_VECTOR_NUM - 1; i++) { 1084d089035SJijie Shao id = pci_irq_vector(priv->pdev, i); 1094d089035SJijie Shao if (id < 0) 1104d089035SJijie Shao return dev_err_probe(dev, id, "failed to get irq id\n"); 1114d089035SJijie Shao 1124d089035SJijie Shao snprintf(vectors->name[i], sizeof(vectors->name[i]), "%s-%s-%s", 1134d089035SJijie Shao dev_driver_string(dev), pci_name(priv->pdev), 1144d089035SJijie Shao irq_names_map[i]); 1154d089035SJijie Shao 1164d089035SJijie Shao ret = devm_request_irq(dev, id, hbg_irq_handle, 0, 1174d089035SJijie Shao vectors->name[i], priv); 1184d089035SJijie Shao if (ret) 1194d089035SJijie Shao return dev_err_probe(dev, ret, 1204d089035SJijie Shao "failed to request irq: %s\n", 1214d089035SJijie Shao irq_names_map[i]); 1224d089035SJijie Shao } 1234d089035SJijie Shao 1244d089035SJijie Shao vectors->info_array = hbg_irqs; 1254d089035SJijie Shao vectors->info_array_len = ARRAY_SIZE(hbg_irqs); 1264d089035SJijie Shao return 0; 1274d089035SJijie Shao } 128