diff options
| author | Yuval Mintz <Yuval.Mintz@qlogic.com> | 2016-08-22 06:25:11 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-08-22 21:24:52 -0400 |
| commit | d8c2c7e3404e5bcaeae4af78d6935e5b8fcc97ee (patch) | |
| tree | e9beb5dc5d4bf584102e0e96830590ee5e0535cd | |
| parent | 11a85d759ea5064c986c47112607681c09cdcdd9 (diff) | |
qed*: Add support for VFs over legacy PFs
Modern VFs can't run on old non-compatible as the fastpath HSI is
slightly changed - but as the HSI is actually very close [basically,
a single bit whose meaning flipped] this can be supported with small
modifications.
The major differences would be in:
- Recognizing that VF is running on top of a legacy PF.
- Returning some slowpath configurations that are no longer needed
on top of modern PFs, but would be required when working over
the legacy ones.
Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_l2.c | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_vf.c | 107 | ||||
| -rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_vf.h | 5 | ||||
| -rw-r--r-- | drivers/net/ethernet/qlogic/qede/qede.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/qlogic/qede/qede_main.c | 10 | ||||
| -rw-r--r-- | include/linux/qed/qed_eth_if.h | 3 |
6 files changed, 109 insertions, 20 deletions
diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index bf433016551a..4409ea3f7d40 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c | |||
| @@ -1685,6 +1685,8 @@ static int qed_fill_eth_dev_info(struct qed_dev *cdev, | |||
| 1685 | qed_vf_get_num_vlan_filters(&cdev->hwfns[0], | 1685 | qed_vf_get_num_vlan_filters(&cdev->hwfns[0], |
| 1686 | &info->num_vlan_filters); | 1686 | &info->num_vlan_filters); |
| 1687 | qed_vf_get_port_mac(&cdev->hwfns[0], info->port_mac); | 1687 | qed_vf_get_port_mac(&cdev->hwfns[0], info->port_mac); |
| 1688 | |||
| 1689 | info->is_legacy = !!cdev->hwfns[0].vf_iov_info->b_pre_fp_hsi; | ||
| 1688 | } | 1690 | } |
| 1689 | 1691 | ||
| 1690 | qed_fill_dev_info(cdev, &info->common); | 1692 | qed_fill_dev_info(cdev, &info->common); |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 9b780b31b15c..f9f68da8b277 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c | |||
| @@ -191,6 +191,9 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) | |||
| 191 | DP_VERBOSE(p_hwfn, | 191 | DP_VERBOSE(p_hwfn, |
| 192 | QED_MSG_IOV, "attempting to acquire resources\n"); | 192 | QED_MSG_IOV, "attempting to acquire resources\n"); |
| 193 | 193 | ||
| 194 | /* Clear response buffer, as this might be a re-send */ | ||
| 195 | memset(p_iov->pf2vf_reply, 0, sizeof(union pfvf_tlvs)); | ||
| 196 | |||
| 194 | /* send acquire request */ | 197 | /* send acquire request */ |
| 195 | rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp)); | 198 | rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp)); |
| 196 | if (rc) | 199 | if (rc) |
| @@ -205,9 +208,12 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) | |||
| 205 | /* PF agrees to allocate our resources */ | 208 | /* PF agrees to allocate our resources */ |
| 206 | if (!(resp->pfdev_info.capabilities & | 209 | if (!(resp->pfdev_info.capabilities & |
| 207 | PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE)) { | 210 | PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE)) { |
| 208 | DP_INFO(p_hwfn, | 211 | /* It's possible legacy PF mistakenly accepted; |
| 209 | "PF is using old incompatible driver; Either downgrade driver or request provider to update hypervisor version\n"); | 212 | * but we don't care - simply mark it as |
| 210 | return -EINVAL; | 213 | * legacy and continue. |
| 214 | */ | ||
| 215 | req->vfdev_info.capabilities |= | ||
| 216 | VFPF_ACQUIRE_CAP_PRE_FP_HSI; | ||
| 211 | } | 217 | } |
| 212 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, "resources acquired\n"); | 218 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, "resources acquired\n"); |
| 213 | resources_acquired = true; | 219 | resources_acquired = true; |
| @@ -215,27 +221,55 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) | |||
| 215 | attempts < VF_ACQUIRE_THRESH) { | 221 | attempts < VF_ACQUIRE_THRESH) { |
| 216 | qed_vf_pf_acquire_reduce_resc(p_hwfn, p_resc, | 222 | qed_vf_pf_acquire_reduce_resc(p_hwfn, p_resc, |
| 217 | &resp->resc); | 223 | &resp->resc); |
| 224 | } else if (resp->hdr.status == PFVF_STATUS_NOT_SUPPORTED) { | ||
| 225 | if (pfdev_info->major_fp_hsi && | ||
| 226 | (pfdev_info->major_fp_hsi != ETH_HSI_VER_MAJOR)) { | ||
| 227 | DP_NOTICE(p_hwfn, | ||
| 228 | "PF uses an incompatible fastpath HSI %02x.%02x [VF requires %02x.%02x]. Please change to a VF driver using %02x.xx.\n", | ||
| 229 | pfdev_info->major_fp_hsi, | ||
| 230 | pfdev_info->minor_fp_hsi, | ||
| 231 | ETH_HSI_VER_MAJOR, | ||
| 232 | ETH_HSI_VER_MINOR, | ||
| 233 | pfdev_info->major_fp_hsi); | ||
| 234 | rc = -EINVAL; | ||
| 235 | goto exit; | ||
| 236 | } | ||
| 218 | 237 | ||
| 219 | /* Clear response buffer */ | 238 | if (!pfdev_info->major_fp_hsi) { |
| 220 | memset(p_iov->pf2vf_reply, 0, sizeof(union pfvf_tlvs)); | 239 | if (req->vfdev_info.capabilities & |
| 221 | } else if ((resp->hdr.status == PFVF_STATUS_NOT_SUPPORTED) && | 240 | VFPF_ACQUIRE_CAP_PRE_FP_HSI) { |
| 222 | pfdev_info->major_fp_hsi && | 241 | DP_NOTICE(p_hwfn, |
| 223 | (pfdev_info->major_fp_hsi != ETH_HSI_VER_MAJOR)) { | 242 | "PF uses very old drivers. Please change to a VF driver using no later than 8.8.x.x.\n"); |
| 224 | DP_NOTICE(p_hwfn, | 243 | rc = -EINVAL; |
| 225 | "PF uses an incompatible fastpath HSI %02x.%02x [VF requires %02x.%02x]. Please change to a VF driver using %02x.xx.\n", | 244 | goto exit; |
| 226 | pfdev_info->major_fp_hsi, | 245 | } else { |
| 227 | pfdev_info->minor_fp_hsi, | 246 | DP_INFO(p_hwfn, |
| 228 | ETH_HSI_VER_MAJOR, | 247 | "PF is old - try re-acquire to see if it supports FW-version override\n"); |
| 229 | ETH_HSI_VER_MINOR, pfdev_info->major_fp_hsi); | 248 | req->vfdev_info.capabilities |= |
| 230 | return -EINVAL; | 249 | VFPF_ACQUIRE_CAP_PRE_FP_HSI; |
| 250 | continue; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | /* If PF/VF are using same Major, PF must have had | ||
| 255 | * it's reasons. Simply fail. | ||
| 256 | */ | ||
| 257 | DP_NOTICE(p_hwfn, "PF rejected acquisition by VF\n"); | ||
| 258 | rc = -EINVAL; | ||
| 259 | goto exit; | ||
| 231 | } else { | 260 | } else { |
| 232 | DP_ERR(p_hwfn, | 261 | DP_ERR(p_hwfn, |
| 233 | "PF returned error %d to VF acquisition request\n", | 262 | "PF returned error %d to VF acquisition request\n", |
| 234 | resp->hdr.status); | 263 | resp->hdr.status); |
| 235 | return -EAGAIN; | 264 | rc = -EAGAIN; |
| 265 | goto exit; | ||
| 236 | } | 266 | } |
| 237 | } | 267 | } |
| 238 | 268 | ||
| 269 | /* Mark the PF as legacy, if needed */ | ||
| 270 | if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_PRE_FP_HSI) | ||
| 271 | p_iov->b_pre_fp_hsi = true; | ||
| 272 | |||
| 239 | /* Update bulletin board size with response from PF */ | 273 | /* Update bulletin board size with response from PF */ |
| 240 | p_iov->bulletin.size = resp->bulletin_size; | 274 | p_iov->bulletin.size = resp->bulletin_size; |
| 241 | 275 | ||
| @@ -253,14 +287,16 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) | |||
| 253 | } | 287 | } |
| 254 | } | 288 | } |
| 255 | 289 | ||
| 256 | if (ETH_HSI_VER_MINOR && | 290 | if (!p_iov->b_pre_fp_hsi && |
| 291 | ETH_HSI_VER_MINOR && | ||
| 257 | (resp->pfdev_info.minor_fp_hsi < ETH_HSI_VER_MINOR)) { | 292 | (resp->pfdev_info.minor_fp_hsi < ETH_HSI_VER_MINOR)) { |
| 258 | DP_INFO(p_hwfn, | 293 | DP_INFO(p_hwfn, |
| 259 | "PF is using older fastpath HSI; %02x.%02x is configured\n", | 294 | "PF is using older fastpath HSI; %02x.%02x is configured\n", |
| 260 | ETH_HSI_VER_MAJOR, resp->pfdev_info.minor_fp_hsi); | 295 | ETH_HSI_VER_MAJOR, resp->pfdev_info.minor_fp_hsi); |
| 261 | } | 296 | } |
| 262 | 297 | ||
| 263 | return 0; | 298 | exit: |
| 299 | return rc; | ||
| 264 | } | 300 | } |
| 265 | 301 | ||
| 266 | int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) | 302 | int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) |
| @@ -347,6 +383,9 @@ free_p_iov: | |||
| 347 | 383 | ||
| 348 | return -ENOMEM; | 384 | return -ENOMEM; |
| 349 | } | 385 | } |
| 386 | #define TSTORM_QZONE_START PXP_VF_BAR0_START_SDM_ZONE_A | ||
| 387 | #define MSTORM_QZONE_START(dev) (TSTORM_QZONE_START + \ | ||
| 388 | (TSTORM_QZONE_SIZE * NUM_OF_L2_QUEUES(dev))) | ||
| 350 | 389 | ||
| 351 | int qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, | 390 | int qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, |
| 352 | u8 rx_qid, | 391 | u8 rx_qid, |
| @@ -374,6 +413,21 @@ int qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, | |||
| 374 | req->bd_max_bytes = bd_max_bytes; | 413 | req->bd_max_bytes = bd_max_bytes; |
| 375 | req->stat_id = -1; | 414 | req->stat_id = -1; |
| 376 | 415 | ||
| 416 | /* If PF is legacy, we'll need to calculate producers ourselves | ||
| 417 | * as well as clean them. | ||
| 418 | */ | ||
| 419 | if (pp_prod && p_iov->b_pre_fp_hsi) { | ||
| 420 | u8 hw_qid = p_iov->acquire_resp.resc.hw_qid[rx_qid]; | ||
| 421 | u32 init_prod_val = 0; | ||
| 422 | |||
| 423 | *pp_prod = (u8 __iomem *)p_hwfn->regview + | ||
| 424 | MSTORM_QZONE_START(p_hwfn->cdev) + | ||
| 425 | hw_qid * MSTORM_QZONE_SIZE; | ||
| 426 | |||
| 427 | /* Init the rcq, rx bd and rx sge (if valid) producers to 0 */ | ||
| 428 | __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u32), | ||
| 429 | (u32 *)(&init_prod_val)); | ||
| 430 | } | ||
| 377 | /* add list termination tlv */ | 431 | /* add list termination tlv */ |
| 378 | qed_add_tlv(p_hwfn, &p_iov->offset, | 432 | qed_add_tlv(p_hwfn, &p_iov->offset, |
| 379 | CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); | 433 | CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); |
| @@ -387,7 +441,7 @@ int qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, | |||
| 387 | return -EINVAL; | 441 | return -EINVAL; |
| 388 | 442 | ||
| 389 | /* Learn the address of the producer from the response */ | 443 | /* Learn the address of the producer from the response */ |
| 390 | if (pp_prod) { | 444 | if (pp_prod && !p_iov->b_pre_fp_hsi) { |
| 391 | u32 init_prod_val = 0; | 445 | u32 init_prod_val = 0; |
| 392 | 446 | ||
| 393 | *pp_prod = (u8 __iomem *)p_hwfn->regview + resp->offset; | 447 | *pp_prod = (u8 __iomem *)p_hwfn->regview + resp->offset; |
| @@ -470,7 +524,20 @@ int qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn, | |||
| 470 | } | 524 | } |
| 471 | 525 | ||
| 472 | if (pp_doorbell) { | 526 | if (pp_doorbell) { |
| 473 | *pp_doorbell = (u8 __iomem *)p_hwfn->doorbells + resp->offset; | 527 | /* Modern PFs provide the actual offsets, while legacy |
| 528 | * provided only the queue id. | ||
| 529 | */ | ||
| 530 | if (!p_iov->b_pre_fp_hsi) { | ||
| 531 | *pp_doorbell = (u8 __iomem *)p_hwfn->doorbells + | ||
| 532 | resp->offset; | ||
| 533 | } else { | ||
| 534 | u8 cid = p_iov->acquire_resp.resc.cid[tx_queue_id]; | ||
| 535 | u32 db_addr; | ||
| 536 | |||
| 537 | db_addr = qed_db_addr(cid, DQ_DEMS_LEGACY); | ||
| 538 | *pp_doorbell = (u8 __iomem *)p_hwfn->doorbells + | ||
| 539 | db_addr; | ||
| 540 | } | ||
| 474 | 541 | ||
| 475 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, | 542 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
| 476 | "Txq[0x%02x]: doorbell at %p [offset 0x%08x]\n", | 543 | "Txq[0x%02x]: doorbell at %p [offset 0x%08x]\n", |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index 60a599b579bd..35db7a28aa13 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h | |||
| @@ -551,6 +551,11 @@ struct qed_vf_iov { | |||
| 551 | 551 | ||
| 552 | /* we set aside a copy of the acquire response */ | 552 | /* we set aside a copy of the acquire response */ |
| 553 | struct pfvf_acquire_resp_tlv acquire_resp; | 553 | struct pfvf_acquire_resp_tlv acquire_resp; |
| 554 | |||
| 555 | /* In case PF originates prior to the fp-hsi version comparison, | ||
| 556 | * this has to be propagated as it affects the fastpath. | ||
| 557 | */ | ||
| 558 | bool b_pre_fp_hsi; | ||
| 554 | }; | 559 | }; |
| 555 | 560 | ||
| 556 | #ifdef CONFIG_QED_SRIOV | 561 | #ifdef CONFIG_QED_SRIOV |
diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 32325ca5951f..700b509f7143 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h | |||
| @@ -268,6 +268,8 @@ struct qede_tx_queue { | |||
| 268 | u16 num_tx_buffers; | 268 | u16 num_tx_buffers; |
| 269 | u64 xmit_pkts; | 269 | u64 xmit_pkts; |
| 270 | u64 stopped_cnt; | 270 | u64 stopped_cnt; |
| 271 | |||
| 272 | bool is_legacy; | ||
| 271 | }; | 273 | }; |
| 272 | 274 | ||
| 273 | #define BD_UNMAP_ADDR(bd) HILO_U64(le32_to_cpu((bd)->addr.hi), \ | 275 | #define BD_UNMAP_ADDR(bd) HILO_U64(le32_to_cpu((bd)->addr.hi), \ |
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index a05459f96962..ac126e6067ae 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c | |||
| @@ -598,6 +598,14 @@ static netdev_tx_t qede_start_xmit(struct sk_buff *skb, | |||
| 598 | 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; | 598 | 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; |
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | /* Legacy FW had flipped behavior in regard to this bit - | ||
| 602 | * I.e., needed to set to prevent FW from touching encapsulated | ||
| 603 | * packets when it didn't need to. | ||
| 604 | */ | ||
| 605 | if (unlikely(txq->is_legacy)) | ||
| 606 | first_bd->data.bitfields ^= | ||
| 607 | 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; | ||
| 608 | |||
| 601 | /* If the packet is IPv6 with extension header, indicate that | 609 | /* If the packet is IPv6 with extension header, indicate that |
| 602 | * to FW and pass few params, since the device cracker doesn't | 610 | * to FW and pass few params, since the device cracker doesn't |
| 603 | * support parsing IPv6 with extension header/s. | 611 | * support parsing IPv6 with extension header/s. |
| @@ -2991,6 +2999,8 @@ static void qede_init_fp(struct qede_dev *edev) | |||
| 2991 | for (tc = 0; tc < edev->num_tc; tc++) { | 2999 | for (tc = 0; tc < edev->num_tc; tc++) { |
| 2992 | txq_index = tc * QEDE_RSS_CNT(edev) + rss_id; | 3000 | txq_index = tc * QEDE_RSS_CNT(edev) + rss_id; |
| 2993 | fp->txqs[tc].index = txq_index; | 3001 | fp->txqs[tc].index = txq_index; |
| 3002 | if (edev->dev_info.is_legacy) | ||
| 3003 | fp->txqs[tc].is_legacy = true; | ||
| 2994 | } | 3004 | } |
| 2995 | 3005 | ||
| 2996 | snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", | 3006 | snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", |
diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h index 4475a9d8ae15..33c24ebc9b7f 100644 --- a/include/linux/qed/qed_eth_if.h +++ b/include/linux/qed/qed_eth_if.h | |||
| @@ -23,6 +23,9 @@ struct qed_dev_eth_info { | |||
| 23 | 23 | ||
| 24 | u8 port_mac[ETH_ALEN]; | 24 | u8 port_mac[ETH_ALEN]; |
| 25 | u8 num_vlan_filters; | 25 | u8 num_vlan_filters; |
| 26 | |||
| 27 | /* Legacy VF - this affects the datapath, so qede has to know */ | ||
| 28 | bool is_legacy; | ||
| 26 | }; | 29 | }; |
| 27 | 30 | ||
| 28 | struct qed_update_vport_rss_params { | 31 | struct qed_update_vport_rss_params { |
