diff options
Diffstat (limited to 'net/ncsi')
-rw-r--r-- | net/ncsi/Kconfig | 6 | ||||
-rw-r--r-- | net/ncsi/internal.h | 9 | ||||
-rw-r--r-- | net/ncsi/ncsi-manage.c | 82 | ||||
-rw-r--r-- | net/ncsi/ncsi-pkt.h | 8 | ||||
-rw-r--r-- | net/ncsi/ncsi-rsp.c | 44 |
5 files changed, 147 insertions, 2 deletions
diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig index 08a8a6031fd7..7f2b46108a24 100644 --- a/net/ncsi/Kconfig +++ b/net/ncsi/Kconfig | |||
@@ -10,3 +10,9 @@ config NET_NCSI | |||
10 | support. Enable this only if your system connects to a network | 10 | support. Enable this only if your system connects to a network |
11 | device via NCSI and the ethernet driver you're using supports | 11 | device via NCSI and the ethernet driver you're using supports |
12 | the protocol explicitly. | 12 | the protocol explicitly. |
13 | config NCSI_OEM_CMD_GET_MAC | ||
14 | bool "Get NCSI OEM MAC Address" | ||
15 | depends on NET_NCSI | ||
16 | ---help--- | ||
17 | This allows to get MAC address from NCSI firmware and set them back to | ||
18 | controller. | ||
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index 13c9b5eeb3b7..1dae77c54009 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h | |||
@@ -71,6 +71,13 @@ enum { | |||
71 | /* OEM Vendor Manufacture ID */ | 71 | /* OEM Vendor Manufacture ID */ |
72 | #define NCSI_OEM_MFR_MLX_ID 0x8119 | 72 | #define NCSI_OEM_MFR_MLX_ID 0x8119 |
73 | #define NCSI_OEM_MFR_BCM_ID 0x113d | 73 | #define NCSI_OEM_MFR_BCM_ID 0x113d |
74 | /* Broadcom specific OEM Command */ | ||
75 | #define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */ | ||
76 | /* OEM Command payload lengths*/ | ||
77 | #define NCSI_OEM_BCM_CMD_GMA_LEN 12 | ||
78 | /* Mac address offset in OEM response */ | ||
79 | #define BCM_MAC_ADDR_OFFSET 28 | ||
80 | |||
74 | 81 | ||
75 | struct ncsi_channel_version { | 82 | struct ncsi_channel_version { |
76 | u32 version; /* Supported BCD encoded NCSI version */ | 83 | u32 version; /* Supported BCD encoded NCSI version */ |
@@ -246,6 +253,7 @@ enum { | |||
246 | ncsi_dev_state_probe_dp, | 253 | ncsi_dev_state_probe_dp, |
247 | ncsi_dev_state_config_sp = 0x0301, | 254 | ncsi_dev_state_config_sp = 0x0301, |
248 | ncsi_dev_state_config_cis, | 255 | ncsi_dev_state_config_cis, |
256 | ncsi_dev_state_config_oem_gma, | ||
249 | ncsi_dev_state_config_clear_vids, | 257 | ncsi_dev_state_config_clear_vids, |
250 | ncsi_dev_state_config_svf, | 258 | ncsi_dev_state_config_svf, |
251 | ncsi_dev_state_config_ev, | 259 | ncsi_dev_state_config_ev, |
@@ -279,6 +287,7 @@ struct ncsi_dev_priv { | |||
279 | #define NCSI_DEV_PROBED 1 /* Finalized NCSI topology */ | 287 | #define NCSI_DEV_PROBED 1 /* Finalized NCSI topology */ |
280 | #define NCSI_DEV_HWA 2 /* Enabled HW arbitration */ | 288 | #define NCSI_DEV_HWA 2 /* Enabled HW arbitration */ |
281 | #define NCSI_DEV_RESHUFFLE 4 | 289 | #define NCSI_DEV_RESHUFFLE 4 |
290 | unsigned int gma_flag; /* OEM GMA flag */ | ||
282 | spinlock_t lock; /* Protect the NCSI device */ | 291 | spinlock_t lock; /* Protect the NCSI device */ |
283 | #if IS_ENABLED(CONFIG_IPV6) | 292 | #if IS_ENABLED(CONFIG_IPV6) |
284 | unsigned int inet6_addr_num; /* Number of IPv6 addresses */ | 293 | unsigned int inet6_addr_num; /* Number of IPv6 addresses */ |
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index 6aa0614d2d28..bfc43b28c7a6 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c | |||
@@ -651,6 +651,72 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, | |||
651 | return 0; | 651 | return 0; |
652 | } | 652 | } |
653 | 653 | ||
654 | #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) | ||
655 | |||
656 | /* NCSI OEM Command APIs */ | ||
657 | static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca) | ||
658 | { | ||
659 | unsigned char data[NCSI_OEM_BCM_CMD_GMA_LEN]; | ||
660 | int ret = 0; | ||
661 | |||
662 | nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN; | ||
663 | |||
664 | memset(data, 0, NCSI_OEM_BCM_CMD_GMA_LEN); | ||
665 | *(unsigned int *)data = ntohl(NCSI_OEM_MFR_BCM_ID); | ||
666 | data[5] = NCSI_OEM_BCM_CMD_GMA; | ||
667 | |||
668 | nca->data = data; | ||
669 | |||
670 | ret = ncsi_xmit_cmd(nca); | ||
671 | if (ret) | ||
672 | netdev_err(nca->ndp->ndev.dev, | ||
673 | "NCSI: Failed to transmit cmd 0x%x during configure\n", | ||
674 | nca->type); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | /* OEM Command handlers initialization */ | ||
679 | static struct ncsi_oem_gma_handler { | ||
680 | unsigned int mfr_id; | ||
681 | int (*handler)(struct ncsi_cmd_arg *nca); | ||
682 | } ncsi_oem_gma_handlers[] = { | ||
683 | { NCSI_OEM_MFR_BCM_ID, ncsi_oem_gma_handler_bcm } | ||
684 | }; | ||
685 | |||
686 | static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id) | ||
687 | { | ||
688 | struct ncsi_oem_gma_handler *nch = NULL; | ||
689 | int i; | ||
690 | |||
691 | /* This function should only be called once, return if flag set */ | ||
692 | if (nca->ndp->gma_flag == 1) | ||
693 | return -1; | ||
694 | |||
695 | /* Find gma handler for given manufacturer id */ | ||
696 | for (i = 0; i < ARRAY_SIZE(ncsi_oem_gma_handlers); i++) { | ||
697 | if (ncsi_oem_gma_handlers[i].mfr_id == mf_id) { | ||
698 | if (ncsi_oem_gma_handlers[i].handler) | ||
699 | nch = &ncsi_oem_gma_handlers[i]; | ||
700 | break; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | if (!nch) { | ||
705 | netdev_err(nca->ndp->ndev.dev, | ||
706 | "NCSI: No GMA handler available for MFR-ID (0x%x)\n", | ||
707 | mf_id); | ||
708 | return -1; | ||
709 | } | ||
710 | |||
711 | /* Set the flag for GMA command which should only be called once */ | ||
712 | nca->ndp->gma_flag = 1; | ||
713 | |||
714 | /* Get Mac address from NCSI device */ | ||
715 | return nch->handler(nca); | ||
716 | } | ||
717 | |||
718 | #endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ | ||
719 | |||
654 | static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) | 720 | static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) |
655 | { | 721 | { |
656 | struct ncsi_dev *nd = &ndp->ndev; | 722 | struct ncsi_dev *nd = &ndp->ndev; |
@@ -701,7 +767,23 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) | |||
701 | goto error; | 767 | goto error; |
702 | } | 768 | } |
703 | 769 | ||
770 | nd->state = ncsi_dev_state_config_oem_gma; | ||
771 | break; | ||
772 | case ncsi_dev_state_config_oem_gma: | ||
704 | nd->state = ncsi_dev_state_config_clear_vids; | 773 | nd->state = ncsi_dev_state_config_clear_vids; |
774 | ret = -1; | ||
775 | |||
776 | #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) | ||
777 | nca.type = NCSI_PKT_CMD_OEM; | ||
778 | nca.package = np->id; | ||
779 | nca.channel = nc->id; | ||
780 | ndp->pending_req_num = 1; | ||
781 | ret = ncsi_gma_handler(&nca, nc->version.mf_id); | ||
782 | #endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ | ||
783 | |||
784 | if (ret < 0) | ||
785 | schedule_work(&ndp->work); | ||
786 | |||
705 | break; | 787 | break; |
706 | case ncsi_dev_state_config_clear_vids: | 788 | case ncsi_dev_state_config_clear_vids: |
707 | case ncsi_dev_state_config_svf: | 789 | case ncsi_dev_state_config_svf: |
diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h index 0f2087c8d42a..4d3f06be38bd 100644 --- a/net/ncsi/ncsi-pkt.h +++ b/net/ncsi/ncsi-pkt.h | |||
@@ -165,6 +165,14 @@ struct ncsi_rsp_oem_pkt { | |||
165 | unsigned char data[]; /* Payload data */ | 165 | unsigned char data[]; /* Payload data */ |
166 | }; | 166 | }; |
167 | 167 | ||
168 | /* Broadcom Response Data */ | ||
169 | struct ncsi_rsp_oem_bcm_pkt { | ||
170 | unsigned char ver; /* Payload Version */ | ||
171 | unsigned char type; /* OEM Command type */ | ||
172 | __be16 len; /* Payload Length */ | ||
173 | unsigned char data[]; /* Cmd specific Data */ | ||
174 | }; | ||
175 | |||
168 | /* Get Link Status */ | 176 | /* Get Link Status */ |
169 | struct ncsi_rsp_gls_pkt { | 177 | struct ncsi_rsp_gls_pkt { |
170 | struct ncsi_rsp_pkt_hdr rsp; /* Response header */ | 178 | struct ncsi_rsp_pkt_hdr rsp; /* Response header */ |
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index 85fa59afae34..77e07ba3f493 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c | |||
@@ -611,19 +611,59 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr) | |||
611 | return 0; | 611 | return 0; |
612 | } | 612 | } |
613 | 613 | ||
614 | /* Response handler for Broadcom command Get Mac Address */ | ||
615 | static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr) | ||
616 | { | ||
617 | struct ncsi_dev_priv *ndp = nr->ndp; | ||
618 | struct net_device *ndev = ndp->ndev.dev; | ||
619 | const struct net_device_ops *ops = ndev->netdev_ops; | ||
620 | struct ncsi_rsp_oem_pkt *rsp; | ||
621 | struct sockaddr saddr; | ||
622 | int ret = 0; | ||
623 | |||
624 | /* Get the response header */ | ||
625 | rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); | ||
626 | |||
627 | saddr.sa_family = ndev->type; | ||
628 | ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; | ||
629 | memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN); | ||
630 | /* Increase mac address by 1 for BMC's address */ | ||
631 | saddr.sa_data[ETH_ALEN - 1]++; | ||
632 | ret = ops->ndo_set_mac_address(ndev, &saddr); | ||
633 | if (ret < 0) | ||
634 | netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n"); | ||
635 | |||
636 | return ret; | ||
637 | } | ||
638 | |||
639 | /* Response handler for Broadcom card */ | ||
640 | static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr) | ||
641 | { | ||
642 | struct ncsi_rsp_oem_bcm_pkt *bcm; | ||
643 | struct ncsi_rsp_oem_pkt *rsp; | ||
644 | |||
645 | /* Get the response header */ | ||
646 | rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); | ||
647 | bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data); | ||
648 | |||
649 | if (bcm->type == NCSI_OEM_BCM_CMD_GMA) | ||
650 | return ncsi_rsp_handler_oem_bcm_gma(nr); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
614 | static struct ncsi_rsp_oem_handler { | 654 | static struct ncsi_rsp_oem_handler { |
615 | unsigned int mfr_id; | 655 | unsigned int mfr_id; |
616 | int (*handler)(struct ncsi_request *nr); | 656 | int (*handler)(struct ncsi_request *nr); |
617 | } ncsi_rsp_oem_handlers[] = { | 657 | } ncsi_rsp_oem_handlers[] = { |
618 | { NCSI_OEM_MFR_MLX_ID, NULL }, | 658 | { NCSI_OEM_MFR_MLX_ID, NULL }, |
619 | { NCSI_OEM_MFR_BCM_ID, NULL } | 659 | { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm } |
620 | }; | 660 | }; |
621 | 661 | ||
622 | /* Response handler for OEM command */ | 662 | /* Response handler for OEM command */ |
623 | static int ncsi_rsp_handler_oem(struct ncsi_request *nr) | 663 | static int ncsi_rsp_handler_oem(struct ncsi_request *nr) |
624 | { | 664 | { |
625 | struct ncsi_rsp_oem_pkt *rsp; | ||
626 | struct ncsi_rsp_oem_handler *nrh = NULL; | 665 | struct ncsi_rsp_oem_handler *nrh = NULL; |
666 | struct ncsi_rsp_oem_pkt *rsp; | ||
627 | unsigned int mfr_id, i; | 667 | unsigned int mfr_id, i; |
628 | 668 | ||
629 | /* Get the response header */ | 669 | /* Get the response header */ |