mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
misc-mods Fix irq registering for tegra mods
Summary: Support to hook mods interrupts for tegra mods devices was broken due to gpu-mods changes that went uncaught in sanity. This change modifies the kernel to allow the tegra code paths to work again. This change also adds support to map irq numbers to gpio input pins to expand functionality in the irq framework. Change-Id: Iee65f9bcaf09453c1740cd5cf7f64b76c87e00c3 Signed-off-by: Ellis Roberts <ellisr@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/2259509 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Chris Dragan <kdragan@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* mods.h - This file is part of NVIDIA MODS kernel driver.
|
||||
*
|
||||
* Copyright (c) 2008-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2008-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA MODS kernel driver is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License,
|
||||
@@ -643,6 +643,22 @@ struct MODS_DT_INFO {
|
||||
__u32 index;
|
||||
};
|
||||
|
||||
#define MAX_GPIO_NAME_SIZE 256
|
||||
struct MODS_GPIO_INFO {
|
||||
/* OUTPUT */
|
||||
/* Irq number to be mapped to gpio and returned to user */
|
||||
__u32 irq;
|
||||
/* IN */
|
||||
/* Name of Gpio to be mapped */
|
||||
char name[MAX_GPIO_NAME_SIZE];
|
||||
/* IN */
|
||||
/* DT Name of device that gpio belongs to */
|
||||
char dt_name[MAX_DT_SIZE];
|
||||
/* IN */
|
||||
/* Name of device that gpio belongs to */
|
||||
char full_name[MAX_DT_SIZE];
|
||||
};
|
||||
|
||||
#define MODS_MASK_TYPE_IRQ_DISABLE 0
|
||||
#define MODS_MASK_TYPE_IRQ_DISABLE64 1
|
||||
|
||||
@@ -1150,6 +1166,7 @@ struct MODS_SYSFS_NODE {
|
||||
};
|
||||
|
||||
#define MODS_IRQ_TYPE_FROM_FLAGS(flags) ((flags)&0xf)
|
||||
#define MODS_IRQ_FLAG_FROM_FLAGS(flags) (((flags)&0xfff0)>>4)
|
||||
|
||||
/* MODS_ESC_SET_NUM_VF */
|
||||
struct MODS_SET_NUM_VF {
|
||||
@@ -1470,5 +1487,8 @@ struct MODS_MSR {
|
||||
_IOWR(MODS_IOC_MAGIC, 126, struct MODS_DEVICE_NUMA_INFO_3)
|
||||
#define MODS_ESC_PCI_BUS_RESCAN \
|
||||
_IOW(MODS_IOC_MAGIC, 127, struct MODS_PCI_BUS_RESCAN)
|
||||
#define MODS_ESC_MAP_GPIO \
|
||||
_IOWR(MODS_IOC_MAGIC, 128, \
|
||||
struct MODS_GPIO_INFO)
|
||||
|
||||
#endif /* _MODS_H_ */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* mods_internal.h - This file is part of NVIDIA MODS kernel driver.
|
||||
*
|
||||
* Copyright (c) 2008-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2008-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA MODS kernel driver is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License,
|
||||
@@ -505,8 +505,10 @@ int esc_mods_pci_set_dma_mask(struct mods_client *client,
|
||||
struct MODS_PCI_DMA_MASK *dma_mask);
|
||||
#endif
|
||||
/* irq */
|
||||
#if defined(MODS_TEGRA) && defined(CONFIG_OF_IRQ) && defined(CONFIG_OF)
|
||||
#if defined(MODS_TEGRA) && defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
|
||||
int esc_mods_map_irq(struct mods_client *client, struct MODS_DT_INFO *p);
|
||||
int esc_mods_map_irq_to_gpio(struct mods_client *client,
|
||||
struct MODS_GPIO_INFO *p);
|
||||
#endif
|
||||
int esc_mods_register_irq(struct mods_client *client,
|
||||
struct MODS_REGISTER_IRQ *p);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* mods_irq.c - This file is part of NVIDIA MODS kernel driver.
|
||||
*
|
||||
* Copyright (c) 2008-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2008-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA MODS kernel driver is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License,
|
||||
@@ -24,12 +24,14 @@
|
||||
#include <linux/poll.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci_regs.h>
|
||||
#if defined(MODS_TEGRA) && defined(CONFIG_OF_IRQ) && defined(CONFIG_OF)
|
||||
#if defined(MODS_TEGRA) && defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
|
||||
#define PCI_VENDOR_ID_NVIDIA 0x10de
|
||||
@@ -271,9 +273,9 @@ static int rec_irq_done(struct dev_irq_map *t,
|
||||
} else
|
||||
#endif
|
||||
mods_debug_printk(DEBUG_ISR_DETAILED,
|
||||
"CPU IRQ 0x%x, time=%uus\n",
|
||||
t->apic_irq,
|
||||
irq_time);
|
||||
"CPU IRQ 0x%x, time=%uus\n",
|
||||
t->apic_irq,
|
||||
irq_time);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -332,6 +334,9 @@ static int mods_lookup_cpu_irq(u8 client_id, unsigned int irq)
|
||||
struct dev_irq_map *t = NULL;
|
||||
struct dev_irq_map *next = NULL;
|
||||
|
||||
if (!test_bit(client_idx - 1, &mp.client_flags))
|
||||
continue;
|
||||
|
||||
list_for_each_entry_safe(t,
|
||||
next,
|
||||
&client_from_id(client_idx)->irq_list,
|
||||
@@ -346,7 +351,7 @@ static int mods_lookup_cpu_irq(u8 client_id, unsigned int irq)
|
||||
}
|
||||
|
||||
/* Break out of the outer loop */
|
||||
client_idx = MODS_MAX_CLIENTS - 1;
|
||||
client_idx = MODS_MAX_CLIENTS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -411,11 +416,37 @@ static int add_irq_map(struct mods_client *client,
|
||||
u32 irq,
|
||||
u32 entry)
|
||||
{
|
||||
u32 irq_type = MODS_IRQ_TYPE_FROM_FLAGS(p->irq_flags);
|
||||
struct dev_irq_map *newmap = NULL;
|
||||
u32 irq_type = MODS_IRQ_TYPE_FROM_FLAGS(p->irq_flags);
|
||||
struct dev_irq_map *newmap = NULL;
|
||||
u64 irq_flags = MODS_IRQ_FLAG_FROM_FLAGS(p->irq_flags);
|
||||
u64 valid_mask = IRQF_TRIGGER_NONE;
|
||||
|
||||
LOG_ENT();
|
||||
|
||||
/* Get the flags based on the interrupt type*/
|
||||
switch (irq_type) {
|
||||
case MODS_IRQ_TYPE_INT:
|
||||
irq_flags = IRQF_SHARED;
|
||||
break;
|
||||
|
||||
case MODS_IRQ_TYPE_CPU:
|
||||
valid_mask = IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_SHARED;
|
||||
|
||||
/* Either use a valid flag bit or no flags */
|
||||
if (irq_flags & ~valid_mask) {
|
||||
mods_error_printk("invalid Device Interrupt flag %llx\n",
|
||||
(long long) irq_flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
irq_flags = IRQF_TRIGGER_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate memory for the new entry */
|
||||
newmap = kzalloc(sizeof(*newmap), GFP_KERNEL | __GFP_NORETRY);
|
||||
if (unlikely(!newmap)) {
|
||||
@@ -437,10 +468,12 @@ static int add_irq_map(struct mods_client *client,
|
||||
if (request_irq(
|
||||
irq,
|
||||
&mods_irq_handle,
|
||||
(irq_type == MODS_IRQ_TYPE_INT) ? IRQF_SHARED : 0,
|
||||
irq_flags,
|
||||
"nvidia mods",
|
||||
newmap)) {
|
||||
mods_error_printk("unable to enable IRQ 0x%x\n", irq);
|
||||
mods_error_printk("unable to enable IRQ 0x%x with flags %llx\n",
|
||||
irq,
|
||||
(long long) irq_flags);
|
||||
kfree(newmap);
|
||||
atomic_dec(&client->num_allocs);
|
||||
LOG_EXT();
|
||||
@@ -475,7 +508,9 @@ static int add_irq_map(struct mods_client *client,
|
||||
|
||||
/* Print out successful registration string */
|
||||
if (irq_type == MODS_IRQ_TYPE_CPU)
|
||||
mods_debug_printk(DEBUG_ISR, "registered CPU IRQ 0x%x\n", irq);
|
||||
mods_debug_printk(DEBUG_ISR, "registered CPU IRQ 0x%x with flags %llx\n",
|
||||
irq,
|
||||
(long long) irq_flags);
|
||||
#ifdef CONFIG_PCI
|
||||
else if ((irq_type == MODS_IRQ_TYPE_INT) ||
|
||||
(irq_type == MODS_IRQ_TYPE_MSI) ||
|
||||
@@ -1292,7 +1327,7 @@ int esc_mods_query_irq_3(struct mods_client *client,
|
||||
p->irq_list[i].dev.function = PCI_FUNC(dev->devfn);
|
||||
} else {
|
||||
p->irq_list[i].dev.domain = 0;
|
||||
p->irq_list[i].dev.bus = 0;
|
||||
p->irq_list[i].dev.bus = q->data[index].irq;
|
||||
p->irq_list[i].dev.device = 0xFFU;
|
||||
p->irq_list[i].dev.function = 0xFFU;
|
||||
}
|
||||
@@ -1428,7 +1463,7 @@ int esc_mods_irq_handled(struct mods_client *client,
|
||||
int esc_mods_map_irq(struct mods_client *client,
|
||||
struct MODS_DT_INFO *p)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
/* the physical irq */
|
||||
int hwirq;
|
||||
/* platform device handle */
|
||||
@@ -1438,18 +1473,31 @@ int esc_mods_map_irq(struct mods_client *client,
|
||||
/* Search for the node by device tree name */
|
||||
struct device_node *np = of_find_node_by_name(NULL, p->dt_name);
|
||||
|
||||
if (!np) {
|
||||
mods_error_printk("node %s is not valid\n", p->full_name);
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Can be multiple nodes that share the same dt name, */
|
||||
/* make sure you get the correct node matched by the device's full */
|
||||
/* name in device tree (i.e. watchdog@30c0000 as opposed */
|
||||
/* to watchdog) */
|
||||
while (of_node_cmp(np->full_name, p->full_name) != 0)
|
||||
while (of_node_cmp(np->full_name, p->full_name)) {
|
||||
np = of_find_node_by_name(np, p->dt_name);
|
||||
if (!np) {
|
||||
mods_error_printk("node %s is not valid\n",
|
||||
p->full_name);
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
p->irq = irq_of_parse_and_map(np, p->index);
|
||||
err = of_irq_parse_one(np, p->index, &oirq);
|
||||
if (err) {
|
||||
mods_error_printk("Could not parse IRQ\n");
|
||||
return err;
|
||||
mods_error_printk("could not parse IRQ\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hwirq = oirq.args[1];
|
||||
@@ -1470,7 +1518,61 @@ int esc_mods_map_irq(struct mods_client *client,
|
||||
TOP_TKE_TKEIE(hwirq));
|
||||
}
|
||||
|
||||
error:
|
||||
of_node_put(np);
|
||||
/* enable the interrupt */
|
||||
return OK;
|
||||
return err;
|
||||
}
|
||||
|
||||
int esc_mods_map_irq_to_gpio(struct mods_client *client,
|
||||
struct MODS_GPIO_INFO *p)
|
||||
{
|
||||
//TODO: Make sure you are allocating gpio properly
|
||||
int gpio_handle;
|
||||
int irq;
|
||||
int err = 0;
|
||||
|
||||
struct device_node *np = of_find_node_by_name(NULL, p->dt_name);
|
||||
|
||||
if (!np) {
|
||||
mods_error_printk("node %s is not valid\n", p->full_name);
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (of_node_cmp(np->full_name, p->full_name)) {
|
||||
np = of_find_node_by_name(np, p->dt_name);
|
||||
if (!np) {
|
||||
mods_error_printk("node %s is not valid\n",
|
||||
p->full_name);
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_handle = of_get_named_gpio(np, p->name, 0);
|
||||
if (!gpio_is_valid(gpio_handle)) {
|
||||
mods_error_printk("gpio %s is missing\n", p->name);
|
||||
err = gpio_handle;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = gpio_direction_input(gpio_handle);
|
||||
if (err < 0) {
|
||||
mods_error_printk("pex_rst_gpio input direction change failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
irq = gpio_to_irq(gpio_handle);
|
||||
if (irq < 0) {
|
||||
mods_error_printk("Unable to get irq for pex_rst_gpio\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
p->irq = irq;
|
||||
|
||||
error:
|
||||
of_node_put(np);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* mods_krnl.c - This file is part of NVIDIA MODS kernel driver.
|
||||
*
|
||||
* Copyright (c) 2008-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2008-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA MODS kernel driver is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License,
|
||||
@@ -1829,13 +1829,18 @@ static long mods_krnl_ioctl(struct file *fp,
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
||||
#if defined(MODS_TEGRA) && defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
|
||||
case MODS_ESC_MAP_INTERRUPT:
|
||||
#if defined(MODS_TEGRA) && defined(CONFIG_OF_IRQ) && defined(CONFIG_OF)
|
||||
MODS_IOCTL(MODS_ESC_MAP_INTERRUPT,
|
||||
esc_mods_map_irq, MODS_DT_INFO);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MODS_ESC_MAP_GPIO:
|
||||
MODS_IOCTL(MODS_ESC_MAP_GPIO,
|
||||
esc_mods_map_irq_to_gpio, MODS_GPIO_INFO);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case MODS_ESC_REGISTER_IRQ:
|
||||
MODS_IOCTL_NORETVAL(MODS_ESC_REGISTER_IRQ,
|
||||
esc_mods_register_irq, MODS_REGISTER_IRQ);
|
||||
|
||||
Reference in New Issue
Block a user