in ps3-lpm.c [1074:1151]
int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
u64 tb_cache_size)
{
int result;
u64 tb_size;
BUG_ON(!lpm_priv);
BUG_ON(tb_type != PS3_LPM_TB_TYPE_NONE
&& tb_type != PS3_LPM_TB_TYPE_INTERNAL);
if (tb_type == PS3_LPM_TB_TYPE_NONE && tb_cache)
dev_dbg(sbd_core(), "%s:%u: bad in vals\n", __func__, __LINE__);
if (!atomic_add_unless(&lpm_priv->open, 1, 1)) {
dev_dbg(sbd_core(), "%s:%u: busy\n", __func__, __LINE__);
return -EBUSY;
}
/* Note tb_cache needs 128 byte alignment. */
if (tb_type == PS3_LPM_TB_TYPE_NONE) {
lpm_priv->tb_cache_size = 0;
lpm_priv->tb_cache_internal = NULL;
lpm_priv->tb_cache = NULL;
} else if (tb_cache) {
if (tb_cache != (void *)ALIGN((unsigned long)tb_cache, 128)
|| tb_cache_size != ALIGN(tb_cache_size, 128)) {
dev_err(sbd_core(), "%s:%u: unaligned tb_cache\n",
__func__, __LINE__);
result = -EINVAL;
goto fail_align;
}
lpm_priv->tb_cache_size = tb_cache_size;
lpm_priv->tb_cache_internal = NULL;
lpm_priv->tb_cache = tb_cache;
} else {
lpm_priv->tb_cache_size = PS3_LPM_DEFAULT_TB_CACHE_SIZE;
lpm_priv->tb_cache_internal = kzalloc(
lpm_priv->tb_cache_size + 127, GFP_KERNEL);
if (!lpm_priv->tb_cache_internal) {
result = -ENOMEM;
goto fail_malloc;
}
lpm_priv->tb_cache = (void *)ALIGN(
(unsigned long)lpm_priv->tb_cache_internal, 128);
}
result = lv1_construct_lpm(lpm_priv->node_id, tb_type, 0, 0,
ps3_mm_phys_to_lpar(__pa(lpm_priv->tb_cache)),
lpm_priv->tb_cache_size, &lpm_priv->lpm_id,
&lpm_priv->outlet_id, &tb_size);
if (result) {
dev_err(sbd_core(), "%s:%u: lv1_construct_lpm failed: %s\n",
__func__, __LINE__, ps3_result(result));
result = -EINVAL;
goto fail_construct;
}
lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT;
lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT;
lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT;
lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT;
dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%llx, outlet_id 0x%llx, "
"tb_size 0x%llx\n", __func__, __LINE__, lpm_priv->lpm_id,
lpm_priv->outlet_id, tb_size);
return 0;
fail_construct:
kfree(lpm_priv->tb_cache_internal);
lpm_priv->tb_cache_internal = NULL;
fail_malloc:
fail_align:
atomic_dec(&lpm_priv->open);
return result;
}