Commit d821f8eb authored by Todd Poynor's avatar Todd Poynor Committed by Greg Kroah-Hartman

staging: gasket: interrupt: remove static function forward declarations

Remove forward declarations of static functions, move code to avoid
forward references, for kernel style.
Signed-off-by: default avatarTodd Poynor <toddpoynor@google.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ea174ccd
...@@ -70,32 +70,259 @@ struct gasket_interrupt_data { ...@@ -70,32 +70,259 @@ struct gasket_interrupt_data {
int irq; int irq;
}; };
/* Function definitions. */
static ssize_t interrupt_sysfs_show(
struct device *device, struct device_attribute *attr, char *buf);
static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id);
/* Structures to display interrupt counts in sysfs. */ /* Structures to display interrupt counts in sysfs. */
enum interrupt_sysfs_attribute_type { enum interrupt_sysfs_attribute_type {
ATTR_INTERRUPT_COUNTS, ATTR_INTERRUPT_COUNTS,
}; };
/* Set up device registers for interrupt handling. */
static void gasket_interrupt_setup(struct gasket_dev *gasket_dev)
{
int i;
int pack_shift;
ulong mask;
ulong value;
struct gasket_interrupt_data *interrupt_data =
gasket_dev->interrupt_data;
if (!interrupt_data) {
dev_dbg(gasket_dev->dev, "Interrupt data is not initialized\n");
return;
}
dev_dbg(gasket_dev->dev, "Running interrupt setup\n");
if (interrupt_data->type == PLATFORM_WIRE ||
interrupt_data->type == PCI_MSI) {
/* Nothing needs to be done for platform or PCI devices. */
return;
}
if (interrupt_data->type != PCI_MSIX) {
dev_dbg(gasket_dev->dev,
"Cannot handle unsupported interrupt type %d\n",
interrupt_data->type);
return;
}
/* Setup the MSIX table. */
for (i = 0; i < interrupt_data->num_interrupts; i++) {
/*
* If the interrupt is not packed, we can write the index into
* the register directly. If not, we need to deal with a read-
* modify-write and shift based on the packing index.
*/
dev_dbg(gasket_dev->dev,
"Setting up interrupt index %d with index 0x%llx and "
"packing %d\n",
interrupt_data->interrupts[i].index,
interrupt_data->interrupts[i].reg,
interrupt_data->interrupts[i].packing);
if (interrupt_data->interrupts[i].packing == UNPACKED) {
value = interrupt_data->interrupts[i].index;
} else {
switch (interrupt_data->interrupts[i].packing) {
case PACK_0:
pack_shift = 0;
break;
case PACK_1:
pack_shift = interrupt_data->pack_width;
break;
case PACK_2:
pack_shift = 2 * interrupt_data->pack_width;
break;
case PACK_3:
pack_shift = 3 * interrupt_data->pack_width;
break;
default:
dev_dbg(gasket_dev->dev,
"Found interrupt description with "
"unknown enum %d\n",
interrupt_data->interrupts[i].packing);
return;
}
mask = ~(0xFFFF << pack_shift);
value = gasket_dev_read_64(
gasket_dev,
interrupt_data->interrupt_bar_index,
interrupt_data->interrupts[i].reg) &
mask;
value |= interrupt_data->interrupts[i].index
<< pack_shift;
}
gasket_dev_write_64(gasket_dev, value,
interrupt_data->interrupt_bar_index,
interrupt_data->interrupts[i].reg);
}
}
static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id)
{
struct eventfd_ctx *ctx;
struct gasket_interrupt_data *interrupt_data = dev_id;
int interrupt = -1;
int i;
/* If this linear lookup is a problem, we can maintain a map/hash. */
for (i = 0; i < interrupt_data->num_interrupts; i++) {
if (interrupt_data->msix_entries[i].vector == irq) {
interrupt = interrupt_data->msix_entries[i].entry;
break;
}
}
if (interrupt == -1) {
pr_err("Received unknown irq %d\n", irq);
return IRQ_HANDLED;
}
trace_gasket_interrupt_event(interrupt_data->name, interrupt);
ctx = interrupt_data->eventfd_ctxs[interrupt];
if (ctx)
eventfd_signal(ctx, 1);
++(interrupt_data->interrupt_counts[interrupt]);
return IRQ_HANDLED;
}
static int gasket_interrupt_msix_init(
struct gasket_interrupt_data *interrupt_data)
{
int ret = 1;
int i;
for (i = 0; i < interrupt_data->num_interrupts; i++) {
interrupt_data->msix_entries[i].entry = i;
interrupt_data->msix_entries[i].vector = 0;
interrupt_data->eventfd_ctxs[i] = NULL;
}
/* Retry MSIX_RETRY_COUNT times if not enough IRQs are available. */
for (i = 0; i < MSIX_RETRY_COUNT && ret > 0; i++)
ret = pci_enable_msix_exact(interrupt_data->pci_dev,
interrupt_data->msix_entries,
interrupt_data->num_interrupts);
if (ret)
return ret > 0 ? -EBUSY : ret;
interrupt_data->msix_configured = 1;
for (i = 0; i < interrupt_data->num_interrupts; i++) {
ret = request_irq(
interrupt_data->msix_entries[i].vector,
gasket_msix_interrupt_handler, 0, interrupt_data->name,
interrupt_data);
if (ret) {
dev_err(&interrupt_data->pci_dev->dev,
"Cannot get IRQ for interrupt %d, vector %d; "
"%d\n",
i, interrupt_data->msix_entries[i].vector, ret);
return ret;
}
interrupt_data->num_configured++;
}
return 0;
}
/*
* On QCM DragonBoard, we exit gasket_interrupt_msix_init() and kernel interrupt
* setup code with MSIX vectors masked. This is wrong because nothing else in
* the driver will normally touch the MSIX vectors.
*
* As a temporary hack, force unmasking there.
*
* TODO: Figure out why QCM kernel doesn't unmask the MSIX vectors, after
* gasket_interrupt_msix_init(), and remove this code.
*/
static void force_msix_interrupt_unmasking(struct gasket_dev *gasket_dev)
{
int i;
#define MSIX_VECTOR_SIZE 16
#define MSIX_MASK_BIT_OFFSET 12
#define APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE 0x46800
for (i = 0; i < gasket_dev->interrupt_data->num_configured; i++) {
/* Check if the MSIX vector is unmasked */
ulong location = APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE +
MSIX_MASK_BIT_OFFSET + i * MSIX_VECTOR_SIZE;
u32 mask =
gasket_dev_read_32(
gasket_dev,
gasket_dev->interrupt_data->interrupt_bar_index,
location);
if (!(mask & 1))
continue;
/* Unmask the msix vector (clear 32 bits) */
gasket_dev_write_32(
gasket_dev, 0,
gasket_dev->interrupt_data->interrupt_bar_index,
location);
}
#undef MSIX_VECTOR_SIZE
#undef MSIX_MASK_BIT_OFFSET
#undef APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE
}
static ssize_t interrupt_sysfs_show(
struct device *device, struct device_attribute *attr, char *buf)
{
int i, ret;
ssize_t written = 0, total_written = 0;
struct gasket_interrupt_data *interrupt_data;
struct gasket_dev *gasket_dev;
struct gasket_sysfs_attribute *gasket_attr;
enum interrupt_sysfs_attribute_type sysfs_type;
gasket_dev = gasket_sysfs_get_device_data(device);
if (!gasket_dev) {
dev_dbg(device, "No sysfs mapping found for device\n");
return 0;
}
gasket_attr = gasket_sysfs_get_attr(device, attr);
if (!gasket_attr) {
dev_dbg(device, "No sysfs attr data found for device\n");
gasket_sysfs_put_device_data(device, gasket_dev);
return 0;
}
sysfs_type = (enum interrupt_sysfs_attribute_type)
gasket_attr->data.attr_type;
interrupt_data = gasket_dev->interrupt_data;
switch (sysfs_type) {
case ATTR_INTERRUPT_COUNTS:
for (i = 0; i < interrupt_data->num_interrupts; ++i) {
written =
scnprintf(buf, PAGE_SIZE - total_written,
"0x%02x: %ld\n", i,
interrupt_data->interrupt_counts[i]);
total_written += written;
buf += written;
}
ret = total_written;
break;
default:
dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n",
attr->attr.name);
ret = 0;
break;
}
gasket_sysfs_put_attr(device, gasket_attr);
gasket_sysfs_put_device_data(device, gasket_dev);
return ret;
}
static struct gasket_sysfs_attribute interrupt_sysfs_attrs[] = { static struct gasket_sysfs_attribute interrupt_sysfs_attrs[] = {
GASKET_SYSFS_RO( GASKET_SYSFS_RO(
interrupt_counts, interrupt_sysfs_show, ATTR_INTERRUPT_COUNTS), interrupt_counts, interrupt_sysfs_show, ATTR_INTERRUPT_COUNTS),
GASKET_END_OF_ATTR_ARRAY, GASKET_END_OF_ATTR_ARRAY,
}; };
static void gasket_interrupt_setup(struct gasket_dev *gasket_dev);
/* MSIX init and cleanup. */
static int gasket_interrupt_msix_init(
struct gasket_interrupt_data *interrupt_data);
static void gasket_interrupt_msix_cleanup(
struct gasket_interrupt_data *interrupt_data);
static void force_msix_interrupt_unmasking(struct gasket_dev *gasket_dev);
int gasket_interrupt_init( int gasket_interrupt_init(
struct gasket_dev *gasket_dev, const char *name, int type, struct gasket_dev *gasket_dev, const char *name, int type,
const struct gasket_interrupt_desc *interrupts, const struct gasket_interrupt_desc *interrupts,
...@@ -181,48 +408,6 @@ int gasket_interrupt_init( ...@@ -181,48 +408,6 @@ int gasket_interrupt_init(
return 0; return 0;
} }
static int gasket_interrupt_msix_init(
struct gasket_interrupt_data *interrupt_data)
{
int ret = 1;
int i;
for (i = 0; i < interrupt_data->num_interrupts; i++) {
interrupt_data->msix_entries[i].entry = i;
interrupt_data->msix_entries[i].vector = 0;
interrupt_data->eventfd_ctxs[i] = NULL;
}
/* Retry MSIX_RETRY_COUNT times if not enough IRQs are available. */
for (i = 0; i < MSIX_RETRY_COUNT && ret > 0; i++)
ret = pci_enable_msix_exact(interrupt_data->pci_dev,
interrupt_data->msix_entries,
interrupt_data->num_interrupts);
if (ret)
return ret > 0 ? -EBUSY : ret;
interrupt_data->msix_configured = 1;
for (i = 0; i < interrupt_data->num_interrupts; i++) {
ret = request_irq(
interrupt_data->msix_entries[i].vector,
gasket_msix_interrupt_handler, 0, interrupt_data->name,
interrupt_data);
if (ret) {
dev_err(&interrupt_data->pci_dev->dev,
"Cannot get IRQ for interrupt %d, vector %d; "
"%d\n",
i, interrupt_data->msix_entries[i].vector, ret);
return ret;
}
interrupt_data->num_configured++;
}
return 0;
}
static void gasket_interrupt_msix_cleanup( static void gasket_interrupt_msix_cleanup(
struct gasket_interrupt_data *interrupt_data) struct gasket_interrupt_data *interrupt_data)
{ {
...@@ -238,44 +423,6 @@ static void gasket_interrupt_msix_cleanup( ...@@ -238,44 +423,6 @@ static void gasket_interrupt_msix_cleanup(
interrupt_data->msix_configured = 0; interrupt_data->msix_configured = 0;
} }
/*
* On QCM DragonBoard, we exit gasket_interrupt_msix_init() and kernel interrupt
* setup code with MSIX vectors masked. This is wrong because nothing else in
* the driver will normally touch the MSIX vectors.
*
* As a temporary hack, force unmasking there.
*
* TODO: Figure out why QCM kernel doesn't unmask the MSIX vectors, after
* gasket_interrupt_msix_init(), and remove this code.
*/
static void force_msix_interrupt_unmasking(struct gasket_dev *gasket_dev)
{
int i;
#define MSIX_VECTOR_SIZE 16
#define MSIX_MASK_BIT_OFFSET 12
#define APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE 0x46800
for (i = 0; i < gasket_dev->interrupt_data->num_configured; i++) {
/* Check if the MSIX vector is unmasked */
ulong location = APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE +
MSIX_MASK_BIT_OFFSET + i * MSIX_VECTOR_SIZE;
u32 mask =
gasket_dev_read_32(
gasket_dev,
gasket_dev->interrupt_data->interrupt_bar_index,
location);
if (!(mask & 1))
continue;
/* Unmask the msix vector (clear 32 bits) */
gasket_dev_write_32(
gasket_dev, 0,
gasket_dev->interrupt_data->interrupt_bar_index,
location);
}
#undef MSIX_VECTOR_SIZE
#undef MSIX_MASK_BIT_OFFSET
#undef APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE
}
int gasket_interrupt_reinit(struct gasket_dev *gasket_dev) int gasket_interrupt_reinit(struct gasket_dev *gasket_dev)
{ {
int ret; int ret;
...@@ -327,89 +474,6 @@ int gasket_interrupt_reset_counts(struct gasket_dev *gasket_dev) ...@@ -327,89 +474,6 @@ int gasket_interrupt_reset_counts(struct gasket_dev *gasket_dev)
return 0; return 0;
} }
/* Set up device registers for interrupt handling. */
static void gasket_interrupt_setup(struct gasket_dev *gasket_dev)
{
int i;
int pack_shift;
ulong mask;
ulong value;
struct gasket_interrupt_data *interrupt_data =
gasket_dev->interrupt_data;
if (!interrupt_data) {
dev_dbg(gasket_dev->dev, "Interrupt data is not initialized\n");
return;
}
dev_dbg(gasket_dev->dev, "Running interrupt setup\n");
if (interrupt_data->type == PLATFORM_WIRE ||
interrupt_data->type == PCI_MSI) {
/* Nothing needs to be done for platform or PCI devices. */
return;
}
if (interrupt_data->type != PCI_MSIX) {
dev_dbg(gasket_dev->dev,
"Cannot handle unsupported interrupt type %d\n",
interrupt_data->type);
return;
}
/* Setup the MSIX table. */
for (i = 0; i < interrupt_data->num_interrupts; i++) {
/*
* If the interrupt is not packed, we can write the index into
* the register directly. If not, we need to deal with a read-
* modify-write and shift based on the packing index.
*/
dev_dbg(gasket_dev->dev,
"Setting up interrupt index %d with index 0x%llx and "
"packing %d\n",
interrupt_data->interrupts[i].index,
interrupt_data->interrupts[i].reg,
interrupt_data->interrupts[i].packing);
if (interrupt_data->interrupts[i].packing == UNPACKED) {
value = interrupt_data->interrupts[i].index;
} else {
switch (interrupt_data->interrupts[i].packing) {
case PACK_0:
pack_shift = 0;
break;
case PACK_1:
pack_shift = interrupt_data->pack_width;
break;
case PACK_2:
pack_shift = 2 * interrupt_data->pack_width;
break;
case PACK_3:
pack_shift = 3 * interrupt_data->pack_width;
break;
default:
dev_dbg(gasket_dev->dev,
"Found interrupt description with "
"unknown enum %d\n",
interrupt_data->interrupts[i].packing);
return;
}
mask = ~(0xFFFF << pack_shift);
value = gasket_dev_read_64(
gasket_dev,
interrupt_data->interrupt_bar_index,
interrupt_data->interrupts[i].reg) &
mask;
value |= interrupt_data->interrupts[i].index
<< pack_shift;
}
gasket_dev_write_64(gasket_dev, value,
interrupt_data->interrupt_bar_index,
interrupt_data->interrupts[i].reg);
}
}
/* See gasket_interrupt.h for description. */ /* See gasket_interrupt.h for description. */
void gasket_interrupt_cleanup(struct gasket_dev *gasket_dev) void gasket_interrupt_cleanup(struct gasket_dev *gasket_dev)
{ {
...@@ -489,82 +553,3 @@ int gasket_interrupt_clear_eventfd( ...@@ -489,82 +553,3 @@ int gasket_interrupt_clear_eventfd(
interrupt_data->eventfd_ctxs[interrupt] = NULL; interrupt_data->eventfd_ctxs[interrupt] = NULL;
return 0; return 0;
} }
static ssize_t interrupt_sysfs_show(
struct device *device, struct device_attribute *attr, char *buf)
{
int i, ret;
ssize_t written = 0, total_written = 0;
struct gasket_interrupt_data *interrupt_data;
struct gasket_dev *gasket_dev;
struct gasket_sysfs_attribute *gasket_attr;
enum interrupt_sysfs_attribute_type sysfs_type;
gasket_dev = gasket_sysfs_get_device_data(device);
if (!gasket_dev) {
dev_dbg(device, "No sysfs mapping found for device\n");
return 0;
}
gasket_attr = gasket_sysfs_get_attr(device, attr);
if (!gasket_attr) {
dev_dbg(device, "No sysfs attr data found for device\n");
gasket_sysfs_put_device_data(device, gasket_dev);
return 0;
}
sysfs_type = (enum interrupt_sysfs_attribute_type)
gasket_attr->data.attr_type;
interrupt_data = gasket_dev->interrupt_data;
switch (sysfs_type) {
case ATTR_INTERRUPT_COUNTS:
for (i = 0; i < interrupt_data->num_interrupts; ++i) {
written =
scnprintf(buf, PAGE_SIZE - total_written,
"0x%02x: %ld\n", i,
interrupt_data->interrupt_counts[i]);
total_written += written;
buf += written;
}
ret = total_written;
break;
default:
dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n",
attr->attr.name);
ret = 0;
break;
}
gasket_sysfs_put_attr(device, gasket_attr);
gasket_sysfs_put_device_data(device, gasket_dev);
return ret;
}
static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id)
{
struct eventfd_ctx *ctx;
struct gasket_interrupt_data *interrupt_data = dev_id;
int interrupt = -1;
int i;
/* If this linear lookup is a problem, we can maintain a map/hash. */
for (i = 0; i < interrupt_data->num_interrupts; i++) {
if (interrupt_data->msix_entries[i].vector == irq) {
interrupt = interrupt_data->msix_entries[i].entry;
break;
}
}
if (interrupt == -1) {
pr_err("Received unknown irq %d\n", irq);
return IRQ_HANDLED;
}
trace_gasket_interrupt_event(interrupt_data->name, interrupt);
ctx = interrupt_data->eventfd_ctxs[interrupt];
if (ctx)
eventfd_signal(ctx, 1);
++(interrupt_data->interrupt_counts[interrupt]);
return IRQ_HANDLED;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment