Quantcast
Channel: Active questions tagged linux-kernel - Stack Overflow
Viewing all articles
Browse latest Browse all 12244

Linux PCI device interrupt not generated

$
0
0

I am currently refactoring a driver for the AMD Sensor Fusion Hub.The original driver can be found here.When sending commands to the device, the chip takes some time to process the request. I wasusing a hack using msleep to wait for the device to respond. However I'd like to cleanly implement IRQ handling. As a template I looked into the implementation of drivers/i2c/busses/i2c-amd-mp2-pci.c and came up with the following stub interrupt handling.

// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause/* * AMD Sensor Fusion Hub (SFH) PCIe driver * * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> *          Nehal Bakulchandra Shah <Nehal-bakulchandra.Shah@amd.com> *          Richard Neumann <mail@richard-neumann.de> */#include <linux/bitops.h>#include <linux/dma-mapping.h>#include <linux/interrupt.h>#include <linux/io-64-nonatomic-lo-hi.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/pm_runtime.h>#include <linux/types.h>#include "amd-sfh-pci.h"/** * amd_sfh_get_sensor_mask - Returns the sensors mask. * @pci_dev:    The Sensor Fusion Hub PCI device * * Returns an unsigned integer representing the bitmask to match * the sensors connected to the Sensor Fusion Hub. */int amd_sfh_get_sensor_mask(struct pci_dev *pci_dev){    int sensor_mask;    struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);    sensor_mask = readl(sfh_dev->mmio + AMD_SFH_SENSOR_MASK);    /* Correct bit shift in firmware register */    sensor_mask = sensor_mask >> 4;    if (!sensor_mask)        dev_err(&pci_dev->dev, "no sensors marked active on device\n");    return sensor_mask;}EXPORT_SYMBOL_GPL(amd_sfh_get_sensor_mask);/** * amd_sfh_start_sensor- Starts the respective sensor. * @pci_dev:    The Sensor Fusion Hub PCI device * @sensor_idx: The sensor's index * @dma_handle: The DMA handle */void amd_sfh_start_sensor(struct pci_dev *pci_dev, enum sensor_idx sensor_idx,                          dma_addr_t dma_handle){    struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);    union amd_sfh_cmd command;    union amd_sfh_parm parameter;    command.ul = 0;    command.s.cmd_id = enable_sensor;    command.s.period = PERIOD;    command.s.sensor_id = sensor_idx;    parameter.ul = 0;    parameter.s.buffer_layout = 1;    parameter.s.buffer_length = 16;    writeq(dma_handle, sfh_dev->mmio + AMD_SFH_ADDR);    writel(parameter.ul, sfh_dev->mmio + AMD_SFH_PARM);    writel(command.ul, sfh_dev->mmio + AMD_SFH_CMD);}EXPORT_SYMBOL_GPL(amd_sfh_start_sensor);/** * amd_sfh_stop_sensor- Stops the respective sensor. * @pci_dev:    The Sensor Fusion Hub PCI device * @sensor_idx: The sensor's index */void amd_sfh_stop_sensor(struct pci_dev *pci_dev, enum sensor_idx sensor_idx){    struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);    union amd_sfh_cmd command;    command.ul = 0;    command.s.cmd_id = disable_sensor;    command.s.period = 0;    command.s.sensor_id = sensor_idx;    writeq(0x0, sfh_dev->mmio + AMD_SFH_ADDR);    writel(command.ul, sfh_dev->mmio + AMD_SFH_CMD);}EXPORT_SYMBOL_GPL(amd_sfh_stop_sensor);/** * amd_sfh_stop_all_sensors- Stops all sensors on the SFH. * @pci_dev:    The Sensor Fusion Hub PCI device */static void amd_sfh_stop_all_sensors(struct pci_dev *pci_dev){    struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);    union amd_sfh_cmd command;    command.ul = 0;    command.s.cmd_id = stop_all_sensors;    command.s.period = 0;    command.s.sensor_id = 0;    writel(command.ul, sfh_dev->mmio + AMD_SFH_CMD);}/** * amd_sfh_irq_isr - IRQ handler * @irq:    The IRQ number received * @dev:    The underlying device */static irqreturn_t amd_sfh_irq_isr(int irq, void *dev){    struct amd_sfh_dev *sfh_dev = dev;    dev_info(&sfh_dev->pci_dev->dev, "got IRQ: %d\n", irq);    return IRQ_NONE;}/** * amd_sfh_pci_init - Initializes the PCI device * @sfh_dev:    The device data * @pci_dev:    The PCI device */static int amd_sfh_pci_init(struct amd_sfh_dev *sfh_dev,                            struct pci_dev *pci_dev){    int rc;    pci_set_drvdata(pci_dev, sfh_dev);    rc = pcim_enable_device(pci_dev);    if (rc)        goto err_pci_enable;    rc = pcim_iomap_regions(pci_dev, BIT(2), pci_name(pci_dev));    if (rc)        goto err_pci_enable;    sfh_dev->pci_dev = pci_dev;    sfh_dev->mmio = pcim_iomap_table(pci_dev)[2];    pci_set_master(pci_dev);    rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64));    if (rc) {        rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));        if (rc)            goto err_dma_mask;    }    /* Set up intx irq */    writel(0, sfh_dev->mmio + AMD_P2C_MSG_INTEN);    pci_intx(pci_dev, 1);    dev_info(&pci_dev->dev, "available interrupt: %d\n", pci_dev->irq);    rc = devm_request_irq(&pci_dev->dev, pci_dev->irq, amd_sfh_irq_isr,                  0, dev_name(&pci_dev->dev), sfh_dev);    if (rc)        dev_err(&pci_dev->dev, "Failure requesting irq %i: %d\n",            pci_dev->irq, rc);    return rc;err_dma_mask:    pci_clear_master(pci_dev);err_pci_enable:    return rc;}static int amd_sfh_pci_probe(struct pci_dev *pci_dev,                 const struct pci_device_id *id){    int rc;    struct amd_sfh_dev *sfh_dev;    sfh_dev = devm_kzalloc(&pci_dev->dev, sizeof(*sfh_dev), GFP_KERNEL);    if (!sfh_dev)        return -ENOMEM;    rc = amd_sfh_pci_init(sfh_dev, pci_dev);    if (rc)        return rc;    pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000);    pm_runtime_use_autosuspend(&pci_dev->dev);    pm_runtime_put_autosuspend(&pci_dev->dev);    pm_runtime_allow(&pci_dev->dev);    dev_info(&pci_dev->dev, "SFH device registered.\n");    return 0;}static void amd_sfh_pci_remove(struct pci_dev *pci_dev){    struct amd_sfh_dev *sfh_dev = pci_get_drvdata(pci_dev);    amd_sfh_stop_all_sensors(sfh_dev->pci_dev);    pm_runtime_forbid(&pci_dev->dev);    pm_runtime_get_noresume(&pci_dev->dev);    pci_intx(pci_dev, 0);    pci_clear_master(pci_dev);}static const struct pci_device_id amd_sfh_pci_tbl[] = {    {PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SFH)},    {0}};MODULE_DEVICE_TABLE(pci, amd_sfh_pci_tbl);static struct pci_driver amd_sfh_pci_driver = {    .name       = "amd-sfh-pci",    .id_table   = amd_sfh_pci_tbl,    .probe      = amd_sfh_pci_probe,    .remove     = amd_sfh_pci_remove,};module_pci_driver(amd_sfh_pci_driver);/** * amd_sfh_find_device - Returns the first best AMD SFH device. */struct amd_sfh_dev *amd_sfh_find_device(void){    struct device *dev;    struct pci_dev *pci_dev;    dev = driver_find_next_device(&amd_sfh_pci_driver.driver, NULL);    if (!dev)        return NULL;    pci_dev = to_pci_dev(dev);    return pci_get_drvdata(pci_dev);}EXPORT_SYMBOL_GPL(amd_sfh_find_device);MODULE_DESCRIPTION("AMD(R) Sensor Fusion Hub PCI driver");MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");MODULE_AUTHOR("Nehal Bakulchandra Shah <Nehal-bakulchandra.Shah@amd.com>");MODULE_AUTHOR("Richard Neumann <mail@richard-neumann.de>");MODULE_LICENSE("Dual BSD/GPL");

