diff options
| author | Corey Minyard <minyard@acm.org> | 2006-12-06 23:41:07 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:47 -0500 |
| commit | b361e27bba261ba59c73df464fa640f7c0fe3553 (patch) | |
| tree | 4c457c471eb42be1fbcc9e76989e275fa8e023df | |
| parent | 15c62e10bb49eebf3da2b010a9196f5095947b0b (diff) | |
[PATCH] IPMI: system interface hotplug
Add the ability to hot add and remove interfaces in the ipmi_si driver. Any
users who have the device open will get errors if they try to send a message.
Signed-off-by: Corey Minyard <minyard@acm.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | Documentation/IPMI.txt | 25 | ||||
| -rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 320 |
2 files changed, 322 insertions, 23 deletions
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt index 9101cbf2d883..24dc3fcf1594 100644 --- a/Documentation/IPMI.txt +++ b/Documentation/IPMI.txt | |||
| @@ -365,6 +365,7 @@ You can change this at module load time (for a module) with: | |||
| 365 | regshifts=<shift1>,<shift2>,... | 365 | regshifts=<shift1>,<shift2>,... |
| 366 | slave_addrs=<addr1>,<addr2>,... | 366 | slave_addrs=<addr1>,<addr2>,... |
| 367 | force_kipmid=<enable1>,<enable2>,... | 367 | force_kipmid=<enable1>,<enable2>,... |
| 368 | unload_when_empty=[0|1] | ||
| 368 | 369 | ||
| 369 | Each of these except si_trydefaults is a list, the first item for the | 370 | Each of these except si_trydefaults is a list, the first item for the |
| 370 | first interface, second item for the second interface, etc. | 371 | first interface, second item for the second interface, etc. |
| @@ -416,6 +417,11 @@ by the driver, but systems with broken interrupts might need an enable, | |||
| 416 | or users that don't want the daemon (don't need the performance, don't | 417 | or users that don't want the daemon (don't need the performance, don't |
| 417 | want the CPU hit) can disable it. | 418 | want the CPU hit) can disable it. |
| 418 | 419 | ||
| 420 | If unload_when_empty is set to 1, the driver will be unloaded if it | ||
| 421 | doesn't find any interfaces or all the interfaces fail to work. The | ||
| 422 | default is one. Setting to 0 is useful with the hotmod, but is | ||
| 423 | obviously only useful for modules. | ||
| 424 | |||
| 419 | When compiled into the kernel, the parameters can be specified on the | 425 | When compiled into the kernel, the parameters can be specified on the |
| 420 | kernel command line as: | 426 | kernel command line as: |
| 421 | 427 | ||
| @@ -441,6 +447,25 @@ have high-res timers enabled in the kernel and you don't have | |||
| 441 | interrupts enabled, the driver will run VERY slowly. Don't blame me, | 447 | interrupts enabled, the driver will run VERY slowly. Don't blame me, |
| 442 | these interfaces suck. | 448 | these interfaces suck. |
| 443 | 449 | ||
| 450 | The driver supports a hot add and remove of interfaces. This way, | ||
| 451 | interfaces can be added or removed after the kernel is up and running. | ||
| 452 | This is done using /sys/modules/ipmi_si/hotmod, which is a write-only | ||
| 453 | parameter. You write a string to this interface. The string has the | ||
| 454 | format: | ||
| 455 | <op1>[:op2[:op3...]] | ||
| 456 | The "op"s are: | ||
| 457 | add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]] | ||
| 458 | You can specify more than one interface on the line. The "opt"s are: | ||
| 459 | rsp=<regspacing> | ||
| 460 | rsi=<regsize> | ||
| 461 | rsh=<regshift> | ||
| 462 | irq=<irq> | ||
| 463 | ipmb=<ipmb slave addr> | ||
| 464 | and these have the same meanings as discussed above. Note that you | ||
| 465 | can also use this on the kernel command line for a more compact format | ||
| 466 | for specifying an interface. Note that when removing an interface, | ||
| 467 | only the first three parameters (si type, address type, and address) | ||
| 468 | are used for the comparison. Any options are ignored for removing. | ||
| 444 | 469 | ||
| 445 | The SMBus Driver | 470 | The SMBus Driver |
| 446 | ---------------- | 471 | ---------------- |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index bedd76310045..8b36b5036391 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
| @@ -61,6 +61,10 @@ | |||
| 61 | #include "ipmi_si_sm.h" | 61 | #include "ipmi_si_sm.h" |
| 62 | #include <linux/init.h> | 62 | #include <linux/init.h> |
| 63 | #include <linux/dmi.h> | 63 | #include <linux/dmi.h> |
| 64 | #include <linux/string.h> | ||
| 65 | #include <linux/ctype.h> | ||
| 66 | |||
| 67 | #define PFX "ipmi_si: " | ||
| 64 | 68 | ||
| 65 | /* Measure times between events in the driver. */ | 69 | /* Measure times between events in the driver. */ |
| 66 | #undef DEBUG_TIMING | 70 | #undef DEBUG_TIMING |
| @@ -92,7 +96,7 @@ enum si_intf_state { | |||
| 92 | enum si_type { | 96 | enum si_type { |
| 93 | SI_KCS, SI_SMIC, SI_BT | 97 | SI_KCS, SI_SMIC, SI_BT |
| 94 | }; | 98 | }; |
| 95 | static char *si_to_str[] = { "KCS", "SMIC", "BT" }; | 99 | static char *si_to_str[] = { "kcs", "smic", "bt" }; |
| 96 | 100 | ||
| 97 | #define DEVICE_NAME "ipmi_si" | 101 | #define DEVICE_NAME "ipmi_si" |
| 98 | 102 | ||
| @@ -222,7 +226,10 @@ struct smi_info | |||
| 222 | static int force_kipmid[SI_MAX_PARMS]; | 226 | static int force_kipmid[SI_MAX_PARMS]; |
| 223 | static int num_force_kipmid; | 227 | static int num_force_kipmid; |
| 224 | 228 | ||
| 229 | static int unload_when_empty = 1; | ||
| 230 | |||
| 225 | static int try_smi_init(struct smi_info *smi); | 231 | static int try_smi_init(struct smi_info *smi); |
| 232 | static void cleanup_one_si(struct smi_info *to_clean); | ||
| 226 | 233 | ||
| 227 | static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); | 234 | static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); |
| 228 | static int register_xaction_notifier(struct notifier_block * nb) | 235 | static int register_xaction_notifier(struct notifier_block * nb) |
| @@ -247,7 +254,7 @@ static void return_hosed_msg(struct smi_info *smi_info) | |||
| 247 | /* Make it a reponse */ | 254 | /* Make it a reponse */ |
| 248 | msg->rsp[0] = msg->data[0] | 4; | 255 | msg->rsp[0] = msg->data[0] | 4; |
| 249 | msg->rsp[1] = msg->data[1]; | 256 | msg->rsp[1] = msg->data[1]; |
| 250 | msg->rsp[2] = 0xFF; /* Unknown error. */ | 257 | msg->rsp[2] = IPMI_ERR_UNSPECIFIED; |
| 251 | msg->rsp_size = 3; | 258 | msg->rsp_size = 3; |
| 252 | 259 | ||
| 253 | smi_info->curr_msg = NULL; | 260 | smi_info->curr_msg = NULL; |
| @@ -716,6 +723,15 @@ static void sender(void *send_info, | |||
| 716 | struct timeval t; | 723 | struct timeval t; |
| 717 | #endif | 724 | #endif |
| 718 | 725 | ||
| 726 | if (atomic_read(&smi_info->stop_operation)) { | ||
| 727 | msg->rsp[0] = msg->data[0] | 4; | ||
| 728 | msg->rsp[1] = msg->data[1]; | ||
| 729 | msg->rsp[2] = IPMI_ERR_UNSPECIFIED; | ||
| 730 | msg->rsp_size = 3; | ||
| 731 | deliver_recv_msg(smi_info, msg); | ||
| 732 | return; | ||
| 733 | } | ||
| 734 | |||
| 719 | spin_lock_irqsave(&(smi_info->msg_lock), flags); | 735 | spin_lock_irqsave(&(smi_info->msg_lock), flags); |
| 720 | #ifdef DEBUG_TIMING | 736 | #ifdef DEBUG_TIMING |
| 721 | do_gettimeofday(&t); | 737 | do_gettimeofday(&t); |
| @@ -819,6 +835,9 @@ static void request_events(void *send_info) | |||
| 819 | { | 835 | { |
| 820 | struct smi_info *smi_info = send_info; | 836 | struct smi_info *smi_info = send_info; |
| 821 | 837 | ||
| 838 | if (atomic_read(&smi_info->stop_operation)) | ||
| 839 | return; | ||
| 840 | |||
| 822 | atomic_set(&smi_info->req_events, 1); | 841 | atomic_set(&smi_info->req_events, 1); |
| 823 | } | 842 | } |
| 824 | 843 | ||
| @@ -1003,6 +1022,16 @@ static int num_regshifts = 0; | |||
| 1003 | static int slave_addrs[SI_MAX_PARMS]; | 1022 | static int slave_addrs[SI_MAX_PARMS]; |
| 1004 | static int num_slave_addrs = 0; | 1023 | static int num_slave_addrs = 0; |
| 1005 | 1024 | ||
| 1025 | #define IPMI_IO_ADDR_SPACE 0 | ||
| 1026 | #define IPMI_MEM_ADDR_SPACE 1 | ||
| 1027 | static char *addr_space_to_str[] = { "I/O", "mem" }; | ||
| 1028 | |||
| 1029 | static int hotmod_handler(const char *val, struct kernel_param *kp); | ||
| 1030 | |||
| 1031 | module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); | ||
| 1032 | MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" | ||
| 1033 | " Documentation/IPMI.txt in the kernel sources for the" | ||
| 1034 | " gory details."); | ||
| 1006 | 1035 | ||
| 1007 | module_param_named(trydefaults, si_trydefaults, bool, 0); | 1036 | module_param_named(trydefaults, si_trydefaults, bool, 0); |
| 1008 | MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the" | 1037 | MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the" |
| @@ -1054,12 +1083,12 @@ module_param_array(force_kipmid, int, &num_force_kipmid, 0); | |||
| 1054 | MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" | 1083 | MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" |
| 1055 | " disabled(0). Normally the IPMI driver auto-detects" | 1084 | " disabled(0). Normally the IPMI driver auto-detects" |
| 1056 | " this, but the value may be overridden by this parm."); | 1085 | " this, but the value may be overridden by this parm."); |
| 1086 | module_param(unload_when_empty, int, 0); | ||
| 1087 | MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are" | ||
| 1088 | " specified or found, default is 1. Setting to 0" | ||
| 1089 | " is useful for hot add of devices using hotmod."); | ||
| 1057 | 1090 | ||
| 1058 | 1091 | ||
| 1059 | #define IPMI_IO_ADDR_SPACE 0 | ||
| 1060 | #define IPMI_MEM_ADDR_SPACE 1 | ||
| 1061 | static char *addr_space_to_str[] = { "I/O", "memory" }; | ||
| 1062 | |||
| 1063 | static void std_irq_cleanup(struct smi_info *info) | 1092 | static void std_irq_cleanup(struct smi_info *info) |
| 1064 | { | 1093 | { |
| 1065 | if (info->si_type == SI_BT) | 1094 | if (info->si_type == SI_BT) |
| @@ -1333,6 +1362,234 @@ static int mem_setup(struct smi_info *info) | |||
| 1333 | return 0; | 1362 | return 0; |
| 1334 | } | 1363 | } |
| 1335 | 1364 | ||
| 1365 | /* | ||
| 1366 | * Parms come in as <op1>[:op2[:op3...]]. ops are: | ||
| 1367 | * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]] | ||
| 1368 | * Options are: | ||
| 1369 | * rsp=<regspacing> | ||
| 1370 | * rsi=<regsize> | ||
| 1371 | * rsh=<regshift> | ||
| 1372 | * irq=<irq> | ||
| 1373 | * ipmb=<ipmb addr> | ||
| 1374 | */ | ||
| 1375 | enum hotmod_op { HM_ADD, HM_REMOVE }; | ||
| 1376 | struct hotmod_vals { | ||
| 1377 | char *name; | ||
| 1378 | int val; | ||
| 1379 | }; | ||
| 1380 | static struct hotmod_vals hotmod_ops[] = { | ||
| 1381 | { "add", HM_ADD }, | ||
| 1382 | { "remove", HM_REMOVE }, | ||
| 1383 | { NULL } | ||
| 1384 | }; | ||
| 1385 | static struct hotmod_vals hotmod_si[] = { | ||
| 1386 | { "kcs", SI_KCS }, | ||
| 1387 | { "smic", SI_SMIC }, | ||
| 1388 | { "bt", SI_BT }, | ||
| 1389 | { NULL } | ||
| 1390 | }; | ||
| 1391 | static struct hotmod_vals hotmod_as[] = { | ||
| 1392 | { "mem", IPMI_MEM_ADDR_SPACE }, | ||
| 1393 | { "i/o", IPMI_IO_ADDR_SPACE }, | ||
| 1394 | { NULL } | ||
| 1395 | }; | ||
| 1396 | static int ipmi_strcasecmp(const char *s1, const char *s2) | ||
| 1397 | { | ||
| 1398 | while (*s1 || *s2) { | ||
| 1399 | if (!*s1) | ||
| 1400 | return -1; | ||
| 1401 | if (!*s2) | ||
| 1402 | return 1; | ||
| 1403 | if (*s1 != *s2) | ||
| 1404 | return *s1 - *s2; | ||
| 1405 | s1++; | ||
| 1406 | s2++; | ||
| 1407 | } | ||
| 1408 | return 0; | ||
| 1409 | } | ||
| 1410 | static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr) | ||
| 1411 | { | ||
| 1412 | char *s; | ||
| 1413 | int i; | ||
| 1414 | |||
| 1415 | s = strchr(*curr, ','); | ||
| 1416 | if (!s) { | ||
| 1417 | printk(KERN_WARNING PFX "No hotmod %s given.\n", name); | ||
| 1418 | return -EINVAL; | ||
| 1419 | } | ||
| 1420 | *s = '\0'; | ||
| 1421 | s++; | ||
| 1422 | for (i = 0; hotmod_ops[i].name; i++) { | ||
| 1423 | if (ipmi_strcasecmp(*curr, v[i].name) == 0) { | ||
| 1424 | *val = v[i].val; | ||
| 1425 | *curr = s; | ||
| 1426 | return 0; | ||
| 1427 | } | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | printk(KERN_WARNING PFX "Invalid hotmod %s '%s'\n", name, *curr); | ||
| 1431 | return -EINVAL; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | static int hotmod_handler(const char *val, struct kernel_param *kp) | ||
| 1435 | { | ||
| 1436 | char *str = kstrdup(val, GFP_KERNEL); | ||
| 1437 | int rv = -EINVAL; | ||
| 1438 | char *next, *curr, *s, *n, *o; | ||
| 1439 | enum hotmod_op op; | ||
| 1440 | enum si_type si_type; | ||
| 1441 | int addr_space; | ||
| 1442 | unsigned long addr; | ||
| 1443 | int regspacing; | ||
| 1444 | int regsize; | ||
| 1445 | int regshift; | ||
| 1446 | int irq; | ||
| 1447 | int ipmb; | ||
| 1448 | int ival; | ||
| 1449 | struct smi_info *info; | ||
| 1450 | |||
| 1451 | if (!str) | ||
| 1452 | return -ENOMEM; | ||
| 1453 | |||
| 1454 | /* Kill any trailing spaces, as we can get a "\n" from echo. */ | ||
| 1455 | ival = strlen(str) - 1; | ||
| 1456 | while ((ival >= 0) && isspace(str[ival])) { | ||
| 1457 | str[ival] = '\0'; | ||
| 1458 | ival--; | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | for (curr = str; curr; curr = next) { | ||
| 1462 | regspacing = 1; | ||
| 1463 | regsize = 1; | ||
| 1464 | regshift = 0; | ||
| 1465 | irq = 0; | ||
| 1466 | ipmb = 0x20; | ||
| 1467 | |||
| 1468 | next = strchr(curr, ':'); | ||
| 1469 | if (next) { | ||
| 1470 | *next = '\0'; | ||
| 1471 | next++; | ||
| 1472 | } | ||
| 1473 | |||
| 1474 | rv = parse_str(hotmod_ops, &ival, "operation", &curr); | ||
| 1475 | if (rv) | ||
| 1476 | break; | ||
| 1477 | op = ival; | ||
| 1478 | |||
| 1479 | rv = parse_str(hotmod_si, &ival, "interface type", &curr); | ||
| 1480 | if (rv) | ||
| 1481 | break; | ||
| 1482 | si_type = ival; | ||
| 1483 | |||
| 1484 | rv = parse_str(hotmod_as, &addr_space, "address space", &curr); | ||
| 1485 | if (rv) | ||
| 1486 | break; | ||
| 1487 | |||
| 1488 | s = strchr(curr, ','); | ||
| 1489 | if (s) { | ||
| 1490 | *s = '\0'; | ||
| 1491 | s++; | ||
| 1492 | } | ||
| 1493 | addr = simple_strtoul(curr, &n, 0); | ||
| 1494 | if ((*n != '\0') || (*curr == '\0')) { | ||
| 1495 | printk(KERN_WARNING PFX "Invalid hotmod address" | ||
| 1496 | " '%s'\n", curr); | ||
| 1497 | break; | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | while (s) { | ||
| 1501 | curr = s; | ||
| 1502 | s = strchr(curr, ','); | ||
| 1503 | if (s) { | ||
| 1504 | *s = '\0'; | ||
| 1505 | s++; | ||
| 1506 | } | ||
| 1507 | o = strchr(curr, '='); | ||
| 1508 | if (o) { | ||
| 1509 | *o = '\0'; | ||
| 1510 | o++; | ||
| 1511 | } | ||
| 1512 | #define HOTMOD_INT_OPT(name, val) \ | ||
| 1513 | if (ipmi_strcasecmp(curr, name) == 0) { \ | ||
| 1514 | if (!o) { \ | ||
| 1515 | printk(KERN_WARNING PFX \ | ||
| 1516 | "No option given for '%s'\n", \ | ||
| 1517 | curr); \ | ||
| 1518 | goto out; \ | ||
| 1519 | } \ | ||
| 1520 | val = simple_strtoul(o, &n, 0); \ | ||
| 1521 | if ((*n != '\0') || (*o == '\0')) { \ | ||
| 1522 | printk(KERN_WARNING PFX \ | ||
| 1523 | "Bad option given for '%s'\n", \ | ||
| 1524 | curr); \ | ||
| 1525 | goto out; \ | ||
| 1526 | } \ | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | HOTMOD_INT_OPT("rsp", regspacing) | ||
| 1530 | else HOTMOD_INT_OPT("rsi", regsize) | ||
| 1531 | else HOTMOD_INT_OPT("rsh", regshift) | ||
| 1532 | else HOTMOD_INT_OPT("irq", irq) | ||
| 1533 | else HOTMOD_INT_OPT("ipmb", ipmb) | ||
| 1534 | else { | ||
| 1535 | printk(KERN_WARNING PFX | ||
| 1536 | "Invalid hotmod option '%s'\n", | ||
| 1537 | curr); | ||
| 1538 | goto out; | ||
| 1539 | } | ||
| 1540 | #undef HOTMOD_INT_OPT | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | if (op == HM_ADD) { | ||
| 1544 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
| 1545 | if (!info) { | ||
| 1546 | rv = -ENOMEM; | ||
| 1547 | goto out; | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | info->addr_source = "hotmod"; | ||
| 1551 | info->si_type = si_type; | ||
| 1552 | info->io.addr_data = addr; | ||
| 1553 | info->io.addr_type = addr_space; | ||
| 1554 | if (addr_space == IPMI_MEM_ADDR_SPACE) | ||
| 1555 | info->io_setup = mem_setup; | ||
| 1556 | else | ||
| 1557 | info->io_setup = port_setup; | ||
| 1558 | |||
| 1559 | info->io.addr = NULL; | ||
| 1560 | info->io.regspacing = regspacing; | ||
| 1561 | if (!info->io.regspacing) | ||
| 1562 | info->io.regspacing = DEFAULT_REGSPACING; | ||
| 1563 | info->io.regsize = regsize; | ||
| 1564 | if (!info->io.regsize) | ||
| 1565 | info->io.regsize = DEFAULT_REGSPACING; | ||
| 1566 | info->io.regshift = regshift; | ||
| 1567 | info->irq = irq; | ||
| 1568 | if (info->irq) | ||
| 1569 | info->irq_setup = std_irq_setup; | ||
| 1570 | info->slave_addr = ipmb; | ||
| 1571 | |||
| 1572 | try_smi_init(info); | ||
| 1573 | } else { | ||
| 1574 | /* remove */ | ||
| 1575 | struct smi_info *e, *tmp_e; | ||
| 1576 | |||
| 1577 | mutex_lock(&smi_infos_lock); | ||
| 1578 | list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { | ||
| 1579 | if (e->io.addr_type != addr_space) | ||
| 1580 | continue; | ||
| 1581 | if (e->si_type != si_type) | ||
| 1582 | continue; | ||
| 1583 | if (e->io.addr_data == addr) | ||
| 1584 | cleanup_one_si(e); | ||
| 1585 | } | ||
| 1586 | mutex_unlock(&smi_infos_lock); | ||
| 1587 | } | ||
| 1588 | } | ||
| 1589 | out: | ||
| 1590 | kfree(str); | ||
| 1591 | return rv; | ||
| 1592 | } | ||
| 1336 | 1593 | ||
| 1337 | static __devinit void hardcode_find_bmc(void) | 1594 | static __devinit void hardcode_find_bmc(void) |
| 1338 | { | 1595 | { |
| @@ -1349,11 +1606,11 @@ static __devinit void hardcode_find_bmc(void) | |||
| 1349 | 1606 | ||
| 1350 | info->addr_source = "hardcoded"; | 1607 | info->addr_source = "hardcoded"; |
| 1351 | 1608 | ||
| 1352 | if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { | 1609 | if (!si_type[i] || ipmi_strcasecmp(si_type[i], "kcs") == 0) { |
| 1353 | info->si_type = SI_KCS; | 1610 | info->si_type = SI_KCS; |
| 1354 | } else if (strcmp(si_type[i], "smic") == 0) { | 1611 | } else if (ipmi_strcasecmp(si_type[i], "smic") == 0) { |
| 1355 | info->si_type = SI_SMIC; | 1612 | info->si_type = SI_SMIC; |
| 1356 | } else if (strcmp(si_type[i], "bt") == 0) { | 1613 | } else if (ipmi_strcasecmp(si_type[i], "bt") == 0) { |
| 1357 | info->si_type = SI_BT; | 1614 | info->si_type = SI_BT; |
| 1358 | } else { | 1615 | } else { |
| 1359 | printk(KERN_WARNING | 1616 | printk(KERN_WARNING |
| @@ -1968,19 +2225,9 @@ static int try_get_dev_id(struct smi_info *smi_info) | |||
| 1968 | static int type_file_read_proc(char *page, char **start, off_t off, | 2225 | static int type_file_read_proc(char *page, char **start, off_t off, |
| 1969 | int count, int *eof, void *data) | 2226 | int count, int *eof, void *data) |
| 1970 | { | 2227 | { |
| 1971 | char *out = (char *) page; | ||
| 1972 | struct smi_info *smi = data; | 2228 | struct smi_info *smi = data; |
| 1973 | 2229 | ||
| 1974 | switch (smi->si_type) { | 2230 | return sprintf(page, "%s\n", si_to_str[smi->si_type]); |
| 1975 | case SI_KCS: | ||
| 1976 | return sprintf(out, "kcs\n"); | ||
| 1977 | case SI_SMIC: | ||
| 1978 | return sprintf(out, "smic\n"); | ||
| 1979 | case SI_BT: | ||
| 1980 | return sprintf(out, "bt\n"); | ||
| 1981 | default: | ||
| 1982 | return 0; | ||
| 1983 | } | ||
| 1984 | } | 2231 | } |
| 1985 | 2232 | ||
| 1986 | static int stat_file_read_proc(char *page, char **start, off_t off, | 2233 | static int stat_file_read_proc(char *page, char **start, off_t off, |
| @@ -2016,7 +2263,24 @@ static int stat_file_read_proc(char *page, char **start, off_t off, | |||
| 2016 | out += sprintf(out, "incoming_messages: %ld\n", | 2263 | out += sprintf(out, "incoming_messages: %ld\n", |
| 2017 | smi->incoming_messages); | 2264 | smi->incoming_messages); |
| 2018 | 2265 | ||
| 2019 | return (out - ((char *) page)); | 2266 | return out - page; |
| 2267 | } | ||
| 2268 | |||
| 2269 | static int param_read_proc(char *page, char **start, off_t off, | ||
| 2270 | int count, int *eof, void *data) | ||
| 2271 | { | ||
| 2272 | struct smi_info *smi = data; | ||
| 2273 | |||
| 2274 | return sprintf(page, | ||
| 2275 | "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n", | ||
| 2276 | si_to_str[smi->si_type], | ||
| 2277 | addr_space_to_str[smi->io.addr_type], | ||
| 2278 | smi->io.addr_data, | ||
| 2279 | smi->io.regspacing, | ||
| 2280 | smi->io.regsize, | ||
| 2281 | smi->io.regshift, | ||
| 2282 | smi->irq, | ||
| 2283 | smi->slave_addr); | ||
| 2020 | } | 2284 | } |
| 2021 | 2285 | ||
| 2022 | /* | 2286 | /* |
| @@ -2407,6 +2671,16 @@ static int try_smi_init(struct smi_info *new_smi) | |||
| 2407 | goto out_err_stop_timer; | 2671 | goto out_err_stop_timer; |
| 2408 | } | 2672 | } |
| 2409 | 2673 | ||
| 2674 | rv = ipmi_smi_add_proc_entry(new_smi->intf, "params", | ||
| 2675 | param_read_proc, NULL, | ||
| 2676 | new_smi, THIS_MODULE); | ||
| 2677 | if (rv) { | ||
| 2678 | printk(KERN_ERR | ||
| 2679 | "ipmi_si: Unable to create proc entry: %d\n", | ||
| 2680 | rv); | ||
| 2681 | goto out_err_stop_timer; | ||
| 2682 | } | ||
| 2683 | |||
| 2410 | list_add_tail(&new_smi->link, &smi_infos); | 2684 | list_add_tail(&new_smi->link, &smi_infos); |
| 2411 | 2685 | ||
| 2412 | mutex_unlock(&smi_infos_lock); | 2686 | mutex_unlock(&smi_infos_lock); |
| @@ -2515,7 +2789,7 @@ static __devinit int init_ipmi_si(void) | |||
| 2515 | } | 2789 | } |
| 2516 | 2790 | ||
| 2517 | mutex_lock(&smi_infos_lock); | 2791 | mutex_lock(&smi_infos_lock); |
| 2518 | if (list_empty(&smi_infos)) { | 2792 | if (unload_when_empty && list_empty(&smi_infos)) { |
| 2519 | mutex_unlock(&smi_infos_lock); | 2793 | mutex_unlock(&smi_infos_lock); |
| 2520 | #ifdef CONFIG_PCI | 2794 | #ifdef CONFIG_PCI |
| 2521 | pci_unregister_driver(&ipmi_pci_driver); | 2795 | pci_unregister_driver(&ipmi_pci_driver); |
| @@ -2530,7 +2804,7 @@ static __devinit int init_ipmi_si(void) | |||
| 2530 | } | 2804 | } |
| 2531 | module_init(init_ipmi_si); | 2805 | module_init(init_ipmi_si); |
| 2532 | 2806 | ||
| 2533 | static void __devexit cleanup_one_si(struct smi_info *to_clean) | 2807 | static void cleanup_one_si(struct smi_info *to_clean) |
| 2534 | { | 2808 | { |
| 2535 | int rv; | 2809 | int rv; |
| 2536 | unsigned long flags; | 2810 | unsigned long flags; |
