| 273 | } |
| 274 | |
| 275 | static int |
| 276 | dmar_alloc_irq(device_t dev, struct dmar_unit *unit, int idx) |
| 277 | { |
| 278 | device_t pcib; |
| 279 | struct dmar_msi_data *dmd; |
| 280 | uint64_t msi_addr; |
| 281 | uint32_t msi_data; |
| 282 | int error; |
| 283 | |
| 284 | dmd = &unit->intrs[idx]; |
| 285 | pcib = device_get_parent(device_get_parent(dev)); /* Really not pcib */ |
| 286 | error = PCIB_ALLOC_MSIX(pcib, dev, &dmd->irq); |
| 287 | if (error != 0) { |
| 288 | device_printf(dev, "cannot allocate %s interrupt, %d\n", |
| 289 | dmd->name, error); |
| 290 | goto err1; |
| 291 | } |
| 292 | error = bus_set_resource(dev, SYS_RES_IRQ, dmd->irq_rid, |
| 293 | dmd->irq, 1); |
| 294 | if (error != 0) { |
| 295 | device_printf(dev, "cannot set %s interrupt resource, %d\n", |
| 296 | dmd->name, error); |
| 297 | goto err2; |
| 298 | } |
| 299 | dmd->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, |
| 300 | &dmd->irq_rid, RF_ACTIVE); |
| 301 | if (dmd->irq_res == NULL) { |
| 302 | device_printf(dev, |
| 303 | "cannot allocate resource for %s interrupt\n", dmd->name); |
| 304 | error = ENXIO; |
| 305 | goto err3; |
| 306 | } |
| 307 | error = bus_setup_intr(dev, dmd->irq_res, INTR_TYPE_MISC, |
| 308 | dmd->handler, NULL, unit, &dmd->intr_handle); |
| 309 | if (error != 0) { |
| 310 | device_printf(dev, "cannot setup %s interrupt, %d\n", |
| 311 | dmd->name, error); |
| 312 | goto err4; |
| 313 | } |
| 314 | bus_describe_intr(dev, dmd->irq_res, dmd->intr_handle, "%s", dmd->name); |
| 315 | error = PCIB_MAP_MSI(pcib, dev, dmd->irq, &msi_addr, &msi_data); |
| 316 | if (error != 0) { |
| 317 | device_printf(dev, "cannot map %s interrupt, %d\n", |
| 318 | dmd->name, error); |
| 319 | goto err5; |
| 320 | } |
| 321 | dmar_write4(unit, dmd->msi_data_reg, msi_data); |
| 322 | dmar_write4(unit, dmd->msi_addr_reg, msi_addr); |
| 323 | /* Only for xAPIC mode */ |
| 324 | dmar_write4(unit, dmd->msi_uaddr_reg, msi_addr >> 32); |
| 325 | return (0); |
| 326 | |
| 327 | err5: |
| 328 | bus_teardown_intr(dev, dmd->irq_res, dmd->intr_handle); |
| 329 | err4: |
| 330 | bus_release_resource(dev, SYS_RES_IRQ, dmd->irq_rid, dmd->irq_res); |
| 331 | err3: |
| 332 | bus_delete_resource(dev, SYS_RES_IRQ, dmd->irq_rid); |
no test coverage detected