0001
0002
0003 #define pr_fmt(fmt) "ipmi_hardcode: " fmt
0004
0005 #include <linux/moduleparam.h>
0006 #include <linux/platform_device.h>
0007 #include "ipmi_si.h"
0008 #include "ipmi_plat_data.h"
0009
0010
0011
0012
0013
0014
0015 #define SI_MAX_PARMS 4
0016
0017 #define MAX_SI_TYPE_STR 30
0018 static char si_type_str[MAX_SI_TYPE_STR] __initdata;
0019 static unsigned long addrs[SI_MAX_PARMS];
0020 static unsigned int num_addrs;
0021 static unsigned int ports[SI_MAX_PARMS];
0022 static unsigned int num_ports;
0023 static int irqs[SI_MAX_PARMS] __initdata;
0024 static unsigned int num_irqs __initdata;
0025 static int regspacings[SI_MAX_PARMS] __initdata;
0026 static unsigned int num_regspacings __initdata;
0027 static int regsizes[SI_MAX_PARMS] __initdata;
0028 static unsigned int num_regsizes __initdata;
0029 static int regshifts[SI_MAX_PARMS] __initdata;
0030 static unsigned int num_regshifts __initdata;
0031 static int slave_addrs[SI_MAX_PARMS] __initdata;
0032 static unsigned int num_slave_addrs __initdata;
0033
0034 module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0);
0035 MODULE_PARM_DESC(type,
0036 "Defines the type of each interface, each interface separated by commas. The types are 'kcs', 'smic', and 'bt'. For example si_type=kcs,bt will set the first interface to kcs and the second to bt");
0037 module_param_hw_array(addrs, ulong, iomem, &num_addrs, 0);
0038 MODULE_PARM_DESC(addrs,
0039 "Sets the memory address of each interface, the addresses separated by commas. Only use if an interface is in memory. Otherwise, set it to zero or leave it blank.");
0040 module_param_hw_array(ports, uint, ioport, &num_ports, 0);
0041 MODULE_PARM_DESC(ports,
0042 "Sets the port address of each interface, the addresses separated by commas. Only use if an interface is a port. Otherwise, set it to zero or leave it blank.");
0043 module_param_hw_array(irqs, int, irq, &num_irqs, 0);
0044 MODULE_PARM_DESC(irqs,
0045 "Sets the interrupt of each interface, the addresses separated by commas. Only use if an interface has an interrupt. Otherwise, set it to zero or leave it blank.");
0046 module_param_hw_array(regspacings, int, other, &num_regspacings, 0);
0047 MODULE_PARM_DESC(regspacings,
0048 "The number of bytes between the start address and each successive register used by the interface. For instance, if the start address is 0xca2 and the spacing is 2, then the second address is at 0xca4. Defaults to 1.");
0049 module_param_hw_array(regsizes, int, other, &num_regsizes, 0);
0050 MODULE_PARM_DESC(regsizes,
0051 "The size of the specific IPMI register in bytes. This should generally be 1, 2, 4, or 8 for an 8-bit, 16-bit, 32-bit, or 64-bit register. Use this if you the 8-bit IPMI register has to be read from a larger register.");
0052 module_param_hw_array(regshifts, int, other, &num_regshifts, 0);
0053 MODULE_PARM_DESC(regshifts,
0054 "The amount to shift the data read from the. IPMI register, in bits. For instance, if the data is read from a 32-bit word and the IPMI data is in bit 8-15, then the shift would be 8");
0055 module_param_hw_array(slave_addrs, int, other, &num_slave_addrs, 0);
0056 MODULE_PARM_DESC(slave_addrs,
0057 "Set the default IPMB slave address for the controller. Normally this is 0x20, but can be overridden by this parm. This is an array indexed by interface number.");
0058
0059 static void __init ipmi_hardcode_init_one(const char *si_type_str,
0060 unsigned int i,
0061 unsigned long addr,
0062 enum ipmi_addr_space addr_space)
0063 {
0064 struct ipmi_plat_data p;
0065 int t;
0066
0067 memset(&p, 0, sizeof(p));
0068
0069 p.iftype = IPMI_PLAT_IF_SI;
0070 if (!si_type_str || !*si_type_str) {
0071 p.type = SI_KCS;
0072 } else {
0073 t = match_string(si_to_str, -1, si_type_str);
0074 if (t < 0) {
0075 pr_warn("Interface type specified for interface %d, was invalid: %s\n",
0076 i, si_type_str);
0077 return;
0078 }
0079 p.type = t;
0080 }
0081
0082 p.regsize = regsizes[i];
0083 p.slave_addr = slave_addrs[i];
0084 p.addr_source = SI_HARDCODED;
0085 p.regshift = regshifts[i];
0086 p.regsize = regsizes[i];
0087 p.addr = addr;
0088 p.space = addr_space;
0089
0090 ipmi_platform_add("hardcode-ipmi-si", i, &p);
0091 }
0092
0093 void __init ipmi_hardcode_init(void)
0094 {
0095 unsigned int i;
0096 char *str;
0097 char *si_type[SI_MAX_PARMS];
0098
0099 memset(si_type, 0, sizeof(si_type));
0100
0101
0102 str = si_type_str;
0103 if (*str != '\0') {
0104 for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
0105 si_type[i] = str;
0106 str = strchr(str, ',');
0107 if (str) {
0108 *str = '\0';
0109 str++;
0110 } else {
0111 break;
0112 }
0113 }
0114 }
0115
0116 for (i = 0; i < SI_MAX_PARMS; i++) {
0117 if (i < num_ports && ports[i])
0118 ipmi_hardcode_init_one(si_type[i], i, ports[i],
0119 IPMI_IO_ADDR_SPACE);
0120 if (i < num_addrs && addrs[i])
0121 ipmi_hardcode_init_one(si_type[i], i, addrs[i],
0122 IPMI_MEM_ADDR_SPACE);
0123 }
0124 }
0125
0126
0127 void ipmi_si_hardcode_exit(void)
0128 {
0129 ipmi_remove_platform_device_by_name("hardcode-ipmi-si");
0130 }
0131
0132
0133
0134
0135
0136 int ipmi_si_hardcode_match(int addr_space, unsigned long addr)
0137 {
0138 unsigned int i;
0139
0140 if (addr_space == IPMI_IO_ADDR_SPACE) {
0141 for (i = 0; i < num_ports; i++) {
0142 if (ports[i] == addr)
0143 return 1;
0144 }
0145 } else {
0146 for (i = 0; i < num_addrs; i++) {
0147 if (addrs[i] == addr)
0148 return 1;
0149 }
0150 }
0151
0152 return 0;
0153 }