in ipmi/ipmi_ssif.c [1622:1895]
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
unsigned char msg[3];
unsigned char *resp;
struct ssif_info *ssif_info;
int rv = 0;
int len;
int i;
u8 slave_addr = 0;
struct ssif_addr_info *addr_info = NULL;
mutex_lock(&ssif_infos_mutex);
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
if (!resp) {
mutex_unlock(&ssif_infos_mutex);
return -ENOMEM;
}
ssif_info = kzalloc(sizeof(*ssif_info), GFP_KERNEL);
if (!ssif_info) {
kfree(resp);
mutex_unlock(&ssif_infos_mutex);
return -ENOMEM;
}
if (!check_acpi(ssif_info, &client->dev)) {
addr_info = ssif_info_find(client->addr, client->adapter->name,
true);
if (!addr_info) {
/* Must have come in through sysfs. */
ssif_info->addr_source = SI_HOTMOD;
} else {
ssif_info->addr_source = addr_info->addr_src;
ssif_info->ssif_debug = addr_info->debug;
ssif_info->addr_info = addr_info->addr_info;
addr_info->client = client;
slave_addr = addr_info->slave_addr;
}
}
ssif_info->client = client;
i2c_set_clientdata(client, ssif_info);
rv = ssif_check_and_remove(client, ssif_info);
/* If rv is 0 and addr source is not SI_ACPI, continue probing */
if (!rv && ssif_info->addr_source == SI_ACPI) {
rv = ssif_add_infos(client);
if (rv) {
dev_err(&client->dev, "Out of memory!, exiting ..\n");
goto out;
}
} else if (rv) {
dev_err(&client->dev, "Not probing, Interface already present\n");
goto out;
}
slave_addr = find_slave_address(client, slave_addr);
dev_info(&client->dev,
"Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n",
ipmi_addr_src_to_str(ssif_info->addr_source),
client->addr, client->adapter->name, slave_addr);
/* Now check for system interface capabilities */
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD;
msg[2] = 0; /* SSIF */
rv = do_cmd(client, 3, msg, &len, resp);
if (!rv && (len >= 3) && (resp[2] == 0)) {
if (len < 7) {
if (ssif_dbg_probe)
dev_dbg(&ssif_info->client->dev,
"SSIF info too short: %d\n", len);
goto no_support;
}
/* Got a good SSIF response, handle it. */
ssif_info->max_xmit_msg_size = resp[5];
ssif_info->max_recv_msg_size = resp[6];
ssif_info->multi_support = (resp[4] >> 6) & 0x3;
ssif_info->supports_pec = (resp[4] >> 3) & 0x1;
/* Sanitize the data */
switch (ssif_info->multi_support) {
case SSIF_NO_MULTI:
if (ssif_info->max_xmit_msg_size > 32)
ssif_info->max_xmit_msg_size = 32;
if (ssif_info->max_recv_msg_size > 32)
ssif_info->max_recv_msg_size = 32;
break;
case SSIF_MULTI_2_PART:
if (ssif_info->max_xmit_msg_size > 63)
ssif_info->max_xmit_msg_size = 63;
if (ssif_info->max_recv_msg_size > 62)
ssif_info->max_recv_msg_size = 62;
break;
case SSIF_MULTI_n_PART:
/* We take whatever size given, but do some testing. */
break;
default:
/* Data is not sane, just give up. */
goto no_support;
}
} else {
no_support:
/* Assume no multi-part or PEC support */
dev_info(&ssif_info->client->dev,
"Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
rv, len, resp[2]);
ssif_info->max_xmit_msg_size = 32;
ssif_info->max_recv_msg_size = 32;
ssif_info->multi_support = SSIF_NO_MULTI;
ssif_info->supports_pec = 0;
}
test_multipart_messages(client, ssif_info, resp);
/* Make sure the NMI timeout is cleared. */
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
msg[2] = WDT_PRE_TIMEOUT_INT;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 3) || (resp[2] != 0))
dev_warn(&ssif_info->client->dev,
"Unable to clear message flags: %d %d %2.2x\n",
rv, len, resp[2]);
/* Attempt to enable the event buffer. */
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
rv = do_cmd(client, 2, msg, &len, resp);
if (rv || (len < 4) || (resp[2] != 0)) {
dev_warn(&ssif_info->client->dev,
"Error getting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
}
ssif_info->global_enables = resp[3];
if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
ssif_info->has_event_buffer = true;
/* buffer is already enabled, nothing to do. */
goto found;
}
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) {
dev_warn(&ssif_info->client->dev,
"Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
}
if (resp[2] == 0) {
/* A successful return means the event buffer is supported. */
ssif_info->has_event_buffer = true;
ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF;
}
/* Some systems don't behave well if you enable alerts. */
if (alerts_broken)
goto found;
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) {
dev_warn(&ssif_info->client->dev,
"Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
}
if (resp[2] == 0) {
/* A successful return means the alert is supported. */
ssif_info->supports_alert = true;
ssif_info->global_enables |= IPMI_BMC_RCV_MSG_INTR;
}
found:
if (ssif_dbg_probe) {
dev_dbg(&ssif_info->client->dev,
"%s: i2c_probe found device at i2c address %x\n",
__func__, client->addr);
}
spin_lock_init(&ssif_info->lock);
ssif_info->ssif_state = SSIF_NORMAL;
timer_setup(&ssif_info->retry_timer, retry_timeout, 0);
timer_setup(&ssif_info->watch_timer, watch_timeout, 0);
for (i = 0; i < SSIF_NUM_STATS; i++)
atomic_set(&ssif_info->stats[i], 0);
if (ssif_info->supports_pec)
ssif_info->client->flags |= I2C_CLIENT_PEC;
ssif_info->handlers.owner = THIS_MODULE;
ssif_info->handlers.start_processing = ssif_start_processing;
ssif_info->handlers.shutdown = shutdown_ssif;
ssif_info->handlers.get_smi_info = get_smi_info;
ssif_info->handlers.sender = sender;
ssif_info->handlers.request_events = request_events;
ssif_info->handlers.set_need_watch = ssif_set_need_watch;
{
unsigned int thread_num;
thread_num = ((i2c_adapter_id(ssif_info->client->adapter)
<< 8) |
ssif_info->client->addr);
init_completion(&ssif_info->wake_thread);
ssif_info->thread = kthread_run(ipmi_ssif_thread, ssif_info,
"kssif%4.4x", thread_num);
if (IS_ERR(ssif_info->thread)) {
rv = PTR_ERR(ssif_info->thread);
dev_notice(&ssif_info->client->dev,
"Could not start kernel thread: error %d\n",
rv);
goto out;
}
}
dev_set_drvdata(&ssif_info->client->dev, ssif_info);
rv = device_add_group(&ssif_info->client->dev,
&ipmi_ssif_dev_attr_group);
if (rv) {
dev_err(&ssif_info->client->dev,
"Unable to add device attributes: error %d\n",
rv);
goto out;
}
rv = ipmi_register_smi(&ssif_info->handlers,
ssif_info,
&ssif_info->client->dev,
slave_addr);
if (rv) {
dev_err(&ssif_info->client->dev,
"Unable to register device: error %d\n", rv);
goto out_remove_attr;
}
out:
if (rv) {
if (addr_info)
addr_info->client = NULL;
dev_err(&ssif_info->client->dev,
"Unable to start IPMI SSIF: %d\n", rv);
i2c_set_clientdata(client, NULL);
kfree(ssif_info);
}
kfree(resp);
mutex_unlock(&ssif_infos_mutex);
return rv;
out_remove_attr:
device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group);
dev_set_drvdata(&ssif_info->client->dev, NULL);
goto out;
}