diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h index 86a51bae19f3..d9677da38989 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h @@ -65,6 +65,9 @@ * (blocking requests), and * 2) PSI_TX_control: PSIMSGSR[MC] - for PSI to VSI notification messages * (async mode) + * + * Note that for some GET messages, there is no COOKIE field, and the CLASS + * CODE field is expanded to 8 bits. */ #ifndef __ENETC_MAILBOX_H @@ -84,6 +87,8 @@ /* The fileds of PSI-to-VSI message, the message is only 16-bit */ #define ENETC_PF_MSG_COOKIE GENMASK(3, 0) #define ENETC_PF_MSG_CLASS_CODE GENMASK(7, 4) +/* Extend the class code to 8-bit for GET messages without COOKIE */ +#define ENETC_PF_MSG_CLASS_CODE_U8 GENMASK(7, 0) #define ENETC_PF_MSG_CLASS_ID GENMASK(15, 8) enum enetc_msg_class_id { @@ -102,12 +107,17 @@ enum enetc_msg_class_id { /* Common Class ID for PSI-to-VSI and VSI-to-PSI messages */ ENETC_MSG_CLASS_ID_MAC_FILTER = 0x20, + ENETC_MSG_CLASS_ID_IP_REVISION = 0xf0, }; enum enetc_msg_mac_filter_cmd_id { ENETC_MSG_SET_PRIMARY_MAC, }; +enum enetc_msg_ip_revision_cmd_id { + ENETC_MSG_GET_IP_MN = 1, +}; + /* Class-specific error return codes of MAC filter */ enum enetc_mac_filter_class_code { ENETC_MF_CLASS_CODE_INVALID_MAC, @@ -148,4 +158,13 @@ struct enetc_msg_mac_exact_filter { struct enetc_mac_addr mac[]; }; +/* The generic message format applies to the following messages: + * Get IP revision message, class_id 0xf0. + * cmd_id 1: get IP minor revision + */ +struct enetc_msg_generic { + struct enetc_msg_header hdr; + u8 resv[16]; +}; + #endif diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c index 4ab123cbfbec..edc1277bb586 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c @@ -101,6 +101,21 @@ static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id, } } +static u16 enetc_msg_handle_ip_revision(struct enetc_pf *pf, void *vf_msg) +{ + struct enetc_msg_header *msg_hdr = vf_msg; + + switch (msg_hdr->cmd_id) { + case ENETC_MSG_GET_IP_MN: + return (FIELD_PREP(ENETC_PF_MSG_CLASS_ID, + ENETC_MSG_CLASS_ID_IP_REVISION) | + FIELD_PREP(ENETC_PF_MSG_CLASS_CODE_U8, + pf->si->revision)); + default: + return ENETC_PF_MSG_NOTSUPP; + } +} + static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, u16 *pf_msg) { @@ -158,10 +173,24 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, goto free_msg; } + /* The new messages are currently only supported on ENETC v4. If v1 + * requires them, the current restriction can be lifted. + */ + if (is_enetc_rev1(pf->si) && + !(msg_hdr->class_id == ENETC_MSG_CLASS_ID_MAC_FILTER && + msg_hdr->cmd_id == ENETC_MSG_SET_PRIMARY_MAC)) { + dev_err_ratelimited(dev, "Unsupported message for ENETC v1\n"); + + goto free_msg; + } + switch (msg_hdr->class_id) { case ENETC_MSG_CLASS_ID_MAC_FILTER: *pf_msg = enetc_msg_handle_mac_filter(pf, vf_id, msg); break; + case ENETC_MSG_CLASS_ID_IP_REVISION: + *pf_msg = enetc_msg_handle_ip_revision(pf, msg); + break; default: dev_err_ratelimited(dev, "Unsupported message class ID: 0x%x\n", diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c index 77c0eddba6e2..7d022b9c12d7 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c @@ -114,6 +114,9 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg) case ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED: err = -EPERM; break; + case ENETC_MSG_CLASS_ID_IP_REVISION: + err = FIELD_GET(ENETC_PF_MSG_CLASS_CODE_U8, pf_msg); + break; case ENETC_MSG_CLASS_ID_CMD_FAIL: case ENETC_MSG_CLASS_ID_CRC_ERROR: case ENETC_MSG_CLASS_ID_CMD_DEFERRED: @@ -122,7 +125,7 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg) } } - if (err) + if (err < 0) dev_err(dev, "Return error code from PSI: 0x%04x\n", pf_msg); return err; @@ -151,6 +154,24 @@ static int enetc_msg_vsi_set_primary_mac_addr(struct enetc_ndev_priv *priv, return enetc_msg_vsi_send(priv->si, &msg_swbd); } +static int enetc_vf_get_ip_minor_revision(struct enetc_si *si) +{ + struct device *dev = &si->pdev->dev; + struct enetc_msg_swbd msg_swbd; + + msg_swbd.size = ALIGN(sizeof(struct enetc_msg_generic), + ENETC_MSG_ALIGN); + msg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size, + &msg_swbd.dma, GFP_KERNEL); + if (!msg_swbd.vaddr) + return -ENOMEM; + + enetc_msg_fill_common_hdr(&msg_swbd, ENETC_MSG_CLASS_ID_IP_REVISION, + ENETC_MSG_GET_IP_MN, 0, 0); + + return enetc_msg_vsi_send(si, &msg_swbd); +} + static int enetc_vf_set_mac_addr(struct net_device *ndev, void *addr) { struct enetc_ndev_priv *priv = netdev_priv(ndev); @@ -202,6 +223,27 @@ static const struct net_device_ops enetc_ndev_ops = { .ndo_hwtstamp_set = enetc_hwtstamp_set, }; +static void enetc_vf_get_revision(struct enetc_si *si) +{ + int ip_mn; + + if (is_enetc_rev1(si)) { + si->revision = ENETC_REV_1_0; + return; + } + + ip_mn = enetc_vf_get_ip_minor_revision(si); + if (ip_mn >= 0) { + si->revision = (si->pdev->revision << 8) | ip_mn; + return; + } + + si->revision = ENETC_REV_4_1; + dev_info(&si->pdev->dev, + "Failed to get revision, use compatible revision: 0x%04x\n", + si->revision); +} + static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev, const struct net_device_ops *ndev_ops) { @@ -252,6 +294,7 @@ static int enetc_vf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct enetc_ndev_priv *priv; + struct enetc_msg_swbd msg; struct net_device *ndev; struct enetc_si *si; int err; @@ -261,13 +304,13 @@ static int enetc_vf_probe(struct pci_dev *pdev, return dev_err_probe(&pdev->dev, err, "PCI probing failed\n"); si = pci_get_drvdata(pdev); - si->revision = ENETC_REV_1_0; + enetc_vf_get_revision(si); si->ops = &enetc_vsi_ops; err = enetc_get_driver_data(si); if (err) { dev_err_probe(&pdev->dev, err, "Could not get VF driver data\n"); - goto err_alloc_netdev; + goto err_get_driver_data; } enetc_get_si_caps(si); @@ -327,7 +370,10 @@ static int enetc_vf_probe(struct pci_dev *pdev, si->ndev = NULL; free_netdev(ndev); err_alloc_netdev: +err_get_driver_data: + msg = si->msg; enetc_pci_remove(pdev); + enetc_msg_dma_free(&pdev->dev, &msg); return err; }