However the dev_info from amd_sfh_irq_isr is never logged, so I suspect that the IRQ is never triggered when writing to the device registers. What can be the reason for that and what can I do to correctly implement the IRQ handling?

PSdmesg output:

[ 2272.642762] amd-sfh-pci 0000:04:00.7: available interrupt: 56[ 2272.642840] amd-sfh-pci 0000:04:00.7: SFH device registered.

UpdateThe device seems to support MSI:

04:00.7 Non-VGA unclassified device [0000]: Advanced Micro Devices, Inc. [AMD] Raven/Raven2/Renoir Sensor Fusion Hub [1022:15e4]    Subsystem: Hewlett-Packard Company Raven/Raven2/Renoir Sensor Fusion Hub [103c:8496]    Flags: bus master, fast devsel, latency 0, IRQ 56    Memory at fc800000 (32-bit, non-prefetchable) [size=1M]    Memory at fcc8c000 (32-bit, non-prefetchable) [size=8K]    Capabilities: [48] Vendor Specific Information: Len=08 <?>    Capabilities: [50] Power Management version 3    Capabilities: [64] Express Endpoint, MSI 00    Capabilities: [a0] MSI: Enable- Count=1/2 Maskable- 64bit+    Capabilities: [c0] MSI-X: Enable- Count=2 Masked-    Capabilities: [100] Vendor Specific Information: ID=0001 Rev=1 Len=010 <?>    Kernel modules: amd_sfh_pci

