#include "tw_osl_share.h"
#include "tw_cl_share.h"
#include "tw_cl_fwif.h"
#include "tw_cl_ioctl.h"
#include "tw_cl.h"
#include "tw_cl_externs.h"
#include "tw_osl_ioctl.h"
TW_INT32
tw_cl_ctlr_supported(TW_INT32 vendor_id, TW_INT32 device_id)
{
if ((vendor_id == TW_CL_VENDOR_ID) &&
((device_id == TW_CL_DEVICE_ID_9K) ||
(device_id == TW_CL_DEVICE_ID_9K_X) ||
(device_id == TW_CL_DEVICE_ID_9K_E) ||
(device_id == TW_CL_DEVICE_ID_9K_SA)))
return(TW_CL_TRUE);
return(TW_CL_FALSE);
}
TW_INT32
tw_cl_get_pci_bar_info(TW_INT32 device_id, TW_INT32 bar_type,
TW_INT32 *bar_num, TW_INT32 *bar0_offset, TW_INT32 *bar_size)
{
TW_INT32 error = TW_OSL_ESUCCESS;
switch(device_id) {
case TW_CL_DEVICE_ID_9K:
switch(bar_type) {
case TW_CL_BAR_TYPE_IO:
*bar_num = 0;
*bar0_offset = 0;
*bar_size = 4;
break;
case TW_CL_BAR_TYPE_MEM:
*bar_num = 1;
*bar0_offset = 0x4;
*bar_size = 8;
break;
case TW_CL_BAR_TYPE_SBUF:
*bar_num = 2;
*bar0_offset = 0xC;
*bar_size = 8;
break;
}
break;
case TW_CL_DEVICE_ID_9K_X:
case TW_CL_DEVICE_ID_9K_E:
case TW_CL_DEVICE_ID_9K_SA:
switch(bar_type) {
case TW_CL_BAR_TYPE_IO:
*bar_num = 2;
*bar0_offset = 0x10;
*bar_size = 4;
break;
case TW_CL_BAR_TYPE_MEM:
*bar_num = 1;
*bar0_offset = 0x8;
*bar_size = 8;
break;
case TW_CL_BAR_TYPE_SBUF:
*bar_num = 0;
*bar0_offset = 0;
*bar_size = 8;
break;
}
break;
default:
error = TW_OSL_ENOTTY;
break;
}
return(error);
}
TW_INT32
tw_cl_get_mem_requirements(struct tw_cl_ctlr_handle *ctlr_handle,
TW_UINT32 flags, TW_INT32 device_id, TW_INT32 max_simult_reqs,
TW_INT32 max_aens, TW_UINT32 *alignment, TW_UINT32 *sg_size_factor,
TW_UINT32 *non_dma_mem_size, TW_UINT32 *dma_mem_size
)
{
if (device_id == 0)
device_id = TW_CL_DEVICE_ID_9K;
if (max_simult_reqs > TW_CL_MAX_SIMULTANEOUS_REQUESTS) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1000, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Too many simultaneous requests to support!",
"requested = %d, supported = %d, error = %d\n",
max_simult_reqs, TW_CL_MAX_SIMULTANEOUS_REQUESTS,
TW_OSL_EBIG);
return(TW_OSL_EBIG);
}
*alignment = TWA_ALIGNMENT(device_id);
*sg_size_factor = TWA_SG_ELEMENT_SIZE_FACTOR(device_id);
*non_dma_mem_size = sizeof(struct tw_cli_ctlr_context) +
(sizeof(struct tw_cli_req_context) * max_simult_reqs) +
(sizeof(struct tw_cl_event_packet) * max_aens);
*dma_mem_size = (sizeof(struct tw_cl_command_packet) *
(max_simult_reqs)) + (TW_CLI_SECTOR_SIZE);
return(0);
}
TW_INT32
tw_cl_init_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT32 flags,
TW_INT32 device_id, TW_INT32 max_simult_reqs, TW_INT32 max_aens,
TW_VOID *non_dma_mem, TW_VOID *dma_mem, TW_UINT64 dma_mem_phys
)
{
struct tw_cli_ctlr_context *ctlr;
struct tw_cli_req_context *req;
TW_UINT8 *free_non_dma_mem;
TW_INT32 error = TW_OSL_ESUCCESS;
TW_INT32 i;
tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), "entered");
if (flags & TW_CL_START_CTLR_ONLY) {
ctlr = (struct tw_cli_ctlr_context *)
(ctlr_handle->cl_ctlr_ctxt);
goto start_ctlr;
}
if (max_simult_reqs > TW_CL_MAX_SIMULTANEOUS_REQUESTS) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1000, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Too many simultaneous requests to support!",
"requested = %d, supported = %d, error = %d\n",
max_simult_reqs, TW_CL_MAX_SIMULTANEOUS_REQUESTS,
TW_OSL_EBIG);
return(TW_OSL_EBIG);
}
if ((non_dma_mem == TW_CL_NULL) || (dma_mem == TW_CL_NULL)
) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1001, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Insufficient memory for Common Layer's internal usage",
"error = %d\n", TW_OSL_ENOMEM);
return(TW_OSL_ENOMEM);
}
tw_osl_memzero(non_dma_mem, sizeof(struct tw_cli_ctlr_context) +
(sizeof(struct tw_cli_req_context) * max_simult_reqs) +
(sizeof(struct tw_cl_event_packet) * max_aens));
tw_osl_memzero(dma_mem,
(sizeof(struct tw_cl_command_packet) *
max_simult_reqs) +
TW_CLI_SECTOR_SIZE);
free_non_dma_mem = (TW_UINT8 *)non_dma_mem;
ctlr = (struct tw_cli_ctlr_context *)free_non_dma_mem;
free_non_dma_mem += sizeof(struct tw_cli_ctlr_context);
ctlr_handle->cl_ctlr_ctxt = ctlr;
ctlr->ctlr_handle = ctlr_handle;
ctlr->device_id = (TW_UINT32)device_id;
ctlr->arch_id = TWA_ARCH_ID(device_id);
ctlr->flags = flags;
ctlr->sg_size_factor = TWA_SG_ELEMENT_SIZE_FACTOR(device_id);
ctlr->max_simult_reqs = max_simult_reqs;
ctlr->max_aens_supported = max_aens;
tw_cli_req_q_init(ctlr, TW_CLI_FREE_Q);
tw_cli_req_q_init(ctlr, TW_CLI_BUSY_Q);
tw_cli_req_q_init(ctlr, TW_CLI_PENDING_Q);
tw_cli_req_q_init(ctlr, TW_CLI_COMPLETE_Q);
tw_cli_req_q_init(ctlr, TW_CLI_RESET_Q);
ctlr->gen_lock = &(ctlr->gen_lock_handle);
tw_osl_init_lock(ctlr_handle, "tw_cl_gen_lock", ctlr->gen_lock);
ctlr->io_lock = &(ctlr->io_lock_handle);
tw_osl_init_lock(ctlr_handle, "tw_cl_io_lock", ctlr->io_lock);
ctlr->req_ctxt_buf = (struct tw_cli_req_context *)free_non_dma_mem;
free_non_dma_mem += (sizeof(struct tw_cli_req_context) *
max_simult_reqs);
ctlr->cmd_pkt_buf = (struct tw_cl_command_packet *)dma_mem;
ctlr->cmd_pkt_phys = dma_mem_phys;
ctlr->internal_req_data = (TW_UINT8 *)
(ctlr->cmd_pkt_buf +
max_simult_reqs);
ctlr->internal_req_data_phys = ctlr->cmd_pkt_phys +
(sizeof(struct tw_cl_command_packet) *
max_simult_reqs);
for (i = 0; i < max_simult_reqs; i++) {
req = &(ctlr->req_ctxt_buf[i]);
req->cmd_pkt = &(ctlr->cmd_pkt_buf[i]);
req->cmd_pkt_phys = ctlr->cmd_pkt_phys +
(i * sizeof(struct tw_cl_command_packet));
req->request_id = i;
req->ctlr = ctlr;
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
}
ctlr->aen_queue = (struct tw_cl_event_packet *)free_non_dma_mem;
start_ctlr:
tw_cli_disable_interrupts(ctlr);
if ((error = tw_cli_start_ctlr(ctlr))) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1002, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Controller initialization failed. Retrying...",
"error = %d\n", error);
if ((error = tw_cli_soft_reset(ctlr))) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1003, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Controller soft reset failed",
"error = %d\n", error);
return(error);
} else if ((error = tw_cli_start_ctlr(ctlr))) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1004, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Controller initialization retry failed",
"error = %d\n", error);
return(error);
}
}
tw_cli_notify_ctlr_info(ctlr);
ctlr->active = TW_CL_TRUE;
return(error);
}
TW_INT32
tw_cli_start_ctlr(struct tw_cli_ctlr_context *ctlr)
{
TW_UINT16 fw_on_ctlr_srl = 0;
TW_UINT16 fw_on_ctlr_arch_id = 0;
TW_UINT16 fw_on_ctlr_branch = 0;
TW_UINT16 fw_on_ctlr_build = 0;
TW_UINT32 init_connect_result = 0;
TW_INT32 error = TW_OSL_ESUCCESS;
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
if ((error = tw_cli_poll_status(ctlr,
TWA_STATUS_MICROCONTROLLER_READY,
TW_CLI_REQUEST_TIMEOUT_PERIOD))) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1009, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Microcontroller not ready",
"error = %d", error);
return(error);
}
if ((error = tw_cli_drain_response_queue(ctlr))) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100A, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Can't drain response queue",
"error = %d", error);
return(error);
}
if ((error = tw_cli_init_connection(ctlr,
(TW_UINT16)(ctlr->max_simult_reqs),
TWA_EXTENDED_INIT_CONNECT, TWA_CURRENT_FW_SRL,
(TW_UINT16)(ctlr->arch_id),
TWA_CURRENT_FW_BRANCH(ctlr->arch_id),
TWA_CURRENT_FW_BUILD(ctlr->arch_id),
&fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
&fw_on_ctlr_branch, &fw_on_ctlr_build,
&init_connect_result))) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100B, 0x2, TW_CL_SEVERITY_WARNING_STRING,
"Can't initialize connection in current mode",
"error = %d", error);
return(error);
}
{
if (init_connect_result & TWA_CTLR_FW_COMPATIBLE) {
if (init_connect_result & TWA_CTLR_FW_SAME_OR_NEWER) {
ctlr->working_srl = TWA_CURRENT_FW_SRL;
ctlr->working_branch =
TWA_CURRENT_FW_BRANCH(ctlr->arch_id);
ctlr->working_build =
TWA_CURRENT_FW_BUILD(ctlr->arch_id);
} else {
ctlr->working_srl = fw_on_ctlr_srl;
ctlr->working_branch = fw_on_ctlr_branch;
ctlr->working_build = fw_on_ctlr_build;
}
} else {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1010, 0x2, TW_CL_SEVERITY_WARNING_STRING,
"Driver/Firmware mismatch. "
"Negotiating for base level...",
" ");
if ((error = tw_cli_init_connection(ctlr,
(TW_UINT16)(ctlr->max_simult_reqs),
TWA_EXTENDED_INIT_CONNECT,
TWA_BASE_FW_SRL,
(TW_UINT16)(ctlr->arch_id),
TWA_BASE_FW_BRANCH, TWA_BASE_FW_BUILD,
&fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
&fw_on_ctlr_branch, &fw_on_ctlr_build,
&init_connect_result))) {
tw_cl_create_event(ctlr->ctlr_handle,
TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1011, 0x1,
TW_CL_SEVERITY_ERROR_STRING,
"Can't initialize connection in "
"base mode",
" ");
return(error);
}
if (!(init_connect_result & TWA_CTLR_FW_COMPATIBLE)) {
return(1);
}
ctlr->working_srl = TWA_BASE_FW_SRL;
ctlr->working_branch = TWA_BASE_FW_BRANCH;
ctlr->working_build = TWA_BASE_FW_BUILD;
ctlr->operating_mode = TWA_BASE_MODE;
}
ctlr->fw_on_ctlr_srl = fw_on_ctlr_srl;
ctlr->fw_on_ctlr_branch = fw_on_ctlr_branch;
ctlr->fw_on_ctlr_build = fw_on_ctlr_build;
}
if ((error = tw_cli_drain_aen_queue(ctlr)))
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1014, 0x2, TW_CL_SEVERITY_WARNING_STRING,
"Can't drain AEN queue",
"error = %d", error);
tw_cli_enable_interrupts(ctlr);
return(TW_OSL_ESUCCESS);
}
TW_INT32
tw_cl_shutdown_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT32 flags)
{
struct tw_cli_ctlr_context *ctlr =
(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
TW_INT32 error;
tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), "entered");
ctlr->active = TW_CL_FALSE;
tw_cli_disable_interrupts(ctlr);
if ((error = tw_cli_init_connection(ctlr, TWA_SHUTDOWN_MESSAGE_CREDITS,
0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL,
TW_CL_NULL, TW_CL_NULL)))
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1015, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Can't close connection with controller",
"error = %d", error);
if (flags & TW_CL_STOP_CTLR_ONLY)
goto ret;
tw_osl_destroy_lock(ctlr_handle, ctlr->gen_lock);
tw_osl_destroy_lock(ctlr_handle, ctlr->io_lock);
ret:
return(error);
}
TW_INT32
tw_cli_init_connection(struct tw_cli_ctlr_context *ctlr,
TW_UINT16 message_credits, TW_UINT32 set_features,
TW_UINT16 current_fw_srl, TW_UINT16 current_fw_arch_id,
TW_UINT16 current_fw_branch, TW_UINT16 current_fw_build,
TW_UINT16 *fw_on_ctlr_srl, TW_UINT16 *fw_on_ctlr_arch_id,
TW_UINT16 *fw_on_ctlr_branch, TW_UINT16 *fw_on_ctlr_build,
TW_UINT32 *init_connect_result)
{
struct tw_cli_req_context *req;
struct tw_cl_command_init_connect *init_connect;
TW_INT32 error = TW_OSL_EBUSY;
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
if ((req = tw_cli_get_request(ctlr
)) == TW_CL_NULL)
goto out;
req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
init_connect = &(req->cmd_pkt->command.cmd_pkt_7k.init_connect);
req->cmd_pkt->cmd_hdr.header_desc.size_header = 128;
init_connect->res1__opcode =
BUILD_RES__OPCODE(0, TWA_FW_CMD_INIT_CONNECTION);
init_connect->request_id =
(TW_UINT8)(TW_CL_SWAP16(req->request_id));
init_connect->message_credits = TW_CL_SWAP16(message_credits);
init_connect->features = TW_CL_SWAP32(set_features);
if (ctlr->flags & TW_CL_64BIT_ADDRESSES)
init_connect->features |= TW_CL_SWAP32(TWA_64BIT_SG_ADDRESSES);
if (set_features & TWA_EXTENDED_INIT_CONNECT) {
init_connect->size = 6;
init_connect->fw_srl = TW_CL_SWAP16(current_fw_srl);
init_connect->fw_arch_id = TW_CL_SWAP16(current_fw_arch_id);
init_connect->fw_branch = TW_CL_SWAP16(current_fw_branch);
init_connect->fw_build = TW_CL_SWAP16(current_fw_build);
} else
init_connect->size = 3;
error = tw_cli_submit_and_poll_request(req,
TW_CLI_REQUEST_TIMEOUT_PERIOD);
if (error)
goto out;
if ((error = init_connect->status)) {
#if 0
tw_cli_create_ctlr_event(ctlr,
TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
&(req->cmd_pkt->cmd_hdr));
#endif
goto out;
}
if (set_features & TWA_EXTENDED_INIT_CONNECT) {
*fw_on_ctlr_srl = TW_CL_SWAP16(init_connect->fw_srl);
*fw_on_ctlr_arch_id = TW_CL_SWAP16(init_connect->fw_arch_id);
*fw_on_ctlr_branch = TW_CL_SWAP16(init_connect->fw_branch);
*fw_on_ctlr_build = TW_CL_SWAP16(init_connect->fw_build);
*init_connect_result = TW_CL_SWAP32(init_connect->result);
}
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
return(error);
out:
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1016, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"init_connection failed",
"error = %d", error);
if (req)
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
return(error);
}