summaryrefslogtreecommitdiff
path: root/drivers/net/fjes/fjes_hw.c
diff options
context:
space:
mode:
authorTaku Izumi <izumi.taku@jp.fujitsu.com>2016-10-14 20:27:45 +0900
committerDavid S. Miller <davem@davemloft.net>2016-10-14 12:04:57 -0400
commitb6ba737d0b290b272452a2362088222a248fc8da (patch)
tree8b4fdafab65ef761d6052461d0848386c8c389de /drivers/net/fjes/fjes_hw.c
parent82f6aea801e3732fe4bf41af46ebe352bf24fde8 (diff)
fjes: ethtool -w and -W support for fjes driver
This patch adds implementation of supporting ethtool -w and -W for fjes driver. You can enable and disable firmware debug mode by using ethtool -W, and also retrieve firmware activity information by using ethtool -w. This is useful for debugging. Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/fjes/fjes_hw.c')
-rw-r--r--drivers/net/fjes/fjes_hw.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index dba59dcc410f..9c652c04375b 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c
@@ -343,6 +343,9 @@ int fjes_hw_init(struct fjes_hw *hw)
ret = fjes_hw_setup(hw);
+ hw->hw_info.trace = vzalloc(FJES_DEBUG_BUFFER_SIZE);
+ hw->hw_info.trace_size = FJES_DEBUG_BUFFER_SIZE;
+
return ret;
}
@@ -351,6 +354,18 @@ void fjes_hw_exit(struct fjes_hw *hw)
int ret;
if (hw->base) {
+
+ if (hw->debug_mode) {
+ /* disable debug mode */
+ mutex_lock(&hw->hw_info.lock);
+ fjes_hw_stop_debug(hw);
+ mutex_unlock(&hw->hw_info.lock);
+ }
+ vfree(hw->hw_info.trace);
+ hw->hw_info.trace = NULL;
+ hw->hw_info.trace_size = 0;
+ hw->debug_mode = 0;
+
ret = fjes_hw_reset(hw);
if (ret)
pr_err("%s: reset error", __func__);
@@ -1175,3 +1190,125 @@ static void fjes_hw_epstop_task(struct work_struct *work)
}
}
}
+
+int fjes_hw_start_debug(struct fjes_hw *hw)
+{
+ union fjes_device_command_req *req_buf = hw->hw_info.req_buf;
+ union fjes_device_command_res *res_buf = hw->hw_info.res_buf;
+ enum fjes_dev_command_response_e ret;
+ int page_count;
+ int result = 0;
+ void *addr;
+ int i;
+
+ if (!hw->hw_info.trace)
+ return -EPERM;
+ memset(hw->hw_info.trace, 0, FJES_DEBUG_BUFFER_SIZE);
+
+ memset(req_buf, 0, hw->hw_info.req_buf_size);
+ memset(res_buf, 0, hw->hw_info.res_buf_size);
+
+ req_buf->start_trace.length =
+ FJES_DEV_COMMAND_START_DBG_REQ_LEN(hw->hw_info.trace_size);
+ req_buf->start_trace.mode = hw->debug_mode;
+ req_buf->start_trace.buffer_len = hw->hw_info.trace_size;
+ page_count = hw->hw_info.trace_size / FJES_DEBUG_PAGE_SIZE;
+ for (i = 0; i < page_count; i++) {
+ addr = ((u8 *)hw->hw_info.trace) + i * FJES_DEBUG_PAGE_SIZE;
+ req_buf->start_trace.buffer[i] =
+ (__le64)(page_to_phys(vmalloc_to_page(addr)) +
+ offset_in_page(addr));
+ }
+
+ res_buf->start_trace.length = 0;
+ res_buf->start_trace.code = 0;
+
+ trace_fjes_hw_start_debug_req(req_buf);
+ ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_START_DEBUG);
+ trace_fjes_hw_start_debug(res_buf);
+
+ if (res_buf->start_trace.length !=
+ FJES_DEV_COMMAND_START_DBG_RES_LEN) {
+ result = -ENOMSG;
+ trace_fjes_hw_start_debug_err("Invalid res_buf");
+ } else if (ret == FJES_CMD_STATUS_NORMAL) {
+ switch (res_buf->start_trace.code) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL:
+ result = 0;
+ break;
+ default:
+ result = -EPERM;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case FJES_CMD_STATUS_UNKNOWN:
+ result = -EPERM;
+ break;
+ case FJES_CMD_STATUS_TIMEOUT:
+ trace_fjes_hw_start_debug_err("Busy Timeout");
+ result = -EBUSY;
+ break;
+ case FJES_CMD_STATUS_ERROR_PARAM:
+ case FJES_CMD_STATUS_ERROR_STATUS:
+ default:
+ result = -EPERM;
+ break;
+ }
+ }
+
+ return result;
+}
+
+int fjes_hw_stop_debug(struct fjes_hw *hw)
+{
+ union fjes_device_command_req *req_buf = hw->hw_info.req_buf;
+ union fjes_device_command_res *res_buf = hw->hw_info.res_buf;
+ enum fjes_dev_command_response_e ret;
+ int result = 0;
+
+ if (!hw->hw_info.trace)
+ return -EPERM;
+
+ memset(req_buf, 0, hw->hw_info.req_buf_size);
+ memset(res_buf, 0, hw->hw_info.res_buf_size);
+ req_buf->stop_trace.length = FJES_DEV_COMMAND_STOP_DBG_REQ_LEN;
+
+ res_buf->stop_trace.length = 0;
+ res_buf->stop_trace.code = 0;
+
+ ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_STOP_DEBUG);
+ trace_fjes_hw_stop_debug(res_buf);
+
+ if (res_buf->stop_trace.length != FJES_DEV_COMMAND_STOP_DBG_RES_LEN) {
+ trace_fjes_hw_stop_debug_err("Invalid res_buf");
+ result = -ENOMSG;
+ } else if (ret == FJES_CMD_STATUS_NORMAL) {
+ switch (res_buf->stop_trace.code) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL:
+ result = 0;
+ hw->debug_mode = 0;
+ break;
+ default:
+ result = -EPERM;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case FJES_CMD_STATUS_UNKNOWN:
+ result = -EPERM;
+ break;
+ case FJES_CMD_STATUS_TIMEOUT:
+ result = -EBUSY;
+ trace_fjes_hw_stop_debug_err("Busy Timeout");
+ break;
+ case FJES_CMD_STATUS_ERROR_PARAM:
+ case FJES_CMD_STATUS_ERROR_STATUS:
+ default:
+ result = -EPERM;
+ break;
+ }
+ }
+
+ return result;
+}