But the interrupts are still not received / handled:

static void amd_sfh_debug(struct pci_dev *pci_dev){    bool msi;    msi = pci_dev_msi_enabled(pci_dev);    pci_info(pci_dev, "MSI: %s\n", msi ? "true" : "false");    pci_info(pci_dev, "No MSI: %s\n", pci_dev->no_msi ? "true" : "false");}/** * amd_sfh_handle_irq - Handles IRQs. * @irq:    The interrupt request to be handled * @dev:    The driver data * * Returns an appropriate IRQ return type. */static irqreturn_t amd_sfh_handle_irq(int irq, void *dev){    struct amd_sfh_dev *privdata = dev;    pci_info(privdata->pci_dev, "got IRQ: %d\n", irq);    return IRQ_NONE;}static int amd_sfh_setup_irq(struct amd_sfh_dev *privdata){    int rc, vecs, irq;    struct pci_dev *pci_dev = privdata->pci_dev;    vecs = pci_alloc_irq_vectors(pci_dev, 1, 3, PCI_IRQ_ALL_TYPES);    if (vecs < 0)        return vecs;    pci_info(pci_dev, "allocated %d IRQ vectors\n", vecs);    for (irq = 0; irq < vecs; irq++) {        pci_info(pci_dev, "requesting IRQ: %d\n", irq);        rc = devm_request_irq(&pci_dev->dev,                             pci_irq_vector(pci_dev, irq),                             amd_sfh_handle_irq, 0, "sfh-irq",                             privdata);        if (rc) {            pci_err(pci_dev, "failed to get IRQ\n");            goto free_irq_vectors;        }    }    return 0;free_irq_vectors:    pci_free_irq_vectors(pci_dev);    return rc;}static int amd_sfh_pci_init(struct amd_sfh_dev *privdata,                            struct pci_dev *pci_dev){    int rc;    pci_set_drvdata(pci_dev, privdata);    rc = pcim_enable_device(pci_dev);    if (rc)        return rc;    rc = pcim_iomap_regions(pci_dev, BIT(2), pci_name(pci_dev));    if (rc)        return rc;    privdata->pci_dev = pci_dev;    privdata->mmio = pcim_iomap_table(pci_dev)[2];    pci_set_master(pci_dev);    rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64));    if (rc) {        rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));        if (rc)            goto clear_master;    }    /* Setup IRQ */    amd_sfh_debug(pci_dev);    rc = amd_sfh_setup_irq(privdata);    if (rc)        goto clear_master;    amd_sfh_debug(pci_dev);    /* End of IRQ setup */    pci_info(pci_dev, "AMD Sensor Fusion Hub device initialized\n");    return 0;clear_master:    pci_clear_master(pci_dev);    return rc;}

dmesg:

[    6.954524] amd-sfh-pci 0000:04:00.7: enabling device (0000 -> 0002)[    6.954641] amd-sfh-pci 0000:04:00.7: MSI: false[    6.954642] amd-sfh-pci 0000:04:00.7: No MSI: false[    6.954791] amd-sfh-pci 0000:04:00.7: allocated 2 IRQ vectors[    6.954792] amd-sfh-pci 0000:04:00.7: requesting IRQ: 0[    6.954825] amd-sfh-pci 0000:04:00.7: requesting IRQ: 1[    6.954860] amd-sfh-pci 0000:04:00.7: MSI: true[    6.954861] amd-sfh-pci 0000:04:00.7: No MSI: false[    6.954861] amd-sfh-pci 0000:04:00.7: AMD Sensor Fusion Hub device initialized[    6.969691] amd-sfh-pci 0000:04:00.7: [Firmware Bug]: No sensors marked active![    6.971265] amd-sfh-pci 0000:04:00.7: sensor mask: 0x000001[    7.548189] hid-generic 0018:03FE:0001.0001: hidraw0: I2C HID v0.01 Device [amd-sfh-accel] on 

The original documentation from AMD mentiones interrupts but is not too specific as to how they are being generated.


Viewing all articles
Browse latest Browse all 12244

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>