|
Packit Service |
2212bb |
#include "config.h"
|
|
Packit Service |
2212bb |
#include <stdlib.h>
|
|
Packit Service |
2212bb |
#include <stdio.h>
|
|
Packit Service |
2212bb |
#include <unistd.h>
|
|
Packit Service |
2212bb |
#include <sys/types.h>
|
|
Packit Service |
2212bb |
#include <dirent.h>
|
|
Packit Service |
2212bb |
#include <assert.h>
|
|
Packit Service |
2212bb |
#include <errno.h>
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
#include "irqbalance.h"
|
|
Packit Service |
2212bb |
#include "types.h"
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
char *classes[] = {
|
|
Packit Service |
2212bb |
"other",
|
|
Packit Service |
2212bb |
"legacy",
|
|
Packit Service |
2212bb |
"storage",
|
|
Packit Service |
2212bb |
"video",
|
|
Packit Service |
2212bb |
"ethernet",
|
|
Packit Service |
2212bb |
"gbit-ethernet",
|
|
Packit Service |
2212bb |
"10gbit-ethernet",
|
|
Packit Service |
2212bb |
"virt-event",
|
|
Packit Service |
2212bb |
0
|
|
Packit Service |
2212bb |
};
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static int map_class_to_level[8] =
|
|
Packit Service |
2212bb |
{ BALANCE_PACKAGE, BALANCE_CACHE, BALANCE_CORE, BALANCE_CORE, BALANCE_CORE, BALANCE_CORE, BALANCE_CORE, BALANCE_CORE };
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
struct user_irq_policy {
|
|
Packit Service |
2212bb |
int ban;
|
|
Packit Service |
2212bb |
int level;
|
|
Packit Service |
2212bb |
int numa_node_set;
|
|
Packit Service |
2212bb |
int numa_node;
|
|
Packit Service |
2212bb |
};
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static GList *interrupts_db = NULL;
|
|
Packit Service |
2212bb |
static GList *banned_irqs = NULL;
|
|
Packit Service |
2212bb |
GList *cl_banned_irqs = NULL;
|
|
Packit Service |
2212bb |
static GList *cl_banned_modules = NULL;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
#define SYSFS_DIR "/sys"
|
|
Packit Service |
2212bb |
#define SYSDEV_DIR "/sys/bus/pci/devices"
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
#define PCI_MAX_CLASS 0x14
|
|
Packit Service |
2212bb |
#define PCI_MAX_SERIAL_SUBCLASS 0x81
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
#define PCI_INVAL_DATA 0xFFFFFFFF
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
struct pci_info {
|
|
Packit Service |
2212bb |
unsigned short vendor;
|
|
Packit Service |
2212bb |
unsigned short device;
|
|
Packit Service |
2212bb |
unsigned short sub_vendor;
|
|
Packit Service |
2212bb |
unsigned short sub_device;
|
|
Packit Service |
2212bb |
unsigned int class;
|
|
Packit Service |
2212bb |
};
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* PCI vendor ID, device ID */
|
|
Packit Service |
2212bb |
#define PCI_VENDOR_PLX 0x10b5
|
|
Packit Service |
2212bb |
#define PCI_DEVICE_PLX_PEX8619 0x8619
|
|
Packit Service |
2212bb |
#define PCI_VENDOR_CAVIUM 0x177d
|
|
Packit Service |
2212bb |
#define PCI_DEVICE_CAVIUM_CN61XX 0x0093
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* PCI subsystem vendor ID, subsystem device ID */
|
|
Packit Service |
2212bb |
#define PCI_SUB_VENDOR_EMC 0x1120
|
|
Packit Service |
2212bb |
#define PCI_SUB_DEVICE_EMC_055B 0x055b
|
|
Packit Service |
2212bb |
#define PCI_SUB_DEVICE_EMC_0568 0x0568
|
|
Packit Service |
2212bb |
#define PCI_SUB_DEVICE_EMC_dd00 0xdd00
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Apply software workarounds for some special devices
|
|
Packit Service |
2212bb |
*
|
|
Packit Service |
2212bb |
* The world is not perfect and supplies us with broken PCI devices.
|
|
Packit Service |
2212bb |
* Usually there are two sort of cases:
|
|
Packit Service |
2212bb |
*
|
|
Packit Service |
2212bb |
* 1. The device is special
|
|
Packit Service |
2212bb |
* Before shipping the devices, PCI spec doesn't have the definitions.
|
|
Packit Service |
2212bb |
*
|
|
Packit Service |
2212bb |
* 2. Buggy PCI devices
|
|
Packit Service |
2212bb |
* Some PCI devices don't follow the PCI class code definitions.
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
static void apply_pci_quirks(const struct pci_info *pci, int *irq_class)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
if ((pci->vendor == PCI_VENDOR_PLX) &&
|
|
Packit Service |
2212bb |
(pci->device == PCI_DEVICE_PLX_PEX8619) &&
|
|
Packit Service |
2212bb |
(pci->sub_vendor == PCI_SUB_VENDOR_EMC)) {
|
|
Packit Service |
2212bb |
switch (pci->sub_device) {
|
|
Packit Service |
2212bb |
case PCI_SUB_DEVICE_EMC_055B:
|
|
Packit Service |
2212bb |
case PCI_SUB_DEVICE_EMC_dd00:
|
|
Packit Service |
2212bb |
*irq_class = IRQ_SCSI;
|
|
Packit Service |
2212bb |
break;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if ((pci->vendor == PCI_VENDOR_CAVIUM) &&
|
|
Packit Service |
2212bb |
(pci->device == PCI_DEVICE_CAVIUM_CN61XX) &&
|
|
Packit Service |
2212bb |
(pci->sub_vendor == PCI_SUB_VENDOR_EMC)) {
|
|
Packit Service |
2212bb |
switch (pci->sub_device) {
|
|
Packit Service |
2212bb |
case PCI_SUB_DEVICE_EMC_0568:
|
|
Packit Service |
2212bb |
*irq_class = IRQ_SCSI;
|
|
Packit Service |
2212bb |
break;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Determin IRQ class based on PCI class code */
|
|
Packit Service |
2212bb |
static int map_pci_irq_class(unsigned int pci_class)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
unsigned int major = pci_class >> 16;
|
|
Packit Service |
2212bb |
unsigned int sub = (pci_class & 0xFF00) >> 8;
|
|
Packit Service |
2212bb |
int irq_class = IRQ_NODEF;
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Class codes lifted from below PCI-SIG spec:
|
|
Packit Service |
2212bb |
*
|
|
Packit Service |
2212bb |
* PCI Code and ID Assignment Specification v1.5
|
|
Packit Service |
2212bb |
*
|
|
Packit Service |
2212bb |
* and mapped to irqbalance types here.
|
|
Packit Service |
2212bb |
*
|
|
Packit Service |
2212bb |
* IRQ_NODEF will go through classification by PCI sub-class code.
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
static short major_class_codes[PCI_MAX_CLASS] = {
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_SCSI,
|
|
Packit Service |
2212bb |
IRQ_ETH,
|
|
Packit Service |
2212bb |
IRQ_VIDEO,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_NODEF,
|
|
Packit Service |
2212bb |
IRQ_ETH,
|
|
Packit Service |
2212bb |
IRQ_SCSI,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_OTHER,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
};
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* All sub-class code for serial bus controllers.
|
|
Packit Service |
2212bb |
* The major class code is 0xc.
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
static short serial_sub_codes[PCI_MAX_SERIAL_SUBCLASS] = {
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_SCSI,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_SCSI,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
[0xa ... 0x7f] = IRQ_NODEF,
|
|
Packit Service |
2212bb |
IRQ_LEGACY,
|
|
Packit Service |
2212bb |
};
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Check major class code first
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (major >= PCI_MAX_CLASS)
|
|
Packit Service |
2212bb |
return IRQ_NODEF;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
switch (major) {
|
|
Packit Service |
2212bb |
case 0xc: /* Serial bus class */
|
|
Packit Service |
2212bb |
if (sub >= PCI_MAX_SERIAL_SUBCLASS)
|
|
Packit Service |
2212bb |
return IRQ_NODEF;
|
|
Packit Service |
2212bb |
irq_class = serial_sub_codes[sub];
|
|
Packit Service |
2212bb |
break;
|
|
Packit Service |
2212bb |
default: /* All other PCI classes */
|
|
Packit Service |
2212bb |
irq_class = major_class_codes[major];
|
|
Packit Service |
2212bb |
break;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
return irq_class;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Read specific data from sysfs */
|
|
Packit Service |
2212bb |
static unsigned int read_pci_data(const char *devpath, const char* file)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
char path[PATH_MAX];
|
|
Packit Service |
2212bb |
FILE *fd;
|
|
Packit Service |
2212bb |
unsigned int data = PCI_INVAL_DATA;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
sprintf(path, "%s/%s", devpath, file);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
fd = fopen(path, "r");
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!fd) {
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_WARNING, "PCI: can't open file:%s\n", path);
|
|
Packit Service |
2212bb |
return data;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
(void) fscanf(fd, "%x", &data);
|
|
Packit Service |
2212bb |
fclose(fd);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
return data;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Get pci information for IRQ classification */
|
|
Packit Service |
2212bb |
static int get_pci_info(const char *devpath, struct pci_info *pci)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
unsigned int data = PCI_INVAL_DATA;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if ((data = read_pci_data(devpath, "vendor")) == PCI_INVAL_DATA)
|
|
Packit Service |
2212bb |
return -ENODEV;
|
|
Packit Service |
2212bb |
pci->vendor = (unsigned short)data;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if ((data = read_pci_data(devpath, "device")) == PCI_INVAL_DATA)
|
|
Packit Service |
2212bb |
return -ENODEV;
|
|
Packit Service |
2212bb |
pci->device = (unsigned short)data;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if ((data = read_pci_data(devpath, "subsystem_vendor")) == PCI_INVAL_DATA)
|
|
Packit Service |
2212bb |
return -ENODEV;
|
|
Packit Service |
2212bb |
pci->sub_vendor = (unsigned short)data;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if ((data = read_pci_data(devpath, "subsystem_device")) == PCI_INVAL_DATA)
|
|
Packit Service |
2212bb |
return -ENODEV;
|
|
Packit Service |
2212bb |
pci->sub_device = (unsigned short)data;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if ((data = read_pci_data(devpath, "class")) == PCI_INVAL_DATA)
|
|
Packit Service |
2212bb |
return -ENODEV;
|
|
Packit Service |
2212bb |
pci->class = data;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Return IRQ class for given devpath */
|
|
Packit Service |
2212bb |
static int get_irq_class(const char *devpath)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
int irq_class = IRQ_NODEF;
|
|
Packit Service |
2212bb |
struct pci_info pci;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Get PCI info from sysfs */
|
|
Packit Service |
2212bb |
if (get_pci_info(devpath, &pci) < 0)
|
|
Packit Service |
2212bb |
return IRQ_NODEF;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Map PCI class code to irq class */
|
|
Packit Service |
2212bb |
irq_class = map_pci_irq_class(pci.class);
|
|
Packit Service |
2212bb |
if (irq_class < 0) {
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_WARNING, "Invalid PCI class code %d\n",
|
|
Packit Service |
2212bb |
pci.class);
|
|
Packit Service |
2212bb |
return IRQ_NODEF;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Reassign irq class for some buggy devices */
|
|
Packit Service |
2212bb |
apply_pci_quirks(&pci, &irq_class);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
return irq_class;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static gint compare_ints(gconstpointer a, gconstpointer b)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
const struct irq_info *ai = a;
|
|
Packit Service |
2212bb |
const struct irq_info *bi = b;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
return ai->irq - bi->irq;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static void add_banned_irq(int irq, GList **list)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
struct irq_info find, *new;
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
find.irq = irq;
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(*list, &find, compare_ints);
|
|
Packit Service |
2212bb |
if (entry)
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new = calloc(sizeof(struct irq_info), 1);
|
|
Packit Service |
2212bb |
if (!new) {
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_WARNING, "No memory to ban irq %d\n", irq);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new->irq = irq;
|
|
Packit Service |
2212bb |
new->flags |= IRQ_FLAG_BANNED;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
*list = g_list_append(*list, new);
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_INFO, "IRQ %d was BANNED.\n", irq);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void add_cl_banned_irq(int irq)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
add_banned_irq(irq, &cl_banned_irqs);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static int is_banned_irq(int irq)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
struct irq_info find;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
find.irq = irq;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(banned_irqs, &find, compare_ints);
|
|
Packit Service |
2212bb |
return entry ? 1:0;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
gint substr_find(gconstpointer a, gconstpointer b)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
if (strstr(b, a))
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
else
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static void add_banned_module(char *modname, GList **modlist)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
char *newmod;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(*modlist, modname, substr_find);
|
|
Packit Service |
2212bb |
if (entry)
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
newmod = strdup(modname);
|
|
Packit Service |
2212bb |
if (!newmod) {
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_WARNING, "No memory to ban module %s\n", modname);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
*modlist = g_list_append(*modlist, newmod);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void add_cl_banned_module(char *modname)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
add_banned_module(modname, &cl_banned_modules);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Inserts an irq_info struct into the intterupts_db list
|
|
Packit Service |
2212bb |
* devpath points to the device directory in sysfs for the
|
|
Packit Service |
2212bb |
* related device. NULL devpath means no sysfs entries for
|
|
Packit Service |
2212bb |
* this irq.
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
static struct irq_info *add_one_irq_to_db(const char *devpath, int irq, struct user_irq_policy *pol)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
int irq_class = IRQ_OTHER;
|
|
Packit Service |
2212bb |
struct irq_info *new, find;
|
|
Packit Service |
2212bb |
int numa_node;
|
|
Packit Service |
2212bb |
char path[PATH_MAX];
|
|
Packit Service |
2212bb |
FILE *fd;
|
|
Packit Service |
2212bb |
char *lcpu_mask;
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
ssize_t ret;
|
|
Packit Service |
2212bb |
size_t blen;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* First check to make sure this isn't a duplicate entry
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
find.irq = irq;
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(interrupts_db, &find, compare_ints);
|
|
Packit Service |
2212bb |
if (entry) {
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_INFO, "DROPPING DUPLICATE ENTRY FOR IRQ %d on path %s\n", irq, devpath);
|
|
Packit Service |
2212bb |
return NULL;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (is_banned_irq(irq)) {
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_INFO, "SKIPPING BANNED IRQ %d\n", irq);
|
|
Packit Service |
2212bb |
return NULL;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new = calloc(sizeof(struct irq_info), 1);
|
|
Packit Service |
2212bb |
if (!new)
|
|
Packit Service |
2212bb |
return NULL;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new->irq = irq;
|
|
Packit Service |
2212bb |
new->class = IRQ_OTHER;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
interrupts_db = g_list_append(interrupts_db, new);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Some special irqs have NULL devpath */
|
|
Packit Service |
2212bb |
if (devpath != NULL) {
|
|
Packit Service |
2212bb |
/* Map PCI class code to irq class */
|
|
Packit Service |
2212bb |
irq_class = get_irq_class(devpath);
|
|
Packit Service |
2212bb |
if (irq_class < 0)
|
|
Packit Service |
2212bb |
goto get_numa_node;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new->class = irq_class;
|
|
Packit Service |
2212bb |
if (pol->level >= 0)
|
|
Packit Service |
2212bb |
new->level = pol->level;
|
|
Packit Service |
2212bb |
else
|
|
Packit Service |
2212bb |
new->level = map_class_to_level[irq_class];
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
get_numa_node:
|
|
Packit Service |
2212bb |
numa_node = -1;
|
|
Packit Service |
2212bb |
if (numa_avail) {
|
|
Packit Service |
cda3a3 |
if (devpath)
|
|
Packit Service |
cda3a3 |
sprintf(path, "%s/numa_node", devpath);
|
|
Packit Service |
cda3a3 |
else
|
|
Packit Service |
cda3a3 |
sprintf(path, "/proc/irq/%i/node", irq);
|
|
Packit Service |
2212bb |
fd = fopen(path, "r");
|
|
Packit Service |
2212bb |
if (fd) {
|
|
Packit Service |
2212bb |
fscanf(fd, "%d", &numa_node);
|
|
Packit Service |
2212bb |
fclose(fd);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (pol->numa_node_set == 1)
|
|
Packit Service |
2212bb |
new->numa_node = get_numa_node(pol->numa_node);
|
|
Packit Service |
2212bb |
else
|
|
Packit Service |
2212bb |
new->numa_node = get_numa_node(numa_node);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
sprintf(path, "%s/local_cpus", devpath);
|
|
Packit Service |
2212bb |
fd = fopen(path, "r");
|
|
Packit Service |
2212bb |
if (!fd) {
|
|
Packit Service |
2212bb |
cpus_setall(new->cpumask);
|
|
Packit Service |
2212bb |
goto out;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
lcpu_mask = NULL;
|
|
Packit Service |
2212bb |
ret = getline(&lcpu_mask, &blen, fd);
|
|
Packit Service |
2212bb |
fclose(fd);
|
|
Packit Service |
2212bb |
if (ret <= 0) {
|
|
Packit Service |
2212bb |
cpus_setall(new->cpumask);
|
|
Packit Service |
2212bb |
} else {
|
|
Packit Service |
2212bb |
cpumask_parse_user(lcpu_mask, ret, new->cpumask);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
free(lcpu_mask);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
out:
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_INFO, "Adding IRQ %d to database\n", irq);
|
|
Packit Service |
2212bb |
return new;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static void parse_user_policy_key(char *buf, int irq, struct user_irq_policy *pol)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
char *key, *value, *end;
|
|
Packit Service |
2212bb |
char *levelvals[] = { "none", "package", "cache", "core" };
|
|
Packit Service |
2212bb |
int idx;
|
|
Packit Service |
2212bb |
int key_set = 1;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
key = buf;
|
|
Packit Service |
2212bb |
value = strchr(buf, '=');
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!value) {
|
|
Packit Service |
2212bb |
log(TO_SYSLOG, LOG_WARNING, "Bad format for policy, ignoring: %s\n", buf);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* NULL terminate the key and advance value to the start of the value
|
|
Packit Service |
2212bb |
* string
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
*value = '\0';
|
|
Packit Service |
2212bb |
value++;
|
|
Packit Service |
2212bb |
end = strchr(value, '\n');
|
|
Packit Service |
2212bb |
if (end)
|
|
Packit Service |
2212bb |
*end = '\0';
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!strcasecmp("ban", key)) {
|
|
Packit Service |
2212bb |
if (!strcasecmp("false", value))
|
|
Packit Service |
2212bb |
pol->ban = 0;
|
|
Packit Service |
2212bb |
else if (!strcasecmp("true", value))
|
|
Packit Service |
2212bb |
pol->ban = 1;
|
|
Packit Service |
2212bb |
else {
|
|
Packit Service |
2212bb |
key_set = 0;
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_WARNING, "Unknown value for ban policy: %s\n", value);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
} else if (!strcasecmp("balance_level", key)) {
|
|
Packit Service |
2212bb |
for (idx=0; idx<4; idx++) {
|
|
Packit Service |
2212bb |
if (!strcasecmp(levelvals[idx], value))
|
|
Packit Service |
2212bb |
break;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (idx>3) {
|
|
Packit Service |
2212bb |
key_set = 0;
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_WARNING, "Bad value for balance_level policy: %s\n", value);
|
|
Packit Service |
2212bb |
} else
|
|
Packit Service |
2212bb |
pol->level = idx;
|
|
Packit Service |
2212bb |
} else if (!strcasecmp("numa_node", key)) {
|
|
Packit Service |
2212bb |
idx = strtoul(value, NULL, 10);
|
|
Packit Service |
2212bb |
if (!get_numa_node(idx)) {
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_WARNING, "NUMA node %d doesn't exist\n",
|
|
Packit Service |
2212bb |
idx);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
pol->numa_node = idx;
|
|
Packit Service |
2212bb |
pol->numa_node_set = 1;
|
|
Packit Service |
2212bb |
} else {
|
|
Packit Service |
2212bb |
key_set = 0;
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_WARNING, "Unknown key returned, ignoring: %s\n", key);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (key_set)
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_INFO, "IRQ %d: Override %s to %s\n", irq, key, value);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Calls out to a possibly user defined script to get user assigned policy
|
|
Packit Service |
2212bb |
* aspects for a given irq. A value of -1 in a given field indicates no
|
|
Packit Service |
2212bb |
* policy was given and that system defaults should be used
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
static void get_irq_user_policy(char *path, int irq, struct user_irq_policy *pol)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
char *cmd;
|
|
Packit Service |
2212bb |
FILE *output;
|
|
Packit Service |
2212bb |
char buffer[128];
|
|
Packit Service |
2212bb |
char *brc;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
memset(pol, -1, sizeof(struct user_irq_policy));
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Return defaults if no script was given */
|
|
Packit Service |
2212bb |
if (!polscript)
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Use SYSFS_DIR for irq has no sysfs entries */
|
|
Packit Service |
2212bb |
if (!path)
|
|
Packit Service |
2212bb |
path = SYSFS_DIR;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
cmd = alloca(strlen(path)+strlen(polscript)+64);
|
|
Packit Service |
2212bb |
if (!cmd)
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
sprintf(cmd, "exec %s %s %d", polscript, path, irq);
|
|
Packit Service |
2212bb |
output = popen(cmd, "r");
|
|
Packit Service |
2212bb |
if (!output) {
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_WARNING, "Unable to execute user policy script %s\n", polscript);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
while(!feof(output)) {
|
|
Packit Service |
2212bb |
brc = fgets(buffer, 128, output);
|
|
Packit Service |
2212bb |
if (brc)
|
|
Packit Service |
2212bb |
parse_user_policy_key(brc, irq, pol);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
pclose(output);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static int check_for_module_ban(char *name)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(cl_banned_modules, name, substr_find);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (entry)
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
else
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static int check_for_irq_ban(char *path __attribute__((unused)), int irq, GList *proc_interrupts)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
struct irq_info find, *res;
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Check to see if we banned this irq on the command line
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
find.irq = irq;
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(cl_banned_irqs, &find, compare_ints);
|
|
Packit Service |
2212bb |
if (entry)
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Check to see if we banned module which the irq belongs to.
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(proc_interrupts, &find, compare_ints);
|
|
Packit Service |
2212bb |
if (entry) {
|
|
Packit Service |
2212bb |
res = entry->data;
|
|
Packit Service |
2212bb |
if (check_for_module_ban(res->name))
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
#ifdef INCLUDE_BANSCRIPT
|
|
Packit Service |
2212bb |
char *cmd;
|
|
Packit Service |
2212bb |
int rc;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!banscript)
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!path)
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
cmd = alloca(strlen(path)+strlen(banscript)+32);
|
|
Packit Service |
2212bb |
if (!cmd)
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
sprintf(cmd, "%s %s %d > /dev/null",banscript, path, irq);
|
|
Packit Service |
2212bb |
rc = system(cmd);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* The system command itself failed
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
if (rc == -1) {
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_WARNING, "%s failed, please check the --banscript option\n", cmd);
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (WEXITSTATUS(rc)) {
|
|
Packit Service |
2212bb |
log(TO_ALL, LOG_INFO, "irq %d is baned by %s\n", irq, banscript);
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
#endif
|
|
Packit Service |
2212bb |
return 0;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Figures out which interrupt(s) relate to the device we"re looking at in dirname
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
static void build_one_dev_entry(const char *dirname, GList *tmp_irqs)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
struct dirent *entry;
|
|
Packit Service |
2212bb |
DIR *msidir;
|
|
Packit Service |
2212bb |
FILE *fd;
|
|
Packit Service |
2212bb |
int irqnum;
|
|
Packit Service |
2212bb |
struct irq_info *new;
|
|
Packit Service |
2212bb |
char path[PATH_MAX];
|
|
Packit Service |
2212bb |
char devpath[PATH_MAX];
|
|
Packit Service |
2212bb |
struct user_irq_policy pol;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
sprintf(path, "%s/%s/msi_irqs", SYSDEV_DIR, dirname);
|
|
Packit Service |
2212bb |
sprintf(devpath, "%s/%s", SYSDEV_DIR, dirname);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
msidir = opendir(path);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (msidir) {
|
|
Packit Service |
2212bb |
do {
|
|
Packit Service |
2212bb |
entry = readdir(msidir);
|
|
Packit Service |
2212bb |
if (!entry)
|
|
Packit Service |
2212bb |
break;
|
|
Packit Service |
2212bb |
irqnum = strtol(entry->d_name, NULL, 10);
|
|
Packit Service |
2212bb |
if (irqnum) {
|
|
Packit Service |
2212bb |
new = get_irq_info(irqnum);
|
|
Packit Service |
2212bb |
if (new)
|
|
Packit Service |
2212bb |
continue;
|
|
Packit Service |
2212bb |
get_irq_user_policy(devpath, irqnum, &pol;;
|
|
Packit Service |
2212bb |
if ((pol.ban == 1) || (check_for_irq_ban(devpath, irqnum, tmp_irqs))) {
|
|
Packit Service |
2212bb |
add_banned_irq(irqnum, &banned_irqs);
|
|
Packit Service |
2212bb |
continue;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
new = add_one_irq_to_db(devpath, irqnum, &pol;;
|
|
Packit Service |
2212bb |
if (!new)
|
|
Packit Service |
2212bb |
continue;
|
|
Packit Service |
2212bb |
new->type = IRQ_TYPE_MSIX;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
} while (entry != NULL);
|
|
Packit Service |
2212bb |
closedir(msidir);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
sprintf(path, "%s/%s/irq", SYSDEV_DIR, dirname);
|
|
Packit Service |
2212bb |
fd = fopen(path, "r");
|
|
Packit Service |
2212bb |
if (!fd)
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
if (fscanf(fd, "%d", &irqnum) < 0)
|
|
Packit Service |
2212bb |
goto done;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* no pci device has irq 0
|
|
Packit Service |
2212bb |
* irq 255 is invalid on x86/x64 architectures
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
#if defined(__i386__) || defined(__x86_64__)
|
|
Packit Service |
2212bb |
if (irqnum && irqnum != 255) {
|
|
Packit Service |
2212bb |
#else
|
|
Packit Service |
2212bb |
if (irqnum) {
|
|
Packit Service |
2212bb |
#endif
|
|
Packit Service |
2212bb |
new = get_irq_info(irqnum);
|
|
Packit Service |
2212bb |
if (new)
|
|
Packit Service |
2212bb |
goto done;
|
|
Packit Service |
2212bb |
get_irq_user_policy(devpath, irqnum, &pol;;
|
|
Packit Service |
2212bb |
if ((pol.ban == 1) || (check_for_irq_ban(path, irqnum, tmp_irqs))) {
|
|
Packit Service |
2212bb |
add_banned_irq(irqnum, &banned_irqs);
|
|
Packit Service |
2212bb |
goto done;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new = add_one_irq_to_db(devpath, irqnum, &pol;;
|
|
Packit Service |
2212bb |
if (!new)
|
|
Packit Service |
2212bb |
goto done;
|
|
Packit Service |
2212bb |
new->type = IRQ_TYPE_LEGACY;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
done:
|
|
Packit Service |
2212bb |
fclose(fd);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static void free_irq(struct irq_info *info, void *data __attribute__((unused)))
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
free(info);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void free_irq_db(void)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
for_each_irq(NULL, free_irq, NULL);
|
|
Packit Service |
2212bb |
g_list_free(interrupts_db);
|
|
Packit Service |
2212bb |
interrupts_db = NULL;
|
|
Packit Service |
2212bb |
for_each_irq(banned_irqs, free_irq, NULL);
|
|
Packit Service |
2212bb |
g_list_free(banned_irqs);
|
|
Packit Service |
2212bb |
banned_irqs = NULL;
|
|
Packit Service |
2212bb |
g_list_free(rebalance_irq_list);
|
|
Packit Service |
2212bb |
rebalance_irq_list = NULL;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void free_cl_opts(void)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
g_list_free_full(cl_banned_modules, free);
|
|
Packit Service |
2212bb |
g_list_free_full(cl_banned_irqs, free);
|
|
Packit Service |
2212bb |
g_list_free(banned_irqs);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static void add_new_irq(int irq, struct irq_info *hint, GList *proc_interrupts)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
struct irq_info *new;
|
|
Packit Service |
2212bb |
struct user_irq_policy pol;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new = get_irq_info(irq);
|
|
Packit Service |
2212bb |
if (new)
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/* Set NULL devpath for the irq has no sysfs entries */
|
|
Packit Service |
2212bb |
get_irq_user_policy(NULL, irq, &pol;;
|
|
Packit Service |
2212bb |
if ((pol.ban == 1) || check_for_irq_ban(NULL, irq, proc_interrupts)) { /*FIXME*/
|
|
Packit Service |
2212bb |
add_banned_irq(irq, &banned_irqs);
|
|
Packit Service |
2212bb |
new = get_irq_info(irq);
|
|
Packit Service |
2212bb |
} else
|
|
Packit Service |
2212bb |
new = add_one_irq_to_db(NULL, irq, &pol;;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!new) {
|
|
Packit Service |
2212bb |
log(TO_CONSOLE, LOG_WARNING, "add_new_irq: Failed to add irq %d\n", irq);
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
/*
|
|
Packit Service |
2212bb |
* Override some of the new irq defaults here
|
|
Packit Service |
2212bb |
*/
|
|
Packit Service |
2212bb |
if (hint) {
|
|
Packit Service |
2212bb |
new->type = hint->type;
|
|
Packit Service |
2212bb |
new->class = hint->class;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
new->level = map_class_to_level[new->class];
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static void add_missing_irq(struct irq_info *info, void *attr)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
struct irq_info *lookup = get_irq_info(info->irq);
|
|
Packit Service |
2212bb |
GList *proc_interrupts = (GList *) attr;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!lookup)
|
|
Packit Service |
2212bb |
add_new_irq(info->irq, info, proc_interrupts);
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void rebuild_irq_db(void)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
DIR *devdir;
|
|
Packit Service |
2212bb |
struct dirent *entry;
|
|
Packit Service |
2212bb |
GList *tmp_irqs = NULL;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
free_irq_db();
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
tmp_irqs = collect_full_irq_list();
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
devdir = opendir(SYSDEV_DIR);
|
|
Packit Service |
2212bb |
if (!devdir)
|
|
Packit Service |
2212bb |
goto free;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
do {
|
|
Packit Service |
2212bb |
entry = readdir(devdir);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!entry)
|
|
Packit Service |
2212bb |
break;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
build_one_dev_entry(entry->d_name, tmp_irqs);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
} while (entry != NULL);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
closedir(devdir);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
for_each_irq(tmp_irqs, add_missing_irq, interrupts_db);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
free:
|
|
Packit Service |
2212bb |
g_list_free_full(tmp_irqs, free);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void for_each_irq(GList *list, void (*cb)(struct irq_info *info, void *data), void *data)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
GList *entry = g_list_first(list ? list : interrupts_db);
|
|
Packit Service |
2212bb |
GList *next;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
while (entry) {
|
|
Packit Service |
2212bb |
next = g_list_next(entry);
|
|
Packit Service |
2212bb |
cb(entry->data, data);
|
|
Packit Service |
2212bb |
entry = next;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
struct irq_info *get_irq_info(int irq)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
struct irq_info find;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
find.irq = irq;
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(interrupts_db, &find, compare_ints);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!entry)
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(banned_irqs, &find, compare_ints);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
return entry ? entry->data : NULL;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void migrate_irq(GList **from, GList **to, struct irq_info *info)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
GList *entry;
|
|
Packit Service |
2212bb |
struct irq_info find, *tmp;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
find.irq = info->irq;
|
|
Packit Service |
2212bb |
entry = g_list_find_custom(*from, &find, compare_ints);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (!entry)
|
|
Packit Service |
2212bb |
return;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
tmp = entry->data;
|
|
Packit Service |
2212bb |
*from = g_list_delete_link(*from, entry);
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
*to = g_list_append(*to, tmp);
|
|
Packit Service |
2212bb |
info->moved = 1;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
static gint sort_irqs(gconstpointer A, gconstpointer B)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
struct irq_info *a, *b;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
a = (struct irq_info*)A;
|
|
Packit Service |
2212bb |
b = (struct irq_info*)B;
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
if (a->class < b->class)
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
if (a->class > b->class)
|
|
Packit Service |
2212bb |
return -1;
|
|
Packit Service |
2212bb |
if (a->load < b->load)
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
if (a->load > b->load)
|
|
Packit Service |
2212bb |
return -1;
|
|
Packit Service |
2212bb |
if (a < b)
|
|
Packit Service |
2212bb |
return 1;
|
|
Packit Service |
2212bb |
return -1;
|
|
Packit Service |
2212bb |
}
|
|
Packit Service |
2212bb |
|
|
Packit Service |
2212bb |
void sort_irq_list(GList **list)
|
|
Packit Service |
2212bb |
{
|
|
Packit Service |
2212bb |
*list = g_list_sort(*list, sort_irqs);
|
|
Packit Service |
2212bb |
}
|