* [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
@ 2017-11-09 19:00 ` Desnes Augusto Nunes do Rosario
0 siblings, 0 replies; 8+ messages in thread
From: Desnes Augusto Nunes do Rosario @ 2017-11-09 19:00 UTC (permalink / raw)
To: netdev; +Cc: linuxppc-dev, tlfalcon, nfont, jallen
This patch implements and enables VDP support for the ibmvnic driver.
Moreover, it includes the implementation of suitable structs, signal
transmission/handling and functions which allows the retrival of firmware
information from the ibmvnic card through the ethtool command.
Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
---
drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
2 files changed, 173 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index d0cff28..693b502 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
return 0;
}
+static void release_vpd_data(struct ibmvnic_adapter *adapter)
+{
+ if (!adapter->vpd)
+ return;
+
+ kfree(adapter->vpd->buff);
+ kfree(adapter->vpd);
+}
+
static void release_tx_pools(struct ibmvnic_adapter *adapter)
{
struct ibmvnic_tx_pool *tx_pool;
@@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
{
int i;
+ release_vpd_data(adapter);
+
release_tx_pools(adapter);
release_rx_pools(adapter);
@@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
return rc;
}
+static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
+{
+ struct device *dev = &adapter->vdev->dev;
+ union ibmvnic_crq crq;
+ dma_addr_t dma_addr;
+ int len;
+
+ if (adapter->vpd->buff)
+ len = adapter->vpd->len;
+
+ reinit_completion(&adapter->fw_done);
+ crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
+ crq.get_vpd_size.cmd = GET_VPD_SIZE;
+ ibmvnic_send_crq(adapter, &crq);
+ wait_for_completion(&adapter->fw_done);
+
+ if (!adapter->vpd->buff)
+ adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
+ else if (adapter->vpd->len != len)
+ adapter->vpd->buff =
+ krealloc(adapter->vpd->buff,
+ adapter->vpd->len, GFP_KERNEL);
+
+ if (!adapter->vpd->buff) {
+ dev_err(dev, "Could allocate VPD buffer\n");
+ return -ENOMEM;
+ }
+
+ adapter->vpd->dma_addr =
+ dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, dma_addr)) {
+ dev_err(dev, "Could not map VPD buffer\n");
+ return -ENOMEM;
+ }
+
+ reinit_completion(&adapter->fw_done);
+ crq.get_vpd.first = IBMVNIC_CRQ_CMD;
+ crq.get_vpd.cmd = GET_VPD;
+ crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
+ crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
+ ibmvnic_send_crq(adapter, &crq);
+ wait_for_completion(&adapter->fw_done);
+
+ return 0;
+}
+
static int init_resources(struct ibmvnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
if (rc)
return rc;
+ adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
+ if (!adapter->vpd)
+ return -ENOMEM;
+
adapter->map_id = 1;
adapter->napi = kcalloc(adapter->req_rx_queues,
sizeof(struct napi_struct), GFP_KERNEL);
@@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
rc = __ibmvnic_open(netdev);
netif_carrier_on(netdev);
+
+ /* Vital Product Data (VPD) */
+ ibmvnic_get_vpd(adapter);
+
mutex_unlock(&adapter->reset_lock);
return rc;
@@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
return 0;
}
-static void ibmvnic_get_drvinfo(struct net_device *dev,
+static void ibmvnic_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
+ struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, adapter->fw_version,
+ sizeof(info->fw_version));
}
static u32 ibmvnic_get_msglevel(struct net_device *netdev)
@@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
ibmvnic_send_crq(adapter, &crq);
}
+static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
+ struct ibmvnic_adapter *adapter)
+{
+ struct device *dev = &adapter->vdev->dev;
+
+ if (crq->get_vpd_size_rsp.rc.code) {
+ dev_err(dev, "Error retrieving VPD size, rc=%x\n",
+ crq->get_vpd_size_rsp.rc.code);
+ complete(&adapter->fw_done);
+ return;
+ }
+
+ adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
+ complete(&adapter->fw_done);
+}
+
+static void handle_vpd_rsp(union ibmvnic_crq *crq,
+ struct ibmvnic_adapter *adapter)
+{
+ struct device *dev = &adapter->vdev->dev;
+ unsigned char *substr = NULL, *ptr = NULL;
+ u8 fw_level_len = 0;
+
+ dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
+ DMA_FROM_DEVICE);
+
+ if (crq->get_vpd_rsp.rc.code) {
+ dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
+ crq->get_vpd_rsp.rc.code);
+ memset(adapter->fw_version, 0, 32);
+ goto complete;
+ }
+
+ /* get the position of the firmware version info
+ * located after the ASCII 'RM' substring in the buffer
+ */
+ substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
+ if (!substr) {
+ dev_info(dev, "No FW level provided by VPD\n");
+ memset(adapter->fw_version, 0, 32);
+ goto complete;
+ }
+
+ /* get length of firmware level ASCII substring */
+ if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
+ fw_level_len = *(substr + 2);
+ } else {
+ dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
+ memset(adapter->fw_version, 0, 32);
+ goto complete;
+ }
+
+ /* copy firmware version string from vpd into adapter */
+ if ((substr + 3 + fw_level_len) <
+ (adapter->vpd->buff + adapter->vpd->len)) {
+ ptr = strncpy((char *)adapter->fw_version,
+ substr + 3, fw_level_len);
+
+ if (!ptr) {
+ dev_err(dev, "Failed to isolate FW level string\n");
+ memset(adapter->fw_version, 0, 32);
+ }
+ } else {
+ dev_info(dev, "FW substr extrapolated VPD buff\n");
+ memset(adapter->fw_version, 0, 32);
+ }
+
+complete:
+ complete(&adapter->fw_done);
+}
+
static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
{
struct device *dev = &adapter->vdev->dev;
@@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
netdev_dbg(netdev, "Got Collect firmware trace Response\n");
complete(&adapter->fw_done);
break;
+ case GET_VPD_SIZE_RSP:
+ handle_vpd_size_rsp(crq, adapter);
+ break;
+ case GET_VPD_RSP:
+ handle_vpd_rsp(crq, adapter);
+ break;
default:
netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
gen_crq->cmd);
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index 4670af8..d3a6959 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
struct ibmvnic_rc rc;
} __packed __aligned(8);
+struct ibmvnic_get_vpd_size {
+ u8 first;
+ u8 cmd;
+ u8 reserved[14];
+} __packed __aligned(8);
+
struct ibmvnic_get_vpd_size_rsp {
u8 first;
u8 cmd;
@@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
u8 reserved[4];
} __packed __aligned(8);
+struct ibmvnic_get_vpd_rsp {
+ u8 first;
+ u8 cmd;
+ u8 reserved[10];
+ struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
struct ibmvnic_acl_change_indication {
u8 first;
u8 cmd;
@@ -700,10 +713,10 @@ union ibmvnic_crq {
struct ibmvnic_change_mac_addr change_mac_addr_rsp;
struct ibmvnic_multicast_ctrl multicast_ctrl;
struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
- struct ibmvnic_generic_crq get_vpd_size;
+ struct ibmvnic_get_vpd_size get_vpd_size;
struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
struct ibmvnic_get_vpd get_vpd;
- struct ibmvnic_generic_crq get_vpd_rsp;
+ struct ibmvnic_get_vpd_rsp get_vpd_rsp;
struct ibmvnic_acl_change_indication acl_change_indication;
struct ibmvnic_acl_query acl_query;
struct ibmvnic_generic_crq acl_query_rsp;
@@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
__be32 error_id;
};
+struct ibmvnic_vpd {
+ unsigned char *buff;
+ dma_addr_t dma_addr;
+ u64 len;
+};
+
enum vnic_state {VNIC_PROBING = 1,
VNIC_PROBED,
VNIC_OPENING,
@@ -978,6 +997,10 @@ struct ibmvnic_adapter {
dma_addr_t ip_offload_ctrl_tok;
u32 msg_enable;
+ /* Vital Product Data (VPD) */
+ struct ibmvnic_vpd *vpd;
+ char fw_version[32];
+
/* Statistics */
struct ibmvnic_statistics stats;
dma_addr_t stats_token;
--
2.9.5
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH] [net-next, v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
@ 2017-11-09 19:00 ` Desnes Augusto Nunes do Rosario
0 siblings, 0 replies; 8+ messages in thread
From: Desnes Augusto Nunes do Rosario @ 2017-11-09 19:00 UTC (permalink / raw)
To: netdev; +Cc: linuxppc-dev, tlfalcon, nfont, jallen
This patch implements and enables VDP support for the ibmvnic driver.
Moreover, it includes the implementation of suitable structs, signal
transmission/handling and functions which allows the retrival of firmware
information from the ibmvnic card through the ethtool command.
Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
---
drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
2 files changed, 173 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index d0cff28..693b502 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
return 0;
}
+static void release_vpd_data(struct ibmvnic_adapter *adapter)
+{
+ if (!adapter->vpd)
+ return;
+
+ kfree(adapter->vpd->buff);
+ kfree(adapter->vpd);
+}
+
static void release_tx_pools(struct ibmvnic_adapter *adapter)
{
struct ibmvnic_tx_pool *tx_pool;
@@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
{
int i;
+ release_vpd_data(adapter);
+
release_tx_pools(adapter);
release_rx_pools(adapter);
@@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
return rc;
}
+static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
+{
+ struct device *dev = &adapter->vdev->dev;
+ union ibmvnic_crq crq;
+ dma_addr_t dma_addr;
+ int len;
+
+ if (adapter->vpd->buff)
+ len = adapter->vpd->len;
+
+ reinit_completion(&adapter->fw_done);
+ crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
+ crq.get_vpd_size.cmd = GET_VPD_SIZE;
+ ibmvnic_send_crq(adapter, &crq);
+ wait_for_completion(&adapter->fw_done);
+
+ if (!adapter->vpd->buff)
+ adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
+ else if (adapter->vpd->len != len)
+ adapter->vpd->buff =
+ krealloc(adapter->vpd->buff,
+ adapter->vpd->len, GFP_KERNEL);
+
+ if (!adapter->vpd->buff) {
+ dev_err(dev, "Could allocate VPD buffer\n");
+ return -ENOMEM;
+ }
+
+ adapter->vpd->dma_addr =
+ dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, dma_addr)) {
+ dev_err(dev, "Could not map VPD buffer\n");
+ return -ENOMEM;
+ }
+
+ reinit_completion(&adapter->fw_done);
+ crq.get_vpd.first = IBMVNIC_CRQ_CMD;
+ crq.get_vpd.cmd = GET_VPD;
+ crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
+ crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
+ ibmvnic_send_crq(adapter, &crq);
+ wait_for_completion(&adapter->fw_done);
+
+ return 0;
+}
+
static int init_resources(struct ibmvnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
if (rc)
return rc;
+ adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
+ if (!adapter->vpd)
+ return -ENOMEM;
+
adapter->map_id = 1;
adapter->napi = kcalloc(adapter->req_rx_queues,
sizeof(struct napi_struct), GFP_KERNEL);
@@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
rc = __ibmvnic_open(netdev);
netif_carrier_on(netdev);
+
+ /* Vital Product Data (VPD) */
+ ibmvnic_get_vpd(adapter);
+
mutex_unlock(&adapter->reset_lock);
return rc;
@@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
return 0;
}
-static void ibmvnic_get_drvinfo(struct net_device *dev,
+static void ibmvnic_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
+ struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, adapter->fw_version,
+ sizeof(info->fw_version));
}
static u32 ibmvnic_get_msglevel(struct net_device *netdev)
@@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
ibmvnic_send_crq(adapter, &crq);
}
+static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
+ struct ibmvnic_adapter *adapter)
+{
+ struct device *dev = &adapter->vdev->dev;
+
+ if (crq->get_vpd_size_rsp.rc.code) {
+ dev_err(dev, "Error retrieving VPD size, rc=%x\n",
+ crq->get_vpd_size_rsp.rc.code);
+ complete(&adapter->fw_done);
+ return;
+ }
+
+ adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
+ complete(&adapter->fw_done);
+}
+
+static void handle_vpd_rsp(union ibmvnic_crq *crq,
+ struct ibmvnic_adapter *adapter)
+{
+ struct device *dev = &adapter->vdev->dev;
+ unsigned char *substr = NULL, *ptr = NULL;
+ u8 fw_level_len = 0;
+
+ dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
+ DMA_FROM_DEVICE);
+
+ if (crq->get_vpd_rsp.rc.code) {
+ dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
+ crq->get_vpd_rsp.rc.code);
+ memset(adapter->fw_version, 0, 32);
+ goto complete;
+ }
+
+ /* get the position of the firmware version info
+ * located after the ASCII 'RM' substring in the buffer
+ */
+ substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
+ if (!substr) {
+ dev_info(dev, "No FW level provided by VPD\n");
+ memset(adapter->fw_version, 0, 32);
+ goto complete;
+ }
+
+ /* get length of firmware level ASCII substring */
+ if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
+ fw_level_len = *(substr + 2);
+ } else {
+ dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
+ memset(adapter->fw_version, 0, 32);
+ goto complete;
+ }
+
+ /* copy firmware version string from vpd into adapter */
+ if ((substr + 3 + fw_level_len) <
+ (adapter->vpd->buff + adapter->vpd->len)) {
+ ptr = strncpy((char *)adapter->fw_version,
+ substr + 3, fw_level_len);
+
+ if (!ptr) {
+ dev_err(dev, "Failed to isolate FW level string\n");
+ memset(adapter->fw_version, 0, 32);
+ }
+ } else {
+ dev_info(dev, "FW substr extrapolated VPD buff\n");
+ memset(adapter->fw_version, 0, 32);
+ }
+
+complete:
+ complete(&adapter->fw_done);
+}
+
static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
{
struct device *dev = &adapter->vdev->dev;
@@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
netdev_dbg(netdev, "Got Collect firmware trace Response\n");
complete(&adapter->fw_done);
break;
+ case GET_VPD_SIZE_RSP:
+ handle_vpd_size_rsp(crq, adapter);
+ break;
+ case GET_VPD_RSP:
+ handle_vpd_rsp(crq, adapter);
+ break;
default:
netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
gen_crq->cmd);
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index 4670af8..d3a6959 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
struct ibmvnic_rc rc;
} __packed __aligned(8);
+struct ibmvnic_get_vpd_size {
+ u8 first;
+ u8 cmd;
+ u8 reserved[14];
+} __packed __aligned(8);
+
struct ibmvnic_get_vpd_size_rsp {
u8 first;
u8 cmd;
@@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
u8 reserved[4];
} __packed __aligned(8);
+struct ibmvnic_get_vpd_rsp {
+ u8 first;
+ u8 cmd;
+ u8 reserved[10];
+ struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
struct ibmvnic_acl_change_indication {
u8 first;
u8 cmd;
@@ -700,10 +713,10 @@ union ibmvnic_crq {
struct ibmvnic_change_mac_addr change_mac_addr_rsp;
struct ibmvnic_multicast_ctrl multicast_ctrl;
struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
- struct ibmvnic_generic_crq get_vpd_size;
+ struct ibmvnic_get_vpd_size get_vpd_size;
struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
struct ibmvnic_get_vpd get_vpd;
- struct ibmvnic_generic_crq get_vpd_rsp;
+ struct ibmvnic_get_vpd_rsp get_vpd_rsp;
struct ibmvnic_acl_change_indication acl_change_indication;
struct ibmvnic_acl_query acl_query;
struct ibmvnic_generic_crq acl_query_rsp;
@@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
__be32 error_id;
};
+struct ibmvnic_vpd {
+ unsigned char *buff;
+ dma_addr_t dma_addr;
+ u64 len;
+};
+
enum vnic_state {VNIC_PROBING = 1,
VNIC_PROBED,
VNIC_OPENING,
@@ -978,6 +997,10 @@ struct ibmvnic_adapter {
dma_addr_t ip_offload_ctrl_tok;
u32 msg_enable;
+ /* Vital Product Data (VPD) */
+ struct ibmvnic_vpd *vpd;
+ char fw_version[32];
+
/* Statistics */
struct ibmvnic_statistics stats;
dma_addr_t stats_token;
--
2.9.5
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
2017-11-09 19:00 ` [PATCH] [net-next, v3] " Desnes Augusto Nunes do Rosario
(?)
@ 2017-11-09 19:20 ` Tushar Dave
-1 siblings, 0 replies; 8+ messages in thread
From: Tushar Dave @ 2017-11-09 19:20 UTC (permalink / raw)
To: Desnes Augusto Nunes do Rosario, netdev
Cc: linuxppc-dev, tlfalcon, nfont, jallen
On 11/09/2017 11:00 AM, Desnes Augusto Nunes do Rosario wrote:
> This patch implements and enables VDP support for the ibmvnic driver.
> Moreover, it includes the implementation of suitable structs, signal
> transmission/handling and functions which allows the retrival of firmware
> information from the ibmvnic card through the ethtool command.
>
> Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
> ---
> drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
> drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
> 2 files changed, 173 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
> index d0cff28..693b502 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.c
> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
> @@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
> return 0;
> }
>
> +static void release_vpd_data(struct ibmvnic_adapter *adapter)
> +{
> + if (!adapter->vpd)
> + return;
> +
> + kfree(adapter->vpd->buff);
> + kfree(adapter->vpd);
> +}
> +
> static void release_tx_pools(struct ibmvnic_adapter *adapter)
> {
> struct ibmvnic_tx_pool *tx_pool;
> @@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
> {
> int i;
>
> + release_vpd_data(adapter);
> +
> release_tx_pools(adapter);
> release_rx_pools(adapter);
>
> @@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
> return rc;
> }
>
> +static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
> +{
> + struct device *dev = &adapter->vdev->dev;
> + union ibmvnic_crq crq;
> + dma_addr_t dma_addr;
> + int len;
> +
> + if (adapter->vpd->buff)
> + len = adapter->vpd->len;
> +
> + reinit_completion(&adapter->fw_done);
> + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
> + crq.get_vpd_size.cmd = GET_VPD_SIZE;
> + ibmvnic_send_crq(adapter, &crq);
> + wait_for_completion(&adapter->fw_done);
> +
> + if (!adapter->vpd->buff)
> + adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
> + else if (adapter->vpd->len != len)
> + adapter->vpd->buff =
> + krealloc(adapter->vpd->buff,
> + adapter->vpd->len, GFP_KERNEL);
> +
> + if (!adapter->vpd->buff) {
> + dev_err(dev, "Could allocate VPD buffer\n");
> + return -ENOMEM;
> + }
> +
> + adapter->vpd->dma_addr =
> + dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
> + DMA_FROM_DEVICE);
> + if (dma_mapping_error(dev, dma_addr)) {
> + dev_err(dev, "Could not map VPD buffer\n");
> + return -ENOMEM;
In this case, driver should release memory for adapter->vpd->buff.
> + }
> +
> + reinit_completion(&adapter->fw_done);
> + crq.get_vpd.first = IBMVNIC_CRQ_CMD;
> + crq.get_vpd.cmd = GET_VPD;
> + crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
> + crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
> + ibmvnic_send_crq(adapter, &crq);
> + wait_for_completion(&adapter->fw_done);
> +
> + return 0;
> +}
> +
> static int init_resources(struct ibmvnic_adapter *adapter)
> {
> struct net_device *netdev = adapter->netdev;
> @@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
> if (rc)
> return rc;
>
> + adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
> + if (!adapter->vpd)
> + return -ENOMEM;
> +
> adapter->map_id = 1;
> adapter->napi = kcalloc(adapter->req_rx_queues,
> sizeof(struct napi_struct), GFP_KERNEL);
> @@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
>
> rc = __ibmvnic_open(netdev);
> netif_carrier_on(netdev);
> +
> + /* Vital Product Data (VPD) */
> + ibmvnic_get_vpd(adapter);
May want to check return value from ibmvnic_get_vpd() ?
-Tushar
> +
> mutex_unlock(&adapter->reset_lock);
>
> return rc;
> @@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
> return 0;
> }
>
> -static void ibmvnic_get_drvinfo(struct net_device *dev,
> +static void ibmvnic_get_drvinfo(struct net_device *netdev,
> struct ethtool_drvinfo *info)
> {
> + struct ibmvnic_adapter *adapter = netdev_priv(netdev);
> +
> strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
> strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
> + strlcpy(info->fw_version, adapter->fw_version,
> + sizeof(info->fw_version));
> }
>
> static u32 ibmvnic_get_msglevel(struct net_device *netdev)
> @@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
> ibmvnic_send_crq(adapter, &crq);
> }
>
> +static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
> + struct ibmvnic_adapter *adapter)
> +{
> + struct device *dev = &adapter->vdev->dev;
> +
> + if (crq->get_vpd_size_rsp.rc.code) {
> + dev_err(dev, "Error retrieving VPD size, rc=%x\n",
> + crq->get_vpd_size_rsp.rc.code);
> + complete(&adapter->fw_done);
> + return;
> + }
> +
> + adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
> + complete(&adapter->fw_done);
> +}
> +
> +static void handle_vpd_rsp(union ibmvnic_crq *crq,
> + struct ibmvnic_adapter *adapter)
> +{
> + struct device *dev = &adapter->vdev->dev;
> + unsigned char *substr = NULL, *ptr = NULL;
> + u8 fw_level_len = 0;
> +
> + dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
> + DMA_FROM_DEVICE);
> +
> + if (crq->get_vpd_rsp.rc.code) {
> + dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
> + crq->get_vpd_rsp.rc.code);
> + memset(adapter->fw_version, 0, 32);
> + goto complete;
> + }
> +
> + /* get the position of the firmware version info
> + * located after the ASCII 'RM' substring in the buffer
> + */
> + substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
> + if (!substr) {
> + dev_info(dev, "No FW level provided by VPD\n");
> + memset(adapter->fw_version, 0, 32);
> + goto complete;
> + }
> +
> + /* get length of firmware level ASCII substring */
> + if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
> + fw_level_len = *(substr + 2);
> + } else {
> + dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
> + memset(adapter->fw_version, 0, 32);
> + goto complete;
> + }
> +
> + /* copy firmware version string from vpd into adapter */
> + if ((substr + 3 + fw_level_len) <
> + (adapter->vpd->buff + adapter->vpd->len)) {
> + ptr = strncpy((char *)adapter->fw_version,
> + substr + 3, fw_level_len);
> +
> + if (!ptr) {
> + dev_err(dev, "Failed to isolate FW level string\n");
> + memset(adapter->fw_version, 0, 32);
> + }
> + } else {
> + dev_info(dev, "FW substr extrapolated VPD buff\n");
> + memset(adapter->fw_version, 0, 32);
> + }
> +
> +complete:
> + complete(&adapter->fw_done);
> +}
> +
> static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
> {
> struct device *dev = &adapter->vdev->dev;
> @@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
> netdev_dbg(netdev, "Got Collect firmware trace Response\n");
> complete(&adapter->fw_done);
> break;
> + case GET_VPD_SIZE_RSP:
> + handle_vpd_size_rsp(crq, adapter);
> + break;
> + case GET_VPD_RSP:
> + handle_vpd_rsp(crq, adapter);
> + break;
> default:
> netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
> gen_crq->cmd);
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
> index 4670af8..d3a6959 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.h
> +++ b/drivers/net/ethernet/ibm/ibmvnic.h
> @@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
> struct ibmvnic_rc rc;
> } __packed __aligned(8);
>
> +struct ibmvnic_get_vpd_size {
> + u8 first;
> + u8 cmd;
> + u8 reserved[14];
> +} __packed __aligned(8);
> +
> struct ibmvnic_get_vpd_size_rsp {
> u8 first;
> u8 cmd;
> @@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
> u8 reserved[4];
> } __packed __aligned(8);
>
> +struct ibmvnic_get_vpd_rsp {
> + u8 first;
> + u8 cmd;
> + u8 reserved[10];
> + struct ibmvnic_rc rc;
> +} __packed __aligned(8);
> +
> struct ibmvnic_acl_change_indication {
> u8 first;
> u8 cmd;
> @@ -700,10 +713,10 @@ union ibmvnic_crq {
> struct ibmvnic_change_mac_addr change_mac_addr_rsp;
> struct ibmvnic_multicast_ctrl multicast_ctrl;
> struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
> - struct ibmvnic_generic_crq get_vpd_size;
> + struct ibmvnic_get_vpd_size get_vpd_size;
> struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
> struct ibmvnic_get_vpd get_vpd;
> - struct ibmvnic_generic_crq get_vpd_rsp;
> + struct ibmvnic_get_vpd_rsp get_vpd_rsp;
> struct ibmvnic_acl_change_indication acl_change_indication;
> struct ibmvnic_acl_query acl_query;
> struct ibmvnic_generic_crq acl_query_rsp;
> @@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
> __be32 error_id;
> };
>
> +struct ibmvnic_vpd {
> + unsigned char *buff;
> + dma_addr_t dma_addr;
> + u64 len;
> +};
> +
> enum vnic_state {VNIC_PROBING = 1,
> VNIC_PROBED,
> VNIC_OPENING,
> @@ -978,6 +997,10 @@ struct ibmvnic_adapter {
> dma_addr_t ip_offload_ctrl_tok;
> u32 msg_enable;
>
> + /* Vital Product Data (VPD) */
> + struct ibmvnic_vpd *vpd;
> + char fw_version[32];
> +
> /* Statistics */
> struct ibmvnic_statistics stats;
> dma_addr_t stats_token;
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
2017-11-09 19:00 ` [PATCH] [net-next, v3] " Desnes Augusto Nunes do Rosario
(?)
(?)
@ 2017-11-09 20:31 ` Nathan Fontenot
2017-11-10 14:41 ` Desnes Augusto Nunes do Rosário
-1 siblings, 1 reply; 8+ messages in thread
From: Nathan Fontenot @ 2017-11-09 20:31 UTC (permalink / raw)
To: Desnes Augusto Nunes do Rosario, netdev; +Cc: linuxppc-dev, tlfalcon, jallen
On 11/09/2017 01:00 PM, Desnes Augusto Nunes do Rosario wrote:
> This patch implements and enables VDP support for the ibmvnic driver.
> Moreover, it includes the implementation of suitable structs, signal
> transmission/handling and functions which allows the retrival of firmware
> information from the ibmvnic card through the ethtool command.
>
> Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
> ---
> drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
> drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
> 2 files changed, 173 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
> index d0cff28..693b502 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.c
> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
> @@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
> return 0;
> }
>
> +static void release_vpd_data(struct ibmvnic_adapter *adapter)
> +{
> + if (!adapter->vpd)
> + return;
> +
> + kfree(adapter->vpd->buff);
> + kfree(adapter->vpd);
> +}
> +
> static void release_tx_pools(struct ibmvnic_adapter *adapter)
> {
> struct ibmvnic_tx_pool *tx_pool;
> @@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
> {
> int i;
>
> + release_vpd_data(adapter);
> +
> release_tx_pools(adapter);
> release_rx_pools(adapter);
>
> @@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
> return rc;
> }
>
> +static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
> +{
> + struct device *dev = &adapter->vdev->dev;
> + union ibmvnic_crq crq;
> + dma_addr_t dma_addr;
> + int len;
> +
> + if (adapter->vpd->buff)
> + len = adapter->vpd->len;
> +
> + reinit_completion(&adapter->fw_done);
> + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
> + crq.get_vpd_size.cmd = GET_VPD_SIZE;
> + ibmvnic_send_crq(adapter, &crq);
> + wait_for_completion(&adapter->fw_done);
> +
Shouldn't there be a check for the return code when getting the
vpd size?
> + if (!adapter->vpd->buff)
> + adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
> + else if (adapter->vpd->len != len)
> + adapter->vpd->buff =
> + krealloc(adapter->vpd->buff,
> + adapter->vpd->len, GFP_KERNEL);
> +
> + if (!adapter->vpd->buff) {
> + dev_err(dev, "Could allocate VPD buffer\n");
> + return -ENOMEM;
> + }
> +
> + adapter->vpd->dma_addr =
> + dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
> + DMA_FROM_DEVICE);
> + if (dma_mapping_error(dev, dma_addr)) {
> + dev_err(dev, "Could not map VPD buffer\n");
> + return -ENOMEM;
> + }
> +
> + reinit_completion(&adapter->fw_done);
> + crq.get_vpd.first = IBMVNIC_CRQ_CMD;
> + crq.get_vpd.cmd = GET_VPD;
> + crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
> + crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
> + ibmvnic_send_crq(adapter, &crq);
> + wait_for_completion(&adapter->fw_done);
> +
> + return 0;
> +}
> +
> static int init_resources(struct ibmvnic_adapter *adapter)
> {
> struct net_device *netdev = adapter->netdev;
> @@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
> if (rc)
> return rc;
>
> + adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
> + if (!adapter->vpd)
> + return -ENOMEM;
> +
> adapter->map_id = 1;
> adapter->napi = kcalloc(adapter->req_rx_queues,
> sizeof(struct napi_struct), GFP_KERNEL);
> @@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
>
> rc = __ibmvnic_open(netdev);
> netif_carrier_on(netdev);
> +
> + /* Vital Product Data (VPD) */
> + ibmvnic_get_vpd(adapter);
> +
> mutex_unlock(&adapter->reset_lock);
>
> return rc;
> @@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
> return 0;
> }
>
> -static void ibmvnic_get_drvinfo(struct net_device *dev,
> +static void ibmvnic_get_drvinfo(struct net_device *netdev,
> struct ethtool_drvinfo *info)
> {
> + struct ibmvnic_adapter *adapter = netdev_priv(netdev);
> +
> strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
> strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
> + strlcpy(info->fw_version, adapter->fw_version,
> + sizeof(info->fw_version));
> }
>
> static u32 ibmvnic_get_msglevel(struct net_device *netdev)
> @@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
> ibmvnic_send_crq(adapter, &crq);
> }
>
> +static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
> + struct ibmvnic_adapter *adapter)
> +{
> + struct device *dev = &adapter->vdev->dev;
> +
> + if (crq->get_vpd_size_rsp.rc.code) {
> + dev_err(dev, "Error retrieving VPD size, rc=%x\n",
> + crq->get_vpd_size_rsp.rc.code);
> + complete(&adapter->fw_done);
> + return;
> + }
> +
> + adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
> + complete(&adapter->fw_done);
> +}
> +
> +static void handle_vpd_rsp(union ibmvnic_crq *crq,
> + struct ibmvnic_adapter *adapter)
> +{
> + struct device *dev = &adapter->vdev->dev;
> + unsigned char *substr = NULL, *ptr = NULL;
> + u8 fw_level_len = 0;
> +
> + dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
> + DMA_FROM_DEVICE);
> +
> + if (crq->get_vpd_rsp.rc.code) {
> + dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
> + crq->get_vpd_rsp.rc.code);
> + memset(adapter->fw_version, 0, 32);
> + goto complete;
> + }
> +
> + /* get the position of the firmware version info
> + * located after the ASCII 'RM' substring in the buffer
> + */
> + substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
> + if (!substr) {
> + dev_info(dev, "No FW level provided by VPD\n");
> + memset(adapter->fw_version, 0, 32);
> + goto complete;
> + }
> +
> + /* get length of firmware level ASCII substring */
> + if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
> + fw_level_len = *(substr + 2);
> + } else {
> + dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
> + memset(adapter->fw_version, 0, 32);
> + goto complete;
> + }
> +
> + /* copy firmware version string from vpd into adapter */
> + if ((substr + 3 + fw_level_len) <
> + (adapter->vpd->buff + adapter->vpd->len)) {
> + ptr = strncpy((char *)adapter->fw_version,
> + substr + 3, fw_level_len);
> +
> + if (!ptr) {
> + dev_err(dev, "Failed to isolate FW level string\n");
> + memset(adapter->fw_version, 0, 32);
> + }
> + } else {
> + dev_info(dev, "FW substr extrapolated VPD buff\n");
> + memset(adapter->fw_version, 0, 32);
> + }
> +
> +complete:
> + complete(&adapter->fw_done);
> +}
> +
> static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
> {
> struct device *dev = &adapter->vdev->dev;
> @@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
> netdev_dbg(netdev, "Got Collect firmware trace Response\n");
> complete(&adapter->fw_done);
> break;
> + case GET_VPD_SIZE_RSP:
> + handle_vpd_size_rsp(crq, adapter);
> + break;
> + case GET_VPD_RSP:
> + handle_vpd_rsp(crq, adapter);
> + break;
> default:
> netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
> gen_crq->cmd);
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
> index 4670af8..d3a6959 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.h
> +++ b/drivers/net/ethernet/ibm/ibmvnic.h
> @@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
> struct ibmvnic_rc rc;
> } __packed __aligned(8);
>
> +struct ibmvnic_get_vpd_size {
> + u8 first;
> + u8 cmd;
> + u8 reserved[14];
> +} __packed __aligned(8);
> +
> struct ibmvnic_get_vpd_size_rsp {
> u8 first;
> u8 cmd;
> @@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
> u8 reserved[4];
> } __packed __aligned(8);
>
> +struct ibmvnic_get_vpd_rsp {
> + u8 first;
> + u8 cmd;
> + u8 reserved[10];
> + struct ibmvnic_rc rc;
> +} __packed __aligned(8);
> +
> struct ibmvnic_acl_change_indication {
> u8 first;
> u8 cmd;
> @@ -700,10 +713,10 @@ union ibmvnic_crq {
> struct ibmvnic_change_mac_addr change_mac_addr_rsp;
> struct ibmvnic_multicast_ctrl multicast_ctrl;
> struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
> - struct ibmvnic_generic_crq get_vpd_size;
> + struct ibmvnic_get_vpd_size get_vpd_size;
> struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
> struct ibmvnic_get_vpd get_vpd;
> - struct ibmvnic_generic_crq get_vpd_rsp;
> + struct ibmvnic_get_vpd_rsp get_vpd_rsp;
> struct ibmvnic_acl_change_indication acl_change_indication;
> struct ibmvnic_acl_query acl_query;
> struct ibmvnic_generic_crq acl_query_rsp;
> @@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
> __be32 error_id;
> };
>
> +struct ibmvnic_vpd {
> + unsigned char *buff;
> + dma_addr_t dma_addr;
> + u64 len;
> +};
> +
> enum vnic_state {VNIC_PROBING = 1,
> VNIC_PROBED,
> VNIC_OPENING,
> @@ -978,6 +997,10 @@ struct ibmvnic_adapter {
> dma_addr_t ip_offload_ctrl_tok;
> u32 msg_enable;
>
> + /* Vital Product Data (VPD) */
> + struct ibmvnic_vpd *vpd;
> + char fw_version[32];
> +
> /* Statistics */
> struct ibmvnic_statistics stats;
> dma_addr_t stats_token;
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
2017-11-09 20:31 ` Nathan Fontenot
@ 2017-11-10 14:41 ` Desnes Augusto Nunes do Rosário
2017-11-10 14:54 ` Nathan Fontenot
0 siblings, 1 reply; 8+ messages in thread
From: Desnes Augusto Nunes do Rosário @ 2017-11-10 14:41 UTC (permalink / raw)
To: Nathan Fontenot, netdev; +Cc: linuxppc-dev, tlfalcon, jallen
On 11/09/2017 06:31 PM, Nathan Fontenot wrote:
> On 11/09/2017 01:00 PM, Desnes Augusto Nunes do Rosario wrote:
>> This patch implements and enables VDP support for the ibmvnic driver.
>> Moreover, it includes the implementation of suitable structs, signal
>> transmission/handling and functions which allows the retrival of firmware
>> information from the ibmvnic card through the ethtool command.
>>
>> Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
>> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
>> ---
>> drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
>> drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
>> 2 files changed, 173 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
>> index d0cff28..693b502 100644
>> --- a/drivers/net/ethernet/ibm/ibmvnic.c
>> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
>> @@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
>> return 0;
>> }
>>
>> +static void release_vpd_data(struct ibmvnic_adapter *adapter)
>> +{
>> + if (!adapter->vpd)
>> + return;
>> +
>> + kfree(adapter->vpd->buff);
>> + kfree(adapter->vpd);
>> +}
>> +
>> static void release_tx_pools(struct ibmvnic_adapter *adapter)
>> {
>> struct ibmvnic_tx_pool *tx_pool;
>> @@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
>> {
>> int i;
>>
>> + release_vpd_data(adapter);
>> +
>> release_tx_pools(adapter);
>> release_rx_pools(adapter);
>>
>> @@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
>> return rc;
>> }
>>
>> +static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
>> +{
>> + struct device *dev = &adapter->vdev->dev;
>> + union ibmvnic_crq crq;
>> + dma_addr_t dma_addr;
>> + int len;
>> +
>> + if (adapter->vpd->buff)
>> + len = adapter->vpd->len;
>> +
>> + reinit_completion(&adapter->fw_done);
>> + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
>> + crq.get_vpd_size.cmd = GET_VPD_SIZE;
>> + ibmvnic_send_crq(adapter, &crq);
>> + wait_for_completion(&adapter->fw_done);
>> +
>
> Shouldn't there be a check for the return code when getting the
> vpd size?
Hello Nathan,
This check is already being performed on the handle_vpd_size_rsp()
function down below.
In short, a GET_VPD_SIZE signal is sent here through a ibmvnic_crq union
in ibmvnic_send_crq(), whereas handle_query_ip_offload_rsp() receives
from the VNIC adapter a GET_VPD_SIZE_RSP containing a ibmvnic_crq union
with the vpd size information and the rc.code. If successful, a
&adapter->fw_done is sent and this part of the code continues; however
if not, a dev_error() is thrown. Same logic applies to GET_VPD/GET_VPD_RSP.
What I am adding on the next version of the patch is a check if
adapter->vpd->len is different than 0 before allocating
adapter->vpd->buff, since that in a case of a failure, adapter->vpd->len
will be 0.
Best Regards,
>
>
>> + if (!adapter->vpd->buff)
>> + adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
>> + else if (adapter->vpd->len != len)
>> + adapter->vpd->buff =
>> + krealloc(adapter->vpd->buff,
>> + adapter->vpd->len, GFP_KERNEL);
>> +
>> + if (!adapter->vpd->buff) {
>> + dev_err(dev, "Could allocate VPD buffer\n");
>> + return -ENOMEM;
>> + }
>> +
>> + adapter->vpd->dma_addr =
>> + dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
>> + DMA_FROM_DEVICE);
>> + if (dma_mapping_error(dev, dma_addr)) {
>> + dev_err(dev, "Could not map VPD buffer\n");
>> + return -ENOMEM;
>> + }
>> +
>> + reinit_completion(&adapter->fw_done);
>> + crq.get_vpd.first = IBMVNIC_CRQ_CMD;
>> + crq.get_vpd.cmd = GET_VPD;
>> + crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
>> + crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
>> + ibmvnic_send_crq(adapter, &crq);
>> + wait_for_completion(&adapter->fw_done);
>> +
>> + return 0;
>> +}
>> +
>> static int init_resources(struct ibmvnic_adapter *adapter)
>> {
>> struct net_device *netdev = adapter->netdev;
>> @@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
>> if (rc)
>> return rc;
>>
>> + adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
>> + if (!adapter->vpd)
>> + return -ENOMEM;
>> +
>> adapter->map_id = 1;
>> adapter->napi = kcalloc(adapter->req_rx_queues,
>> sizeof(struct napi_struct), GFP_KERNEL);
>> @@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
>>
>> rc = __ibmvnic_open(netdev);
>> netif_carrier_on(netdev);
>> +
>> + /* Vital Product Data (VPD) */
>> + ibmvnic_get_vpd(adapter);
>> +
>> mutex_unlock(&adapter->reset_lock);
>>
>> return rc;
>> @@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
>> return 0;
>> }
>>
>> -static void ibmvnic_get_drvinfo(struct net_device *dev,
>> +static void ibmvnic_get_drvinfo(struct net_device *netdev,
>> struct ethtool_drvinfo *info)
>> {
>> + struct ibmvnic_adapter *adapter = netdev_priv(netdev);
>> +
>> strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
>> strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
>> + strlcpy(info->fw_version, adapter->fw_version,
>> + sizeof(info->fw_version));
>> }
>>
>> static u32 ibmvnic_get_msglevel(struct net_device *netdev)
>> @@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
>> ibmvnic_send_crq(adapter, &crq);
>> }
>>
>> +static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
>> + struct ibmvnic_adapter *adapter)
>> +{
>> + struct device *dev = &adapter->vdev->dev;
>> +
>> + if (crq->get_vpd_size_rsp.rc.code) {
>> + dev_err(dev, "Error retrieving VPD size, rc=%x\n",
>> + crq->get_vpd_size_rsp.rc.code);
>> + complete(&adapter->fw_done);
>> + return;
>> + }
>> +
>> + adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
>> + complete(&adapter->fw_done);
>> +}
>> +
>> +static void handle_vpd_rsp(union ibmvnic_crq *crq,
>> + struct ibmvnic_adapter *adapter)
>> +{
>> + struct device *dev = &adapter->vdev->dev;
>> + unsigned char *substr = NULL, *ptr = NULL;
>> + u8 fw_level_len = 0;
>> +
>> + dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
>> + DMA_FROM_DEVICE);
>> +
>> + if (crq->get_vpd_rsp.rc.code) {
>> + dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
>> + crq->get_vpd_rsp.rc.code);
>> + memset(adapter->fw_version, 0, 32);
>> + goto complete;
>> + }
>> +
>> + /* get the position of the firmware version info
>> + * located after the ASCII 'RM' substring in the buffer
>> + */
>> + substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
>> + if (!substr) {
>> + dev_info(dev, "No FW level provided by VPD\n");
>> + memset(adapter->fw_version, 0, 32);
>> + goto complete;
>> + }
>> +
>> + /* get length of firmware level ASCII substring */
>> + if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
>> + fw_level_len = *(substr + 2);
>> + } else {
>> + dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
>> + memset(adapter->fw_version, 0, 32);
>> + goto complete;
>> + }
>> +
>> + /* copy firmware version string from vpd into adapter */
>> + if ((substr + 3 + fw_level_len) <
>> + (adapter->vpd->buff + adapter->vpd->len)) {
>> + ptr = strncpy((char *)adapter->fw_version,
>> + substr + 3, fw_level_len);
>> +
>> + if (!ptr) {
>> + dev_err(dev, "Failed to isolate FW level string\n");
>> + memset(adapter->fw_version, 0, 32);
>> + }
>> + } else {
>> + dev_info(dev, "FW substr extrapolated VPD buff\n");
>> + memset(adapter->fw_version, 0, 32);
>> + }
>> +
>> +complete:
>> + complete(&adapter->fw_done);
>> +}
>> +
>> static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
>> {
>> struct device *dev = &adapter->vdev->dev;
>> @@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
>> netdev_dbg(netdev, "Got Collect firmware trace Response\n");
>> complete(&adapter->fw_done);
>> break;
>> + case GET_VPD_SIZE_RSP:
>> + handle_vpd_size_rsp(crq, adapter);
>> + break;
>> + case GET_VPD_RSP:
>> + handle_vpd_rsp(crq, adapter);
>> + break;
>> default:
>> netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
>> gen_crq->cmd);
>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
>> index 4670af8..d3a6959 100644
>> --- a/drivers/net/ethernet/ibm/ibmvnic.h
>> +++ b/drivers/net/ethernet/ibm/ibmvnic.h
>> @@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
>> struct ibmvnic_rc rc;
>> } __packed __aligned(8);
>>
>> +struct ibmvnic_get_vpd_size {
>> + u8 first;
>> + u8 cmd;
>> + u8 reserved[14];
>> +} __packed __aligned(8);
>> +
>> struct ibmvnic_get_vpd_size_rsp {
>> u8 first;
>> u8 cmd;
>> @@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
>> u8 reserved[4];
>> } __packed __aligned(8);
>>
>> +struct ibmvnic_get_vpd_rsp {
>> + u8 first;
>> + u8 cmd;
>> + u8 reserved[10];
>> + struct ibmvnic_rc rc;
>> +} __packed __aligned(8);
>> +
>> struct ibmvnic_acl_change_indication {
>> u8 first;
>> u8 cmd;
>> @@ -700,10 +713,10 @@ union ibmvnic_crq {
>> struct ibmvnic_change_mac_addr change_mac_addr_rsp;
>> struct ibmvnic_multicast_ctrl multicast_ctrl;
>> struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
>> - struct ibmvnic_generic_crq get_vpd_size;
>> + struct ibmvnic_get_vpd_size get_vpd_size;
>> struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
>> struct ibmvnic_get_vpd get_vpd;
>> - struct ibmvnic_generic_crq get_vpd_rsp;
>> + struct ibmvnic_get_vpd_rsp get_vpd_rsp;
>> struct ibmvnic_acl_change_indication acl_change_indication;
>> struct ibmvnic_acl_query acl_query;
>> struct ibmvnic_generic_crq acl_query_rsp;
>> @@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
>> __be32 error_id;
>> };
>>
>> +struct ibmvnic_vpd {
>> + unsigned char *buff;
>> + dma_addr_t dma_addr;
>> + u64 len;
>> +};
>> +
>> enum vnic_state {VNIC_PROBING = 1,
>> VNIC_PROBED,
>> VNIC_OPENING,
>> @@ -978,6 +997,10 @@ struct ibmvnic_adapter {
>> dma_addr_t ip_offload_ctrl_tok;
>> u32 msg_enable;
>>
>> + /* Vital Product Data (VPD) */
>> + struct ibmvnic_vpd *vpd;
>> + char fw_version[32];
>> +
>> /* Statistics */
>> struct ibmvnic_statistics stats;
>> dma_addr_t stats_token;
>>
--
Desnes Augusto Nunes do Rosário
------------------------------------------
Linux Developer - IBM / Brazil
M.Sc. in Electrical and Computer Engineering - UFRN
desnesn@br.ibm.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
2017-11-10 14:41 ` Desnes Augusto Nunes do Rosário
@ 2017-11-10 14:54 ` Nathan Fontenot
2017-11-10 19:13 ` Desnes Augusto Nunes do Rosário
0 siblings, 1 reply; 8+ messages in thread
From: Nathan Fontenot @ 2017-11-10 14:54 UTC (permalink / raw)
To: Desnes Augusto Nunes do Rosário, netdev
Cc: tlfalcon, linuxppc-dev, jallen
On 11/10/2017 08:41 AM, Desnes Augusto Nunes do Rosário wrote:
>
>
> On 11/09/2017 06:31 PM, Nathan Fontenot wrote:
>> On 11/09/2017 01:00 PM, Desnes Augusto Nunes do Rosario wrote:
>>> This patch implements and enables VDP support for the ibmvnic driver.
>>> Moreover, it includes the implementation of suitable structs, signal
>>> transmission/handling and functions which allows the retrival of firmware
>>> information from the ibmvnic card through the ethtool command.
>>>
>>> Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
>>> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
>>> ---
>>> drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
>>> drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
>>> 2 files changed, 173 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
>>> index d0cff28..693b502 100644
>>> --- a/drivers/net/ethernet/ibm/ibmvnic.c
>>> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
>>> @@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
>>> return 0;
>>> }
>>>
>>> +static void release_vpd_data(struct ibmvnic_adapter *adapter)
>>> +{
>>> + if (!adapter->vpd)
>>> + return;
>>> +
>>> + kfree(adapter->vpd->buff);
>>> + kfree(adapter->vpd);
>>> +}
>>> +
>>> static void release_tx_pools(struct ibmvnic_adapter *adapter)
>>> {
>>> struct ibmvnic_tx_pool *tx_pool;
>>> @@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
>>> {
>>> int i;
>>>
>>> + release_vpd_data(adapter);
>>> +
>>> release_tx_pools(adapter);
>>> release_rx_pools(adapter);
>>>
>>> @@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
>>> return rc;
>>> }
>>>
>>> +static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
>>> +{
>>> + struct device *dev = &adapter->vdev->dev;
>>> + union ibmvnic_crq crq;
>>> + dma_addr_t dma_addr;
>>> + int len;
>>> +
>>> + if (adapter->vpd->buff)
>>> + len = adapter->vpd->len;
>>> +
>>> + reinit_completion(&adapter->fw_done);
>>> + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
>>> + crq.get_vpd_size.cmd = GET_VPD_SIZE;
>>> + ibmvnic_send_crq(adapter, &crq);
>>> + wait_for_completion(&adapter->fw_done);
>>> +
>>
>> Shouldn't there be a check for the return code when getting the
>> vpd size?
>
> Hello Nathan,
>
> This check is already being performed on the handle_vpd_size_rsp() function down below.
>
> In short, a GET_VPD_SIZE signal is sent here through a ibmvnic_crq union in ibmvnic_send_crq(), whereas handle_query_ip_offload_rsp() receives from the VNIC adapter a GET_VPD_SIZE_RSP containing a ibmvnic_crq union with the vpd size information and the rc.code. If successful, a &adapter->fw_done is sent and this part of the code continues; however if not, a dev_error() is thrown. Same logic applies to GET_VPD/GET_VPD_RSP.
>
Yes, I did see that code. You do a complet of the completion variable for both success and failure,
this then lets this routine continue irregardless of the results of the get vpd size request. The
call to dev_err will print the error message but does not prevent use from bailing if the
get vpd size fails. Perhaps setting vpd->len to -1 to indicate the get vpd call failed which could
then be checked by the requester.
-Nathan
> What I am adding on the next version of the patch is a check if adapter->vpd->len is different than 0 before allocating adapter->vpd->buff, since that in a case of a failure, adapter->vpd->len will be 0.
>
> Best Regards,
>
>>
>>
>>> + if (!adapter->vpd->buff)
>>> + adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
>>> + else if (adapter->vpd->len != len)
>>> + adapter->vpd->buff =
>>> + krealloc(adapter->vpd->buff,
>>> + adapter->vpd->len, GFP_KERNEL);
>>> +
>>> + if (!adapter->vpd->buff) {
>>> + dev_err(dev, "Could allocate VPD buffer\n");
>>> + return -ENOMEM;
>>> + }
>>> +
>>> + adapter->vpd->dma_addr =
>>> + dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
>>> + DMA_FROM_DEVICE);
>>> + if (dma_mapping_error(dev, dma_addr)) {
>>> + dev_err(dev, "Could not map VPD buffer\n");
>>> + return -ENOMEM;
>>> + }
>>> +
>>> + reinit_completion(&adapter->fw_done);
>>> + crq.get_vpd.first = IBMVNIC_CRQ_CMD;
>>> + crq.get_vpd.cmd = GET_VPD;
>>> + crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
>>> + crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
>>> + ibmvnic_send_crq(adapter, &crq);
>>> + wait_for_completion(&adapter->fw_done);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static int init_resources(struct ibmvnic_adapter *adapter)
>>> {
>>> struct net_device *netdev = adapter->netdev;
>>> @@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
>>> if (rc)
>>> return rc;
>>>
>>> + adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
>>> + if (!adapter->vpd)
>>> + return -ENOMEM;
>>> +
>>> adapter->map_id = 1;
>>> adapter->napi = kcalloc(adapter->req_rx_queues,
>>> sizeof(struct napi_struct), GFP_KERNEL);
>>> @@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
>>>
>>> rc = __ibmvnic_open(netdev);
>>> netif_carrier_on(netdev);
>>> +
>>> + /* Vital Product Data (VPD) */
>>> + ibmvnic_get_vpd(adapter);
>>> +
>>> mutex_unlock(&adapter->reset_lock);
>>>
>>> return rc;
>>> @@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
>>> return 0;
>>> }
>>>
>>> -static void ibmvnic_get_drvinfo(struct net_device *dev,
>>> +static void ibmvnic_get_drvinfo(struct net_device *netdev,
>>> struct ethtool_drvinfo *info)
>>> {
>>> + struct ibmvnic_adapter *adapter = netdev_priv(netdev);
>>> +
>>> strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
>>> strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
>>> + strlcpy(info->fw_version, adapter->fw_version,
>>> + sizeof(info->fw_version));
>>> }
>>>
>>> static u32 ibmvnic_get_msglevel(struct net_device *netdev)
>>> @@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
>>> ibmvnic_send_crq(adapter, &crq);
>>> }
>>>
>>> +static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
>>> + struct ibmvnic_adapter *adapter)
>>> +{
>>> + struct device *dev = &adapter->vdev->dev;
>>> +
>>> + if (crq->get_vpd_size_rsp.rc.code) {
>>> + dev_err(dev, "Error retrieving VPD size, rc=%x\n",
>>> + crq->get_vpd_size_rsp.rc.code);
>>> + complete(&adapter->fw_done);
>>> + return;
>>> + }
>>> +
>>> + adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
>>> + complete(&adapter->fw_done);
>>> +}
>>> +
>>> +static void handle_vpd_rsp(union ibmvnic_crq *crq,
>>> + struct ibmvnic_adapter *adapter)
>>> +{
>>> + struct device *dev = &adapter->vdev->dev;
>>> + unsigned char *substr = NULL, *ptr = NULL;
>>> + u8 fw_level_len = 0;
>>> +
>>> + dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
>>> + DMA_FROM_DEVICE);
>>> +
>>> + if (crq->get_vpd_rsp.rc.code) {
>>> + dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
>>> + crq->get_vpd_rsp.rc.code);
>>> + memset(adapter->fw_version, 0, 32);
>>> + goto complete;
>>> + }
>>> +
>>> + /* get the position of the firmware version info
>>> + * located after the ASCII 'RM' substring in the buffer
>>> + */
>>> + substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
>>> + if (!substr) {
>>> + dev_info(dev, "No FW level provided by VPD\n");
>>> + memset(adapter->fw_version, 0, 32);
>>> + goto complete;
>>> + }
>>> +
>>> + /* get length of firmware level ASCII substring */
>>> + if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
>>> + fw_level_len = *(substr + 2);
>>> + } else {
>>> + dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
>>> + memset(adapter->fw_version, 0, 32);
>>> + goto complete;
>>> + }
>>> +
>>> + /* copy firmware version string from vpd into adapter */
>>> + if ((substr + 3 + fw_level_len) <
>>> + (adapter->vpd->buff + adapter->vpd->len)) {
>>> + ptr = strncpy((char *)adapter->fw_version,
>>> + substr + 3, fw_level_len);
>>> +
>>> + if (!ptr) {
>>> + dev_err(dev, "Failed to isolate FW level string\n");
>>> + memset(adapter->fw_version, 0, 32);
>>> + }
>>> + } else {
>>> + dev_info(dev, "FW substr extrapolated VPD buff\n");
>>> + memset(adapter->fw_version, 0, 32);
>>> + }
>>> +
>>> +complete:
>>> + complete(&adapter->fw_done);
>>> +}
>>> +
>>> static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
>>> {
>>> struct device *dev = &adapter->vdev->dev;
>>> @@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
>>> netdev_dbg(netdev, "Got Collect firmware trace Response\n");
>>> complete(&adapter->fw_done);
>>> break;
>>> + case GET_VPD_SIZE_RSP:
>>> + handle_vpd_size_rsp(crq, adapter);
>>> + break;
>>> + case GET_VPD_RSP:
>>> + handle_vpd_rsp(crq, adapter);
>>> + break;
>>> default:
>>> netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
>>> gen_crq->cmd);
>>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
>>> index 4670af8..d3a6959 100644
>>> --- a/drivers/net/ethernet/ibm/ibmvnic.h
>>> +++ b/drivers/net/ethernet/ibm/ibmvnic.h
>>> @@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
>>> struct ibmvnic_rc rc;
>>> } __packed __aligned(8);
>>>
>>> +struct ibmvnic_get_vpd_size {
>>> + u8 first;
>>> + u8 cmd;
>>> + u8 reserved[14];
>>> +} __packed __aligned(8);
>>> +
>>> struct ibmvnic_get_vpd_size_rsp {
>>> u8 first;
>>> u8 cmd;
>>> @@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
>>> u8 reserved[4];
>>> } __packed __aligned(8);
>>>
>>> +struct ibmvnic_get_vpd_rsp {
>>> + u8 first;
>>> + u8 cmd;
>>> + u8 reserved[10];
>>> + struct ibmvnic_rc rc;
>>> +} __packed __aligned(8);
>>> +
>>> struct ibmvnic_acl_change_indication {
>>> u8 first;
>>> u8 cmd;
>>> @@ -700,10 +713,10 @@ union ibmvnic_crq {
>>> struct ibmvnic_change_mac_addr change_mac_addr_rsp;
>>> struct ibmvnic_multicast_ctrl multicast_ctrl;
>>> struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
>>> - struct ibmvnic_generic_crq get_vpd_size;
>>> + struct ibmvnic_get_vpd_size get_vpd_size;
>>> struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
>>> struct ibmvnic_get_vpd get_vpd;
>>> - struct ibmvnic_generic_crq get_vpd_rsp;
>>> + struct ibmvnic_get_vpd_rsp get_vpd_rsp;
>>> struct ibmvnic_acl_change_indication acl_change_indication;
>>> struct ibmvnic_acl_query acl_query;
>>> struct ibmvnic_generic_crq acl_query_rsp;
>>> @@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
>>> __be32 error_id;
>>> };
>>>
>>> +struct ibmvnic_vpd {
>>> + unsigned char *buff;
>>> + dma_addr_t dma_addr;
>>> + u64 len;
>>> +};
>>> +
>>> enum vnic_state {VNIC_PROBING = 1,
>>> VNIC_PROBED,
>>> VNIC_OPENING,
>>> @@ -978,6 +997,10 @@ struct ibmvnic_adapter {
>>> dma_addr_t ip_offload_ctrl_tok;
>>> u32 msg_enable;
>>>
>>> + /* Vital Product Data (VPD) */
>>> + struct ibmvnic_vpd *vpd;
>>> + char fw_version[32];
>>> +
>>> /* Statistics */
>>> struct ibmvnic_statistics stats;
>>> dma_addr_t stats_token;
>>>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
2017-11-10 14:54 ` Nathan Fontenot
@ 2017-11-10 19:13 ` Desnes Augusto Nunes do Rosário
2017-11-13 14:58 ` Nathan Fontenot
0 siblings, 1 reply; 8+ messages in thread
From: Desnes Augusto Nunes do Rosário @ 2017-11-10 19:13 UTC (permalink / raw)
To: Nathan Fontenot, netdev; +Cc: tlfalcon, linuxppc-dev, jallen
On 11/10/2017 12:54 PM, Nathan Fontenot wrote:
> On 11/10/2017 08:41 AM, Desnes Augusto Nunes do Rosário wrote:
>>
>>
>> On 11/09/2017 06:31 PM, Nathan Fontenot wrote:
>>> On 11/09/2017 01:00 PM, Desnes Augusto Nunes do Rosario wrote:
>>>> This patch implements and enables VDP support for the ibmvnic driver.
>>>> Moreover, it includes the implementation of suitable structs, signal
>>>> transmission/handling and functions which allows the retrival of firmware
>>>> information from the ibmvnic card through the ethtool command.
>>>>
>>>> Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
>>>> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
>>>> ---
>>>> drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
>>>> drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
>>>> 2 files changed, 173 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
>>>> index d0cff28..693b502 100644
>>>> --- a/drivers/net/ethernet/ibm/ibmvnic.c
>>>> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
>>>> @@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
>>>> return 0;
>>>> }
>>>>
>>>> +static void release_vpd_data(struct ibmvnic_adapter *adapter)
>>>> +{
>>>> + if (!adapter->vpd)
>>>> + return;
>>>> +
>>>> + kfree(adapter->vpd->buff);
>>>> + kfree(adapter->vpd);
>>>> +}
>>>> +
>>>> static void release_tx_pools(struct ibmvnic_adapter *adapter)
>>>> {
>>>> struct ibmvnic_tx_pool *tx_pool;
>>>> @@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
>>>> {
>>>> int i;
>>>>
>>>> + release_vpd_data(adapter);
>>>> +
>>>> release_tx_pools(adapter);
>>>> release_rx_pools(adapter);
>>>>
>>>> @@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
>>>> return rc;
>>>> }
>>>>
>>>> +static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
>>>> +{
>>>> + struct device *dev = &adapter->vdev->dev;
>>>> + union ibmvnic_crq crq;
>>>> + dma_addr_t dma_addr;
>>>> + int len;
>>>> +
>>>> + if (adapter->vpd->buff)
>>>> + len = adapter->vpd->len;
>>>> +
>>>> + reinit_completion(&adapter->fw_done);
>>>> + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
>>>> + crq.get_vpd_size.cmd = GET_VPD_SIZE;
>>>> + ibmvnic_send_crq(adapter, &crq);
>>>> + wait_for_completion(&adapter->fw_done);
>>>> +
>>>
>>> Shouldn't there be a check for the return code when getting the
>>> vpd size?
>>
>> Hello Nathan,
>>
>> This check is already being performed on the handle_vpd_size_rsp() function down below.
>>
>> In short, a GET_VPD_SIZE signal is sent here through a ibmvnic_crq union in ibmvnic_send_crq(), whereas handle_query_ip_offload_rsp() receives from the VNIC adapter a GET_VPD_SIZE_RSP containing a ibmvnic_crq union with the vpd size information and the rc.code. If successful, a &adapter->fw_done is sent and this part of the code continues; however if not, a dev_error() is thrown. Same logic applies to GET_VPD/GET_VPD_RSP.
>>
>
> Yes, I did see that code. You do a complet of the completion variable for both success and failure,
> this then lets this routine continue irregardless of the results of the get vpd size request. The
> call to dev_err will print the error message but does not prevent use from bailing if the
> get vpd size fails. Perhaps setting vpd->len to -1 to indicate the get vpd call failed which could
> then be checked by the requester.
>
> -Nathan
>
> >> What I am adding on the next version of the patch is a check if
adapter->vpd->len is different than 0 before allocating
adapter->vpd->buff, since that in a case of a failure, adapter->vpd->len
will be 0.
I do concur with your observation that the break is necessary.
If the reception of vpd failed, adapter->vpd->len will be still zeroed
out since it was created with kzalloc in init_resources().
Thus, do you agree if in the next version I send the following code?
=======
+ reinit_completion(&adapter->fw_done);
+ crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
+ crq.get_vpd_size.cmd = GET_VPD_SIZE;
+ ibmvnic_send_crq(adapter, &crq);
+ wait_for_completion(&adapter->fw_done);
+
->+ if(!adapter->vpd->len)
->+ return -ENODATA;
+
+ if (!adapter->vpd->buff)
+ adapter->vpd->buff = kzalloc(adapter->vpd->len,
GFP_KERNEL);
+ else if (adapter->vpd->len != len)
+ adapter->vpd->buff =
+ krealloc(adapter->vpd->buff,
+ adapter->vpd->len, GFP_KERNEL);
=======
>>
>> Best Regards,
>>
>>>
>>>
>>>> + if (!adapter->vpd->buff)
>>>> + adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
>>>> + else if (adapter->vpd->len != len)
>>>> + adapter->vpd->buff =
>>>> + krealloc(adapter->vpd->buff,
>>>> + adapter->vpd->len, GFP_KERNEL);
>>>> +
>>>> + if (!adapter->vpd->buff) {
>>>> + dev_err(dev, "Could allocate VPD buffer\n");
>>>> + return -ENOMEM;
>>>> + }
>>>> +
>>>> + adapter->vpd->dma_addr =
>>>> + dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
>>>> + DMA_FROM_DEVICE);
>>>> + if (dma_mapping_error(dev, dma_addr)) {
>>>> + dev_err(dev, "Could not map VPD buffer\n");
>>>> + return -ENOMEM;
>>>> + }
>>>> +
>>>> + reinit_completion(&adapter->fw_done);
>>>> + crq.get_vpd.first = IBMVNIC_CRQ_CMD;
>>>> + crq.get_vpd.cmd = GET_VPD;
>>>> + crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
>>>> + crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
>>>> + ibmvnic_send_crq(adapter, &crq);
>>>> + wait_for_completion(&adapter->fw_done);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> static int init_resources(struct ibmvnic_adapter *adapter)
>>>> {
>>>> struct net_device *netdev = adapter->netdev;
>>>> @@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
>>>> if (rc)
>>>> return rc;
>>>>
>>>> + adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
>>>> + if (!adapter->vpd)
>>>> + return -ENOMEM;
>>>> +
>>>> adapter->map_id = 1;
>>>> adapter->napi = kcalloc(adapter->req_rx_queues,
>>>> sizeof(struct napi_struct), GFP_KERNEL);
>>>> @@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
>>>>
>>>> rc = __ibmvnic_open(netdev);
>>>> netif_carrier_on(netdev);
>>>> +
>>>> + /* Vital Product Data (VPD) */
>>>> + ibmvnic_get_vpd(adapter);
>>>> +
>>>> mutex_unlock(&adapter->reset_lock);
>>>>
>>>> return rc;
>>>> @@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
>>>> return 0;
>>>> }
>>>>
>>>> -static void ibmvnic_get_drvinfo(struct net_device *dev,
>>>> +static void ibmvnic_get_drvinfo(struct net_device *netdev,
>>>> struct ethtool_drvinfo *info)
>>>> {
>>>> + struct ibmvnic_adapter *adapter = netdev_priv(netdev);
>>>> +
>>>> strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
>>>> strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
>>>> + strlcpy(info->fw_version, adapter->fw_version,
>>>> + sizeof(info->fw_version));
>>>> }
>>>>
>>>> static u32 ibmvnic_get_msglevel(struct net_device *netdev)
>>>> @@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
>>>> ibmvnic_send_crq(adapter, &crq);
>>>> }
>>>>
>>>> +static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
>>>> + struct ibmvnic_adapter *adapter)
>>>> +{
>>>> + struct device *dev = &adapter->vdev->dev;
>>>> +
>>>> + if (crq->get_vpd_size_rsp.rc.code) {
>>>> + dev_err(dev, "Error retrieving VPD size, rc=%x\n",
>>>> + crq->get_vpd_size_rsp.rc.code);
>>>> + complete(&adapter->fw_done);
>>>> + return;
>>>> + }
>>>> +
>>>> + adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
>>>> + complete(&adapter->fw_done);
>>>> +}
>>>> +
>>>> +static void handle_vpd_rsp(union ibmvnic_crq *crq,
>>>> + struct ibmvnic_adapter *adapter)
>>>> +{
>>>> + struct device *dev = &adapter->vdev->dev;
>>>> + unsigned char *substr = NULL, *ptr = NULL;
>>>> + u8 fw_level_len = 0;
>>>> +
>>>> + dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
>>>> + DMA_FROM_DEVICE);
>>>> +
>>>> + if (crq->get_vpd_rsp.rc.code) {
>>>> + dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
>>>> + crq->get_vpd_rsp.rc.code);
>>>> + memset(adapter->fw_version, 0, 32);
>>>> + goto complete;
>>>> + }
>>>> +
>>>> + /* get the position of the firmware version info
>>>> + * located after the ASCII 'RM' substring in the buffer
>>>> + */
>>>> + substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
>>>> + if (!substr) {
>>>> + dev_info(dev, "No FW level provided by VPD\n");
>>>> + memset(adapter->fw_version, 0, 32);
>>>> + goto complete;
>>>> + }
>>>> +
>>>> + /* get length of firmware level ASCII substring */
>>>> + if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
>>>> + fw_level_len = *(substr + 2);
>>>> + } else {
>>>> + dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
>>>> + memset(adapter->fw_version, 0, 32);
>>>> + goto complete;
>>>> + }
>>>> +
>>>> + /* copy firmware version string from vpd into adapter */
>>>> + if ((substr + 3 + fw_level_len) <
>>>> + (adapter->vpd->buff + adapter->vpd->len)) {
>>>> + ptr = strncpy((char *)adapter->fw_version,
>>>> + substr + 3, fw_level_len);
>>>> +
>>>> + if (!ptr) {
>>>> + dev_err(dev, "Failed to isolate FW level string\n");
>>>> + memset(adapter->fw_version, 0, 32);
>>>> + }
>>>> + } else {
>>>> + dev_info(dev, "FW substr extrapolated VPD buff\n");
>>>> + memset(adapter->fw_version, 0, 32);
>>>> + }
>>>> +
>>>> +complete:
>>>> + complete(&adapter->fw_done);
>>>> +}
>>>> +
>>>> static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
>>>> {
>>>> struct device *dev = &adapter->vdev->dev;
>>>> @@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
>>>> netdev_dbg(netdev, "Got Collect firmware trace Response\n");
>>>> complete(&adapter->fw_done);
>>>> break;
>>>> + case GET_VPD_SIZE_RSP:
>>>> + handle_vpd_size_rsp(crq, adapter);
>>>> + break;
>>>> + case GET_VPD_RSP:
>>>> + handle_vpd_rsp(crq, adapter);
>>>> + break;
>>>> default:
>>>> netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
>>>> gen_crq->cmd);
>>>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
>>>> index 4670af8..d3a6959 100644
>>>> --- a/drivers/net/ethernet/ibm/ibmvnic.h
>>>> +++ b/drivers/net/ethernet/ibm/ibmvnic.h
>>>> @@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
>>>> struct ibmvnic_rc rc;
>>>> } __packed __aligned(8);
>>>>
>>>> +struct ibmvnic_get_vpd_size {
>>>> + u8 first;
>>>> + u8 cmd;
>>>> + u8 reserved[14];
>>>> +} __packed __aligned(8);
>>>> +
>>>> struct ibmvnic_get_vpd_size_rsp {
>>>> u8 first;
>>>> u8 cmd;
>>>> @@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
>>>> u8 reserved[4];
>>>> } __packed __aligned(8);
>>>>
>>>> +struct ibmvnic_get_vpd_rsp {
>>>> + u8 first;
>>>> + u8 cmd;
>>>> + u8 reserved[10];
>>>> + struct ibmvnic_rc rc;
>>>> +} __packed __aligned(8);
>>>> +
>>>> struct ibmvnic_acl_change_indication {
>>>> u8 first;
>>>> u8 cmd;
>>>> @@ -700,10 +713,10 @@ union ibmvnic_crq {
>>>> struct ibmvnic_change_mac_addr change_mac_addr_rsp;
>>>> struct ibmvnic_multicast_ctrl multicast_ctrl;
>>>> struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
>>>> - struct ibmvnic_generic_crq get_vpd_size;
>>>> + struct ibmvnic_get_vpd_size get_vpd_size;
>>>> struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
>>>> struct ibmvnic_get_vpd get_vpd;
>>>> - struct ibmvnic_generic_crq get_vpd_rsp;
>>>> + struct ibmvnic_get_vpd_rsp get_vpd_rsp;
>>>> struct ibmvnic_acl_change_indication acl_change_indication;
>>>> struct ibmvnic_acl_query acl_query;
>>>> struct ibmvnic_generic_crq acl_query_rsp;
>>>> @@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
>>>> __be32 error_id;
>>>> };
>>>>
>>>> +struct ibmvnic_vpd {
>>>> + unsigned char *buff;
>>>> + dma_addr_t dma_addr;
>>>> + u64 len;
>>>> +};
>>>> +
>>>> enum vnic_state {VNIC_PROBING = 1,
>>>> VNIC_PROBED,
>>>> VNIC_OPENING,
>>>> @@ -978,6 +997,10 @@ struct ibmvnic_adapter {
>>>> dma_addr_t ip_offload_ctrl_tok;
>>>> u32 msg_enable;
>>>>
>>>> + /* Vital Product Data (VPD) */
>>>> + struct ibmvnic_vpd *vpd;
>>>> + char fw_version[32];
>>>> +
>>>> /* Statistics */
>>>> struct ibmvnic_statistics stats;
>>>> dma_addr_t stats_token;
>>>>
>>
--
Desnes Augusto Nunes do Rosário
------------------------------------------
Linux Developer - IBM / Brazil
M.Sc. in Electrical and Computer Engineering - UFRN
(11) 9595-30-900
desnesn@br.ibm.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver
2017-11-10 19:13 ` Desnes Augusto Nunes do Rosário
@ 2017-11-13 14:58 ` Nathan Fontenot
0 siblings, 0 replies; 8+ messages in thread
From: Nathan Fontenot @ 2017-11-13 14:58 UTC (permalink / raw)
To: Desnes Augusto Nunes do Rosário, netdev
Cc: tlfalcon, linuxppc-dev, jallen
On 11/10/2017 01:13 PM, Desnes Augusto Nunes do Rosário wrote:
>
>
> On 11/10/2017 12:54 PM, Nathan Fontenot wrote:
>> On 11/10/2017 08:41 AM, Desnes Augusto Nunes do Rosário wrote:
>>>
>>>
>>> On 11/09/2017 06:31 PM, Nathan Fontenot wrote:
>>>> On 11/09/2017 01:00 PM, Desnes Augusto Nunes do Rosario wrote:
>>>>> This patch implements and enables VDP support for the ibmvnic driver.
>>>>> Moreover, it includes the implementation of suitable structs, signal
>>>>> transmission/handling and functions which allows the retrival of firmware
>>>>> information from the ibmvnic card through the ethtool command.
>>>>>
>>>>> Signed-off-by: Desnes A. Nunes do Rosario <desnesn@linux.vnet.ibm.com>
>>>>> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
>>>>> ---
>>>>> drivers/net/ethernet/ibm/ibmvnic.c | 149 ++++++++++++++++++++++++++++++++++++-
>>>>> drivers/net/ethernet/ibm/ibmvnic.h | 27 ++++++-
>>>>> 2 files changed, 173 insertions(+), 3 deletions(-)
>>>>>
>>>>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
>>>>> index d0cff28..693b502 100644
>>>>> --- a/drivers/net/ethernet/ibm/ibmvnic.c
>>>>> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
>>>>> @@ -573,6 +573,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
>>>>> return 0;
>>>>> }
>>>>>
>>>>> +static void release_vpd_data(struct ibmvnic_adapter *adapter)
>>>>> +{
>>>>> + if (!adapter->vpd)
>>>>> + return;
>>>>> +
>>>>> + kfree(adapter->vpd->buff);
>>>>> + kfree(adapter->vpd);
>>>>> +}
>>>>> +
>>>>> static void release_tx_pools(struct ibmvnic_adapter *adapter)
>>>>> {
>>>>> struct ibmvnic_tx_pool *tx_pool;
>>>>> @@ -753,6 +762,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
>>>>> {
>>>>> int i;
>>>>>
>>>>> + release_vpd_data(adapter);
>>>>> +
>>>>> release_tx_pools(adapter);
>>>>> release_rx_pools(adapter);
>>>>>
>>>>> @@ -833,6 +844,53 @@ static int set_real_num_queues(struct net_device *netdev)
>>>>> return rc;
>>>>> }
>>>>>
>>>>> +static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
>>>>> +{
>>>>> + struct device *dev = &adapter->vdev->dev;
>>>>> + union ibmvnic_crq crq;
>>>>> + dma_addr_t dma_addr;
>>>>> + int len;
>>>>> +
>>>>> + if (adapter->vpd->buff)
>>>>> + len = adapter->vpd->len;
>>>>> +
>>>>> + reinit_completion(&adapter->fw_done);
>>>>> + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
>>>>> + crq.get_vpd_size.cmd = GET_VPD_SIZE;
>>>>> + ibmvnic_send_crq(adapter, &crq);
>>>>> + wait_for_completion(&adapter->fw_done);
>>>>> +
>>>>
>>>> Shouldn't there be a check for the return code when getting the
>>>> vpd size?
>>>
>>> Hello Nathan,
>>>
>>> This check is already being performed on the handle_vpd_size_rsp() function down below.
>>>
>>> In short, a GET_VPD_SIZE signal is sent here through a ibmvnic_crq union in ibmvnic_send_crq(), whereas handle_query_ip_offload_rsp() receives from the VNIC adapter a GET_VPD_SIZE_RSP containing a ibmvnic_crq union with the vpd size information and the rc.code. If successful, a &adapter->fw_done is sent and this part of the code continues; however if not, a dev_error() is thrown. Same logic applies to GET_VPD/GET_VPD_RSP.
>>>
>>
>> Yes, I did see that code. You do a complet of the completion variable for both success and failure,
>> this then lets this routine continue irregardless of the results of the get vpd size request. The
>> call to dev_err will print the error message but does not prevent use from bailing if the
>> get vpd size fails. Perhaps setting vpd->len to -1 to indicate the get vpd call failed which could
>> then be checked by the requester.
>>
>> -Nathan
>>
>> >> What I am adding on the next version of the patch is a check if
> adapter->vpd->len is different than 0 before allocating adapter->vpd->buff, since that in a case of a failure, adapter->vpd->len will be 0.
>
> I do concur with your observation that the break is necessary.
>
> If the reception of vpd failed, adapter->vpd->len will be still zeroed out since it was created with kzalloc in init_resources().
>
> Thus, do you agree if in the next version I send the following code?
Yes, this would be good.
I think you should also add an explicit setting of len to 0 before the call too.
Looking at the code before the get cpd size call, if a vpd buffer already exists
then the len will be non-zero.
-Nathan
>
> =======
> + reinit_completion(&adapter->fw_done);
> + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
> + crq.get_vpd_size.cmd = GET_VPD_SIZE;
> + ibmvnic_send_crq(adapter, &crq);
> + wait_for_completion(&adapter->fw_done);
> +
> ->+ if(!adapter->vpd->len)
> ->+ return -ENODATA;
> +
> + if (!adapter->vpd->buff)
> + adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
> + else if (adapter->vpd->len != len)
> + adapter->vpd->buff =
> + krealloc(adapter->vpd->buff,
> + adapter->vpd->len, GFP_KERNEL);
> =======
>
>>>
>>> Best Regards,
>>>
>>>>
>>>>
>>>>> + if (!adapter->vpd->buff)
>>>>> + adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
>>>>> + else if (adapter->vpd->len != len)
>>>>> + adapter->vpd->buff =
>>>>> + krealloc(adapter->vpd->buff,
>>>>> + adapter->vpd->len, GFP_KERNEL);
>>>>> +
>>>>> + if (!adapter->vpd->buff) {
>>>>> + dev_err(dev, "Could allocate VPD buffer\n");
>>>>> + return -ENOMEM;
>>>>> + }
>>>>> +
>>>>> + adapter->vpd->dma_addr =
>>>>> + dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
>>>>> + DMA_FROM_DEVICE);
>>>>> + if (dma_mapping_error(dev, dma_addr)) {
>>>>> + dev_err(dev, "Could not map VPD buffer\n");
>>>>> + return -ENOMEM;
>>>>> + }
>>>>> +
>>>>> + reinit_completion(&adapter->fw_done);
>>>>> + crq.get_vpd.first = IBMVNIC_CRQ_CMD;
>>>>> + crq.get_vpd.cmd = GET_VPD;
>>>>> + crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
>>>>> + crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
>>>>> + ibmvnic_send_crq(adapter, &crq);
>>>>> + wait_for_completion(&adapter->fw_done);
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> static int init_resources(struct ibmvnic_adapter *adapter)
>>>>> {
>>>>> struct net_device *netdev = adapter->netdev;
>>>>> @@ -850,6 +908,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
>>>>> if (rc)
>>>>> return rc;
>>>>>
>>>>> + adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
>>>>> + if (!adapter->vpd)
>>>>> + return -ENOMEM;
>>>>> +
>>>>> adapter->map_id = 1;
>>>>> adapter->napi = kcalloc(adapter->req_rx_queues,
>>>>> sizeof(struct napi_struct), GFP_KERNEL);
>>>>> @@ -950,6 +1012,10 @@ static int ibmvnic_open(struct net_device *netdev)
>>>>>
>>>>> rc = __ibmvnic_open(netdev);
>>>>> netif_carrier_on(netdev);
>>>>> +
>>>>> + /* Vital Product Data (VPD) */
>>>>> + ibmvnic_get_vpd(adapter);
>>>>> +
>>>>> mutex_unlock(&adapter->reset_lock);
>>>>>
>>>>> return rc;
>>>>> @@ -1878,11 +1944,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
>>>>> return 0;
>>>>> }
>>>>>
>>>>> -static void ibmvnic_get_drvinfo(struct net_device *dev,
>>>>> +static void ibmvnic_get_drvinfo(struct net_device *netdev,
>>>>> struct ethtool_drvinfo *info)
>>>>> {
>>>>> + struct ibmvnic_adapter *adapter = netdev_priv(netdev);
>>>>> +
>>>>> strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
>>>>> strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
>>>>> + strlcpy(info->fw_version, adapter->fw_version,
>>>>> + sizeof(info->fw_version));
>>>>> }
>>>>>
>>>>> static u32 ibmvnic_get_msglevel(struct net_device *netdev)
>>>>> @@ -3076,6 +3146,77 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
>>>>> ibmvnic_send_crq(adapter, &crq);
>>>>> }
>>>>>
>>>>> +static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
>>>>> + struct ibmvnic_adapter *adapter)
>>>>> +{
>>>>> + struct device *dev = &adapter->vdev->dev;
>>>>> +
>>>>> + if (crq->get_vpd_size_rsp.rc.code) {
>>>>> + dev_err(dev, "Error retrieving VPD size, rc=%x\n",
>>>>> + crq->get_vpd_size_rsp.rc.code);
>>>>> + complete(&adapter->fw_done);
>>>>> + return;
>>>>> + }
>>>>> +
>>>>> + adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
>>>>> + complete(&adapter->fw_done);
>>>>> +}
>>>>> +
>>>>> +static void handle_vpd_rsp(union ibmvnic_crq *crq,
>>>>> + struct ibmvnic_adapter *adapter)
>>>>> +{
>>>>> + struct device *dev = &adapter->vdev->dev;
>>>>> + unsigned char *substr = NULL, *ptr = NULL;
>>>>> + u8 fw_level_len = 0;
>>>>> +
>>>>> + dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
>>>>> + DMA_FROM_DEVICE);
>>>>> +
>>>>> + if (crq->get_vpd_rsp.rc.code) {
>>>>> + dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
>>>>> + crq->get_vpd_rsp.rc.code);
>>>>> + memset(adapter->fw_version, 0, 32);
>>>>> + goto complete;
>>>>> + }
>>>>> +
>>>>> + /* get the position of the firmware version info
>>>>> + * located after the ASCII 'RM' substring in the buffer
>>>>> + */
>>>>> + substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
>>>>> + if (!substr) {
>>>>> + dev_info(dev, "No FW level provided by VPD\n");
>>>>> + memset(adapter->fw_version, 0, 32);
>>>>> + goto complete;
>>>>> + }
>>>>> +
>>>>> + /* get length of firmware level ASCII substring */
>>>>> + if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
>>>>> + fw_level_len = *(substr + 2);
>>>>> + } else {
>>>>> + dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
>>>>> + memset(adapter->fw_version, 0, 32);
>>>>> + goto complete;
>>>>> + }
>>>>> +
>>>>> + /* copy firmware version string from vpd into adapter */
>>>>> + if ((substr + 3 + fw_level_len) <
>>>>> + (adapter->vpd->buff + adapter->vpd->len)) {
>>>>> + ptr = strncpy((char *)adapter->fw_version,
>>>>> + substr + 3, fw_level_len);
>>>>> +
>>>>> + if (!ptr) {
>>>>> + dev_err(dev, "Failed to isolate FW level string\n");
>>>>> + memset(adapter->fw_version, 0, 32);
>>>>> + }
>>>>> + } else {
>>>>> + dev_info(dev, "FW substr extrapolated VPD buff\n");
>>>>> + memset(adapter->fw_version, 0, 32);
>>>>> + }
>>>>> +
>>>>> +complete:
>>>>> + complete(&adapter->fw_done);
>>>>> +}
>>>>> +
>>>>> static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
>>>>> {
>>>>> struct device *dev = &adapter->vdev->dev;
>>>>> @@ -3807,6 +3948,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
>>>>> netdev_dbg(netdev, "Got Collect firmware trace Response\n");
>>>>> complete(&adapter->fw_done);
>>>>> break;
>>>>> + case GET_VPD_SIZE_RSP:
>>>>> + handle_vpd_size_rsp(crq, adapter);
>>>>> + break;
>>>>> + case GET_VPD_RSP:
>>>>> + handle_vpd_rsp(crq, adapter);
>>>>> + break;
>>>>> default:
>>>>> netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
>>>>> gen_crq->cmd);
>>>>> diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
>>>>> index 4670af8..d3a6959 100644
>>>>> --- a/drivers/net/ethernet/ibm/ibmvnic.h
>>>>> +++ b/drivers/net/ethernet/ibm/ibmvnic.h
>>>>> @@ -558,6 +558,12 @@ struct ibmvnic_multicast_ctrl {
>>>>> struct ibmvnic_rc rc;
>>>>> } __packed __aligned(8);
>>>>>
>>>>> +struct ibmvnic_get_vpd_size {
>>>>> + u8 first;
>>>>> + u8 cmd;
>>>>> + u8 reserved[14];
>>>>> +} __packed __aligned(8);
>>>>> +
>>>>> struct ibmvnic_get_vpd_size_rsp {
>>>>> u8 first;
>>>>> u8 cmd;
>>>>> @@ -575,6 +581,13 @@ struct ibmvnic_get_vpd {
>>>>> u8 reserved[4];
>>>>> } __packed __aligned(8);
>>>>>
>>>>> +struct ibmvnic_get_vpd_rsp {
>>>>> + u8 first;
>>>>> + u8 cmd;
>>>>> + u8 reserved[10];
>>>>> + struct ibmvnic_rc rc;
>>>>> +} __packed __aligned(8);
>>>>> +
>>>>> struct ibmvnic_acl_change_indication {
>>>>> u8 first;
>>>>> u8 cmd;
>>>>> @@ -700,10 +713,10 @@ union ibmvnic_crq {
>>>>> struct ibmvnic_change_mac_addr change_mac_addr_rsp;
>>>>> struct ibmvnic_multicast_ctrl multicast_ctrl;
>>>>> struct ibmvnic_multicast_ctrl multicast_ctrl_rsp;
>>>>> - struct ibmvnic_generic_crq get_vpd_size;
>>>>> + struct ibmvnic_get_vpd_size get_vpd_size;
>>>>> struct ibmvnic_get_vpd_size_rsp get_vpd_size_rsp;
>>>>> struct ibmvnic_get_vpd get_vpd;
>>>>> - struct ibmvnic_generic_crq get_vpd_rsp;
>>>>> + struct ibmvnic_get_vpd_rsp get_vpd_rsp;
>>>>> struct ibmvnic_acl_change_indication acl_change_indication;
>>>>> struct ibmvnic_acl_query acl_query;
>>>>> struct ibmvnic_generic_crq acl_query_rsp;
>>>>> @@ -937,6 +950,12 @@ struct ibmvnic_error_buff {
>>>>> __be32 error_id;
>>>>> };
>>>>>
>>>>> +struct ibmvnic_vpd {
>>>>> + unsigned char *buff;
>>>>> + dma_addr_t dma_addr;
>>>>> + u64 len;
>>>>> +};
>>>>> +
>>>>> enum vnic_state {VNIC_PROBING = 1,
>>>>> VNIC_PROBED,
>>>>> VNIC_OPENING,
>>>>> @@ -978,6 +997,10 @@ struct ibmvnic_adapter {
>>>>> dma_addr_t ip_offload_ctrl_tok;
>>>>> u32 msg_enable;
>>>>>
>>>>> + /* Vital Product Data (VPD) */
>>>>> + struct ibmvnic_vpd *vpd;
>>>>> + char fw_version[32];
>>>>> +
>>>>> /* Statistics */
>>>>> struct ibmvnic_statistics stats;
>>>>> dma_addr_t stats_token;
>>>>>
>>>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2017-11-13 14:58 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-09 19:00 [PATCH] [net-next,v3] ibmvnic: Feature implementation of Vital Product Data (VPD) for the ibmvnic driver Desnes Augusto Nunes do Rosario
2017-11-09 19:00 ` [PATCH] [net-next, v3] " Desnes Augusto Nunes do Rosario
2017-11-09 19:20 ` [PATCH] [net-next,v3] " Tushar Dave
2017-11-09 20:31 ` Nathan Fontenot
2017-11-10 14:41 ` Desnes Augusto Nunes do Rosário
2017-11-10 14:54 ` Nathan Fontenot
2017-11-10 19:13 ` Desnes Augusto Nunes do Rosário
2017-11-13 14:58 ` Nathan Fontenot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.