|
@@ -574,6 +574,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
|
|
return 0;
|
|
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)
|
|
static void release_tx_pools(struct ibmvnic_adapter *adapter)
|
|
{
|
|
{
|
|
struct ibmvnic_tx_pool *tx_pool;
|
|
struct ibmvnic_tx_pool *tx_pool;
|
|
@@ -754,6 +763,8 @@ static void release_resources(struct ibmvnic_adapter *adapter)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
|
|
|
|
|
|
+ release_vpd_data(adapter);
|
|
|
|
+
|
|
release_tx_pools(adapter);
|
|
release_tx_pools(adapter);
|
|
release_rx_pools(adapter);
|
|
release_rx_pools(adapter);
|
|
|
|
|
|
@@ -834,6 +845,57 @@ static int set_real_num_queues(struct net_device *netdev)
|
|
return rc;
|
|
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 = 0;
|
|
|
|
+
|
|
|
|
+ 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->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);
|
|
|
|
+
|
|
|
|
+ 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");
|
|
|
|
+ kfree(adapter->vpd->buff);
|
|
|
|
+ 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)
|
|
static int init_resources(struct ibmvnic_adapter *adapter)
|
|
{
|
|
{
|
|
struct net_device *netdev = adapter->netdev;
|
|
struct net_device *netdev = adapter->netdev;
|
|
@@ -851,6 +913,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
|
|
if (rc)
|
|
if (rc)
|
|
return rc;
|
|
return rc;
|
|
|
|
|
|
|
|
+ adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
|
|
|
|
+ if (!adapter->vpd)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
adapter->map_id = 1;
|
|
adapter->map_id = 1;
|
|
adapter->napi = kcalloc(adapter->req_rx_queues,
|
|
adapter->napi = kcalloc(adapter->req_rx_queues,
|
|
sizeof(struct napi_struct), GFP_KERNEL);
|
|
sizeof(struct napi_struct), GFP_KERNEL);
|
|
@@ -924,7 +990,7 @@ static int __ibmvnic_open(struct net_device *netdev)
|
|
static int ibmvnic_open(struct net_device *netdev)
|
|
static int ibmvnic_open(struct net_device *netdev)
|
|
{
|
|
{
|
|
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
|
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
|
- int rc;
|
|
|
|
|
|
+ int rc, vpd;
|
|
|
|
|
|
mutex_lock(&adapter->reset_lock);
|
|
mutex_lock(&adapter->reset_lock);
|
|
|
|
|
|
@@ -951,6 +1017,12 @@ static int ibmvnic_open(struct net_device *netdev)
|
|
|
|
|
|
rc = __ibmvnic_open(netdev);
|
|
rc = __ibmvnic_open(netdev);
|
|
netif_carrier_on(netdev);
|
|
netif_carrier_on(netdev);
|
|
|
|
+
|
|
|
|
+ /* Vital Product Data (VPD) */
|
|
|
|
+ vpd = ibmvnic_get_vpd(adapter);
|
|
|
|
+ if (vpd)
|
|
|
|
+ netdev_err(netdev, "failed to initialize Vital Product Data (VPD)\n");
|
|
|
|
+
|
|
mutex_unlock(&adapter->reset_lock);
|
|
mutex_unlock(&adapter->reset_lock);
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -1879,11 +1951,15 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev,
|
|
return 0;
|
|
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 ethtool_drvinfo *info)
|
|
{
|
|
{
|
|
|
|
+ struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
|
|
|
+
|
|
strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
|
|
strlcpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
|
|
strlcpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
|
|
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)
|
|
static u32 ibmvnic_get_msglevel(struct net_device *netdev)
|
|
@@ -3140,6 +3216,73 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
|
|
ibmvnic_send_crq(adapter, &crq);
|
|
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;
|
|
|
|
+
|
|
|
|
+ memset(adapter->fw_version, 0, 32);
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+ 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");
|
|
|
|
+ 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");
|
|
|
|
+ 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");
|
|
|
|
+ } else {
|
|
|
|
+ dev_info(dev, "FW substr extrapolated VPD buff\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+complete:
|
|
|
|
+ complete(&adapter->fw_done);
|
|
|
|
+}
|
|
|
|
+
|
|
static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
|
|
static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
|
|
{
|
|
{
|
|
struct device *dev = &adapter->vdev->dev;
|
|
struct device *dev = &adapter->vdev->dev;
|
|
@@ -3871,6 +4014,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
|
|
netdev_dbg(netdev, "Got Collect firmware trace Response\n");
|
|
netdev_dbg(netdev, "Got Collect firmware trace Response\n");
|
|
complete(&adapter->fw_done);
|
|
complete(&adapter->fw_done);
|
|
break;
|
|
break;
|
|
|
|
+ case GET_VPD_SIZE_RSP:
|
|
|
|
+ handle_vpd_size_rsp(crq, adapter);
|
|
|
|
+ break;
|
|
|
|
+ case GET_VPD_RSP:
|
|
|
|
+ handle_vpd_rsp(crq, adapter);
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
|
|
netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
|
|
gen_crq->cmd);
|
|
gen_crq->cmd);
|