|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | 2 | /* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ |
3 | 3 |
|
| 4 | +#include <linux/irqdomain.h> |
4 | 5 | #include <linux/pci.h> |
5 | 6 |
|
6 | 7 | #include "../libwx/wx_type.h" |
7 | 8 | #include "../libwx/wx_lib.h" |
8 | 9 | #include "../libwx/wx_hw.h" |
9 | 10 | #include "txgbe_type.h" |
| 11 | +#include "txgbe_phy.h" |
10 | 12 | #include "txgbe_irq.h" |
11 | 13 |
|
12 | 14 | /** |
@@ -135,3 +137,133 @@ int txgbe_request_irq(struct wx *wx) |
135 | 137 |
|
136 | 138 | return err; |
137 | 139 | } |
| 140 | + |
| 141 | +static int txgbe_request_gpio_irq(struct txgbe *txgbe) |
| 142 | +{ |
| 143 | + txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); |
| 144 | + return request_threaded_irq(txgbe->gpio_irq, NULL, |
| 145 | + txgbe_gpio_irq_handler, |
| 146 | + IRQF_ONESHOT, "txgbe-gpio-irq", txgbe); |
| 147 | +} |
| 148 | + |
| 149 | +static int txgbe_request_link_irq(struct txgbe *txgbe) |
| 150 | +{ |
| 151 | + txgbe->link_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); |
| 152 | + return request_threaded_irq(txgbe->link_irq, NULL, |
| 153 | + txgbe_link_irq_handler, |
| 154 | + IRQF_ONESHOT, "txgbe-link-irq", txgbe); |
| 155 | +} |
| 156 | + |
| 157 | +static const struct irq_chip txgbe_irq_chip = { |
| 158 | + .name = "txgbe-misc-irq", |
| 159 | +}; |
| 160 | + |
| 161 | +static int txgbe_misc_irq_domain_map(struct irq_domain *d, |
| 162 | + unsigned int irq, |
| 163 | + irq_hw_number_t hwirq) |
| 164 | +{ |
| 165 | + struct txgbe *txgbe = d->host_data; |
| 166 | + |
| 167 | + irq_set_chip_data(irq, txgbe); |
| 168 | + irq_set_chip(irq, &txgbe->misc.chip); |
| 169 | + irq_set_nested_thread(irq, true); |
| 170 | + irq_set_noprobe(irq); |
| 171 | + |
| 172 | + return 0; |
| 173 | +} |
| 174 | + |
| 175 | +static const struct irq_domain_ops txgbe_misc_irq_domain_ops = { |
| 176 | + .map = txgbe_misc_irq_domain_map, |
| 177 | +}; |
| 178 | + |
| 179 | +static irqreturn_t txgbe_misc_irq_handle(int irq, void *data) |
| 180 | +{ |
| 181 | + struct txgbe *txgbe = data; |
| 182 | + struct wx *wx = txgbe->wx; |
| 183 | + unsigned int nhandled = 0; |
| 184 | + unsigned int sub_irq; |
| 185 | + u32 eicr; |
| 186 | + |
| 187 | + eicr = wx_misc_isb(wx, WX_ISB_MISC); |
| 188 | + if (eicr & TXGBE_PX_MISC_GPIO) { |
| 189 | + sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); |
| 190 | + handle_nested_irq(sub_irq); |
| 191 | + nhandled++; |
| 192 | + } |
| 193 | + if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | |
| 194 | + TXGBE_PX_MISC_ETH_AN)) { |
| 195 | + sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); |
| 196 | + handle_nested_irq(sub_irq); |
| 197 | + nhandled++; |
| 198 | + } |
| 199 | + |
| 200 | + wx_intr_enable(wx, TXGBE_INTR_MISC); |
| 201 | + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); |
| 202 | +} |
| 203 | + |
| 204 | +static void txgbe_del_irq_domain(struct txgbe *txgbe) |
| 205 | +{ |
| 206 | + int hwirq, virq; |
| 207 | + |
| 208 | + for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) { |
| 209 | + virq = irq_find_mapping(txgbe->misc.domain, hwirq); |
| 210 | + irq_dispose_mapping(virq); |
| 211 | + } |
| 212 | + |
| 213 | + irq_domain_remove(txgbe->misc.domain); |
| 214 | +} |
| 215 | + |
| 216 | +void txgbe_free_misc_irq(struct txgbe *txgbe) |
| 217 | +{ |
| 218 | + free_irq(txgbe->gpio_irq, txgbe); |
| 219 | + free_irq(txgbe->link_irq, txgbe); |
| 220 | + free_irq(txgbe->misc.irq, txgbe); |
| 221 | + txgbe_del_irq_domain(txgbe); |
| 222 | +} |
| 223 | + |
| 224 | +int txgbe_setup_misc_irq(struct txgbe *txgbe) |
| 225 | +{ |
| 226 | + struct wx *wx = txgbe->wx; |
| 227 | + int hwirq, err; |
| 228 | + |
| 229 | + txgbe->misc.nirqs = 2; |
| 230 | + txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0, |
| 231 | + &txgbe_misc_irq_domain_ops, txgbe); |
| 232 | + if (!txgbe->misc.domain) |
| 233 | + return -ENOMEM; |
| 234 | + |
| 235 | + for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) |
| 236 | + irq_create_mapping(txgbe->misc.domain, hwirq); |
| 237 | + |
| 238 | + txgbe->misc.chip = txgbe_irq_chip; |
| 239 | + if (wx->pdev->msix_enabled) |
| 240 | + txgbe->misc.irq = wx->msix_entry->vector; |
| 241 | + else |
| 242 | + txgbe->misc.irq = wx->pdev->irq; |
| 243 | + |
| 244 | + err = request_threaded_irq(txgbe->misc.irq, NULL, |
| 245 | + txgbe_misc_irq_handle, |
| 246 | + IRQF_ONESHOT, |
| 247 | + wx->netdev->name, txgbe); |
| 248 | + if (err) |
| 249 | + goto del_misc_irq; |
| 250 | + |
| 251 | + err = txgbe_request_gpio_irq(txgbe); |
| 252 | + if (err) |
| 253 | + goto free_msic_irq; |
| 254 | + |
| 255 | + err = txgbe_request_link_irq(txgbe); |
| 256 | + if (err) |
| 257 | + goto free_gpio_irq; |
| 258 | + |
| 259 | + return 0; |
| 260 | + |
| 261 | +free_gpio_irq: |
| 262 | + free_irq(txgbe->gpio_irq, txgbe); |
| 263 | +free_msic_irq: |
| 264 | + free_irq(txgbe->misc.irq, txgbe); |
| 265 | +del_misc_irq: |
| 266 | + txgbe_del_irq_domain(txgbe); |
| 267 | + |
| 268 | + return err; |
| 269 | +} |
0 commit comments