diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 3d7e0e44358d57689f8bb02a0cf286170614fa62..c6c3df7a0459db1902e38adc42411432a7a4cf99 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -6144,6 +6144,8 @@ CONFIG_TEE=m # CONFIG_INTERCONNECT is not set # CONFIG_COUNTER is not set # CONFIG_MOST is not set +CONFIG_ROH=m +CONFIG_ROH_HNS=m # end of Device Drivers # diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c index 67b0bf310daaafd1f4a6f4b3bf6c64d06d99e10f..ee4b7f5910b1fa3d97405c2c350da0acce483397 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c @@ -40,7 +40,8 @@ static DEFINE_MUTEX(hnae3_common_lock); static bool hnae3_client_match(enum hnae3_client_type client_type) { if (client_type == HNAE3_CLIENT_KNIC || - client_type == HNAE3_CLIENT_ROCE) + client_type == HNAE3_CLIENT_ROCE || + client_type == HNAE3_CLIENT_ROH) return true; return false; @@ -60,6 +61,9 @@ void hnae3_set_client_init_flag(struct hnae3_client *client, case HNAE3_CLIENT_ROCE: hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited); break; + case HNAE3_CLIENT_ROH: + hnae3_set_bit(ae_dev->flag, HNAE3_ROH_CLIENT_INITED_B, inited); + break; default: break; } @@ -80,6 +84,10 @@ static int hnae3_get_client_init_flag(struct hnae3_client *client, inited = hnae3_get_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B); break; + case HNAE3_CLIENT_ROH: + inited = hnae3_get_bit(ae_dev->flag, + HNAE3_ROH_CLIENT_INITED_B); + break; default: break; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index fb95e83bb740ede5f8e0805fed23358a0c649cd8..cedcac37145a480f5ee31809306ae1e8a544aa16 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -51,7 +51,10 @@ #define HNAE3_DEV_ID_50GE_RDMA 0xA224 #define HNAE3_DEV_ID_50GE_RDMA_MACSEC 0xA225 #define HNAE3_DEV_ID_100G_RDMA_MACSEC 0xA226 +#define HNAE3_DEV_ID_100G_ROH 0xA227 #define HNAE3_DEV_ID_200G_RDMA 0xA228 +#define HNAE3_DEV_ID_200G_ROH 0xA22C +#define HNAE3_DEV_ID_400G_ROH 0xA22D #define HNAE3_DEV_ID_VF 0xA22E #define HNAE3_DEV_ID_RDMA_DCB_PFC_VF 0xA22F @@ -63,6 +66,7 @@ #define HNAE3_KNIC_CLIENT_INITED_B 0x3 #define HNAE3_UNIC_CLIENT_INITED_B 0x4 #define HNAE3_ROCE_CLIENT_INITED_B 0x5 +#define HNAE3_ROH_CLIENT_INITED_B 0x6 #define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) | \ BIT(HNAE3_DEV_SUPPORT_ROCE_B)) @@ -197,6 +201,12 @@ enum hnae3_loop { enum hnae3_client_type { HNAE3_CLIENT_KNIC, HNAE3_CLIENT_ROCE, + HNAE3_CLIENT_ROH, +}; + +enum hnae3_mac_type { + HNAE3_MAC_ETH, + HNAE3_MAC_ROH, }; /* mac media type */ @@ -827,6 +837,13 @@ struct hnae3_roce_private_info { unsigned long state; }; +struct hnae3_roh_private_info { + struct net_device *netdev; + void __iomem *roh_io_base; + int base_vector; + unsigned long reset_state; +}; + #define HNAE3_SUPPORT_APP_LOOPBACK BIT(0) #define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1) #define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2) @@ -859,6 +876,7 @@ struct hnae3_handle { struct net_device *netdev; /* first member */ struct hnae3_knic_private_info kinfo; struct hnae3_roce_private_info rinfo; + struct hnae3_roh_private_info rohinfo; }; u32 numa_node_mask; /* for multi-chip support */ @@ -876,6 +894,8 @@ struct hnae3_handle { unsigned long supported_pflags; unsigned long priv_flags; + + enum hnae3_mac_type mac_type; }; #define hnae3_set_field(origin, mask, shift, val) \ @@ -890,6 +910,11 @@ struct hnae3_handle { #define hnae3_get_bit(origin, shift) \ hnae3_get_field(origin, 0x1 << (shift), shift) +static inline bool hnae3_check_roh_mac_type(struct hnae3_handle *handle) +{ + return handle->mac_type == HNAE3_MAC_ROH; +} + #define HNAE3_FORMAT_MAC_ADDR_LEN 18 #define HNAE3_FORMAT_MAC_ADDR_OFFSET_0 0 #define HNAE3_FORMAT_MAC_ADDR_OFFSET_4 4 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 7601a84873b7d7043e7ea0c0458566321a8bec11..119a1600eb94e6eaa0b14bb70fb5bef1882b8cc0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -94,8 +94,14 @@ static const struct pci_device_id hns3_pci_tbl[] = { HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_ROH), + HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_RDMA), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_ROH), + HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), + HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_VF), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_DCB_PFC_VF), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, @@ -3044,7 +3050,10 @@ bool hns3_is_phys_func(struct pci_dev *pdev) case HNAE3_DEV_ID_50GE_RDMA: case HNAE3_DEV_ID_50GE_RDMA_MACSEC: case HNAE3_DEV_ID_100G_RDMA_MACSEC: + case HNAE3_DEV_ID_100G_ROH: case HNAE3_DEV_ID_200G_RDMA: + case HNAE3_DEV_ID_200G_ROH: + case HNAE3_DEV_ID_400G_ROH: return true; case HNAE3_DEV_ID_VF: case HNAE3_DEV_ID_RDMA_DCB_PFC_VF: diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 489a87e9ecb40e4898362b2cf0d6a0145c407184..88110835e8767a670091ac001ddbca4e172339c6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -180,7 +180,8 @@ struct hclge_pf_res_cmd { __le16 tx_buf_size; __le16 dv_buf_size; __le16 ext_tqp_num; - u8 rsv[6]; + __le16 pf_intr_vector_number_roh; + u8 rsv[4]; }; #define HCLGE_CFG_OFFSET_S 0 @@ -409,6 +410,13 @@ struct hclge_mac_vlan_tbl_entry_cmd { u8 rsv2[6]; }; +struct hclge_check_mac_addr_cmd { + u8 response; + u8 mac_addr[ETH_ALEN]; + u8 vf_id; + u8 rsv[16]; +}; + #define HCLGE_UMV_SPC_ALC_B 0 struct hclge_umv_spc_alc_cmd { u8 allocate; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 142415c84c6b2ded65bd1f16f622dd30c53e2f3c..7051ea085569b5253dca0614688d7b6ad965e915 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -368,6 +368,16 @@ static int hclge_dbg_dump_mac_speed_duplex(struct hclge_dev *hdev, char *buf, return 0; } +static void hclge_dbg_dump_mac_type(struct hclge_dev *hdev, char *buf, int len, + int *pos) +{ + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + + *pos += scnprintf(buf + *pos, len - *pos, "type: %s\n", + handle->mac_type ? "ROH" : "Ethernet"); +} + static int hclge_dbg_dump_mac(struct hclge_dev *hdev, char *buf, int len) { int pos = 0; @@ -381,7 +391,13 @@ static int hclge_dbg_dump_mac(struct hclge_dev *hdev, char *buf, int len) if (ret) return ret; - return hclge_dbg_dump_mac_speed_duplex(hdev, buf, len, &pos); + ret = hclge_dbg_dump_mac_speed_duplex(hdev, buf, len, &pos); + if (ret) + return ret; + + hclge_dbg_dump_mac_type(hdev, buf, len, &pos); + + return 0; } static int hclge_dbg_dump_dcb_qset(struct hclge_dev *hdev, char *buf, int len, @@ -1740,6 +1756,8 @@ static int hclge_dbg_dump_interrupt(struct hclge_dev *hdev, char *buf, int len) hdev->num_nic_msi); pos += scnprintf(buf + pos, len - pos, "num_roce_msi: %u\n", hdev->num_roce_msi); + pos += scnprintf(buf + pos, len - pos, "num_roh_msi: %u\n", + hdev->num_roh_msi); pos += scnprintf(buf + pos, len - pos, "num_msi_used: %u\n", hdev->num_msi_used); pos += scnprintf(buf + pos, len - pos, "num_msi_left: %u\n", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index 6efd768cc07cffee1cac345276bd65a0966823fb..869b529f68e3ff8eb1a47adcf82a253c66cda988 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -1275,6 +1275,15 @@ static const struct hclge_hw_module_id hclge_hw_module_id_st[] = { }, { .module_id = MODULE_ROCEE_LSAN, .msg = "MODULE_ROCEE_LSAN" + }, { + .module_id = MODULE_ROH_MAC_IF, + .msg = "MODULE_ROH_MAC_IF" + }, { + .module_id = MODULE_ROH_HDLC, + .msg = "MODULE_ROH_HDLC" + }, { + .module_id = MODULE_ROH_HPCS, + .msg = "MODULE_ROH_HPCS" } }; @@ -1333,7 +1342,10 @@ static const struct hclge_hw_type_id hclge_hw_type_id_st[] = { }, { .type_id = ROCEE_BUS_ERR, .msg = "rocee_bus_error" - }, + }, { + .type_id = ROH_ERR, + .msg = "roh_error" + } }; static void hclge_log_error(struct device *dev, char *reg, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h index 86be6fb329901755c0c409ffba3e9fdc2e023c33..bbc67be31cf62664918cd55e795b42474988e9d5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h @@ -15,8 +15,10 @@ #define HCLGE_RAS_PF_OTHER_INT_STS_REG 0x20B00 #define HCLGE_RAS_REG_NFE_MASK 0xFF00 #define HCLGE_RAS_REG_ROCEE_ERR_MASK 0x3000000 +#define HCLGE_RAS_REG_ROH_ERR_MASK 0x18000000 #define HCLGE_RAS_REG_ERR_MASK \ - (HCLGE_RAS_REG_NFE_MASK | HCLGE_RAS_REG_ROCEE_ERR_MASK) + (HCLGE_RAS_REG_NFE_MASK | HCLGE_RAS_REG_ROCEE_ERR_MASK | \ + HCLGE_RAS_REG_ROH_ERR_MASK) #define HCLGE_VECTOR0_REG_MSIX_MASK 0x1FF00 @@ -151,6 +153,10 @@ enum hclge_mod_name_list { MODULE_ROCEE_QMM = 48, MODULE_ROCEE_LSAN = 49, /* add new MODULE NAME for RoCEE here in order */ + MODULE_ROH_MAC_IF = 80, + MODULE_ROH_HDLC = 81, + MODULE_ROH_HPCS = 82, + /* add new MODULE NAME for ROH here in order */ }; enum hclge_err_type_list { @@ -174,6 +180,8 @@ enum hclge_err_type_list { ROCEE_OVF_ERR = 41, ROCEE_BUS_ERR = 42, /* add new ERROR TYPE for ROCEE here in order */ + ROH_ERR = 80, + /* add new ERROR TYPE for ROH here in order */ }; struct hclge_hw_blk { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 5214e3ede54d09a19b0ce643400d53878da03318..823c6ea7b0e0983005613369885dfce8462aeba3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -84,7 +84,10 @@ static const struct pci_device_id ae_algo_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA_MACSEC), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), 0}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_ROH), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_RDMA), 0}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_ROH), 0}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), 0}, /* required last entry */ {0, } }; @@ -920,11 +923,14 @@ static int hclge_query_pf_resource(struct hclge_dev *hdev) if (hnae3_dev_roce_supported(hdev)) { hdev->num_roce_msi = le16_to_cpu(req->pf_intr_vector_number_roce); + hdev->num_roh_msi = + le16_to_cpu(req->pf_intr_vector_number_roh); /* PF should have NIC vectors and Roce vectors, * NIC vectors are queued before Roce vectors. */ - hdev->num_msi = hdev->num_nic_msi + hdev->num_roce_msi; + hdev->num_msi = hdev->num_nic_msi + hdev->num_roce_msi + + hdev->num_roh_msi; } else { hdev->num_msi = hdev->num_nic_msi; } @@ -1516,6 +1522,20 @@ static int hclge_query_dev_specs(struct hclge_dev *hdev) return 0; } +static void hclge_mac_type_init(struct hclge_dev *hdev) +{ + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + u32 dev_id = hdev->pdev->device; + + if (dev_id == HNAE3_DEV_ID_100G_ROH || + dev_id == HNAE3_DEV_ID_200G_ROH || + dev_id == HNAE3_DEV_ID_400G_ROH) + handle->mac_type = HNAE3_MAC_ROH; + else + handle->mac_type = HNAE3_MAC_ETH; +} + static int hclge_get_cap(struct hclge_dev *hdev) { int ret; @@ -2544,6 +2564,25 @@ static int hclge_init_roce_base_info(struct hclge_vport *vport) return 0; } +static int hclge_init_roh_base_info(struct hclge_vport *vport) +{ + struct hnae3_handle *roh = &vport->roh; + struct hnae3_handle *nic = &vport->nic; + struct hclge_dev *hdev = vport->back; + + if (hdev->num_msi < hdev->num_nic_msi + hdev->num_roce_msi + + hdev->num_roh_msi) + return -EINVAL; + + roh->rohinfo.netdev = nic->kinfo.netdev; + roh->rohinfo.roh_io_base = hdev->hw.hw.io_base; + + roh->pdev = nic->pdev; + roh->ae_algo = nic->ae_algo; + + return 0; +} + static int hclge_init_msi(struct hclge_dev *hdev) { struct pci_dev *pdev = hdev->pdev; @@ -2823,12 +2862,13 @@ static void hclge_get_fec(struct hnae3_handle *handle, u8 *fec_ability, if (fec_mode) *fec_mode = mac->fec_mode; } - static int hclge_mac_init(struct hclge_dev *hdev) { struct hclge_mac *mac = &hdev->hw.mac; int ret; + hclge_mac_type_init(hdev); + hdev->support_sfp_query = true; hdev->hw.mac.duplex = HCLGE_MAC_FULL; ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed, @@ -3674,6 +3714,28 @@ static int hclge_notify_roce_client(struct hclge_dev *hdev, return ret; } +static int hclge_notify_roh_client(struct hclge_dev *hdev, + enum hnae3_reset_notify_type type) +{ + struct hnae3_handle *handle = &hdev->vport[0].roh; + struct hnae3_client *client = hdev->roh_client; + int ret; + + if (!test_bit(HCLGE_STATE_ROH_REGISTERED, &hdev->state) || !client) + return 0; + + if (!client->ops->reset_notify) + return -EOPNOTSUPP; + + ret = client->ops->reset_notify(handle, type); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to notify roh client type %d, ret = %d\n", + type, ret); + + return ret; +} + static int hclge_reset_wait(struct hclge_dev *hdev) { #define HCLGE_RESET_WATI_MS 100 @@ -4194,6 +4256,10 @@ static int hclge_reset_prepare(struct hclge_dev *hdev) if (ret) return ret; + ret = hclge_notify_roh_client(hdev, HNAE3_DOWN_CLIENT); + if (ret) + return ret; + rtnl_lock(); ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT); rtnl_unlock(); @@ -4213,6 +4279,10 @@ static int hclge_reset_rebuild(struct hclge_dev *hdev) if (ret) return ret; + ret = hclge_notify_roh_client(hdev, HNAE3_UNINIT_CLIENT); + if (ret) + return ret; + rtnl_lock(); ret = hclge_reset_stack(hdev); rtnl_unlock(); @@ -4229,6 +4299,14 @@ static int hclge_reset_rebuild(struct hclge_dev *hdev) hdev->rst_stats.reset_fail_cnt < HCLGE_RESET_MAX_FAIL_CNT - 1) return ret; + ret = hclge_notify_roh_client(hdev, HNAE3_INIT_CLIENT); + /* ignore ROH notify error if it fails HCLGE_RESET_MAX_FAIL_CNT - 1 + * times + */ + if (ret && + hdev->rst_stats.reset_fail_cnt < HCLGE_RESET_MAX_FAIL_CNT - 1) + return ret; + ret = hclge_reset_prepare_up(hdev); if (ret) return ret; @@ -4243,6 +4321,10 @@ static int hclge_reset_rebuild(struct hclge_dev *hdev) if (ret) return ret; + ret = hclge_notify_roh_client(hdev, HNAE3_UP_CLIENT); + if (ret) + return ret; + hdev->last_reset_time = jiffies; hdev->rst_stats.reset_fail_cnt = 0; hdev->rst_stats.reset_done_cnt++; @@ -4560,6 +4642,8 @@ struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle) return container_of(handle, struct hclge_vport, nic); else if (handle->client->type == HNAE3_CLIENT_ROCE) return container_of(handle, struct hclge_vport, roce); + else if (handle->client->type == HNAE3_CLIENT_ROH) + return container_of(handle, struct hclge_vport, roh); else return container_of(handle, struct hclge_vport, nic); } @@ -9017,6 +9101,35 @@ static int hclge_get_mac_ethertype_cmd_status(struct hclge_dev *hdev, return return_status; } +int hclge_check_mac_addr_valid(struct hclge_dev *hdev, u8 vf, + const u8 *mac_addr) +{ + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; + struct hclge_check_mac_addr_cmd *req; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_ADDR_CHECK, false); + req = (struct hclge_check_mac_addr_cmd *)desc.data; + ether_addr_copy(req->mac_addr, mac_addr); + req->vf_id = vf; + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, "failed to check function %u mac addr valid, ret = %d\n", + vf, ret); + return ret; + } + + if (req->response) { + hnae3_format_mac_addr(format_mac_addr, mac_addr); + dev_err(&hdev->pdev->dev, "invalid function %u mac addr: %s\n", + vf, format_mac_addr); + return -EINVAL; + } + + return 0; +} + static int hclge_set_vf_mac(struct hnae3_handle *handle, int vf, u8 *mac_addr) { @@ -9171,6 +9284,12 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, return -EINVAL; } + if (hnae3_check_roh_mac_type(handle)) { + ret = hclge_check_mac_addr_valid(hdev, 0, new_addr); + if (ret) + return ret; + } + ret = hclge_pause_addr_cfg(hdev, new_addr); if (ret) { dev_err(&hdev->pdev->dev, @@ -11050,6 +11169,47 @@ static int hclge_init_roce_client_instance(struct hnae3_ae_dev *ae_dev, return ret; } +static int hclge_init_roh_client_instance(struct hnae3_ae_dev *ae_dev, + struct hclge_vport *vport) +{ + struct hclge_dev *hdev = ae_dev->priv; + struct hnae3_client *client; + int rst_cnt; + int ret; + + if (!hdev->roh_client || !hdev->nic_client) + return 0; + + client = hdev->roh_client; + ret = hclge_init_roh_base_info(vport); + if (ret) + return ret; + + rst_cnt = hdev->rst_stats.reset_cnt; + ret = client->ops->init_instance(&vport->roh); + if (ret) + return ret; + + if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || + rst_cnt != hdev->rst_stats.reset_cnt) { + ret = -EBUSY; + goto init_roh_err; + } + + set_bit(HCLGE_STATE_ROH_REGISTERED, &hdev->state); + hnae3_set_client_init_flag(client, ae_dev, 1); + + return 0; + +init_roh_err: + while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) + msleep(HCLGE_WAIT_RESET_DONE); + + hdev->roh_client->ops->uninit_instance(&vport->roh, 0); + + return ret; +} + static int hclge_init_client_instance(struct hnae3_client *client, struct hnae3_ae_dev *ae_dev) { @@ -11065,6 +11225,14 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_nic; + ret = hclge_init_roh_client_instance(ae_dev, vport); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to init roh client, ret = %d\n", ret); + hdev->roh_client = NULL; + vport->roh.client = NULL; + } + ret = hclge_init_roce_client_instance(ae_dev, vport); if (ret) goto clear_roce; @@ -11080,6 +11248,15 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roce; + break; + case HNAE3_CLIENT_ROH: + hdev->roh_client = client; + vport->roh.client = client; + + ret = hclge_init_roh_client_instance(ae_dev, vport); + if (ret) + goto clear_roh; + break; default: return -EINVAL; @@ -11095,6 +11272,10 @@ static int hclge_init_client_instance(struct hnae3_client *client, hdev->roce_client = NULL; vport->roce.client = NULL; return ret; +clear_roh: + hdev->roh_client = NULL; + vport->roh.client = NULL; + return ret; } static void hclge_uninit_client_instance(struct hnae3_client *client, @@ -11103,6 +11284,19 @@ static void hclge_uninit_client_instance(struct hnae3_client *client, struct hclge_dev *hdev = ae_dev->priv; struct hclge_vport *vport = &hdev->vport[0]; + if (hdev->roh_client && (client->type == HNAE3_CLIENT_ROH || + client->type == HNAE3_CLIENT_KNIC)) { + clear_bit(HCLGE_STATE_ROH_REGISTERED, &hdev->state); + while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) + msleep(HCLGE_WAIT_RESET_DONE); + + hdev->roh_client->ops->uninit_instance(&vport->roh, 0); + hdev->roh_client = NULL; + vport->roh.client = NULL; + } + if (client->type == HNAE3_CLIENT_ROH) + return; + if (hdev->roce_client) { clear_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state); while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index d2158116398d367fb677f327b356b0e451e94127..f48ba1e7589c860348865663b24425b89057f44e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -202,6 +202,7 @@ enum HCLGE_DEV_STATE { HCLGE_STATE_REMOVING, HCLGE_STATE_NIC_REGISTERED, HCLGE_STATE_ROCE_REGISTERED, + HCLGE_STATE_ROH_REGISTERED, HCLGE_STATE_SERVICE_INITED, HCLGE_STATE_RST_SERVICE_SCHED, HCLGE_STATE_RST_HANDLING, @@ -874,6 +875,7 @@ struct hclge_dev { int *vector_irq; u16 num_nic_msi; /* Num of nic vectors for this PF */ u16 num_roce_msi; /* Num of roce vectors for this PF */ + u16 num_roh_msi; /* Num of roh vectors for this PF */ unsigned long service_timer_period; unsigned long service_timer_previous; @@ -890,6 +892,7 @@ struct hclge_dev { struct hnae3_client *nic_client; struct hnae3_client *roce_client; + struct hnae3_client *roh_client; #define HCLGE_FLAG_MAIN BIT(0) #define HCLGE_FLAG_DCB_CAPABLE BIT(1) @@ -1019,6 +1022,7 @@ struct hclge_vport { struct hclge_dev *back; /* Back reference to associated dev */ struct hnae3_handle nic; struct hnae3_handle roce; + struct hnae3_handle roh; unsigned long state; unsigned long last_active_jiffies; @@ -1120,6 +1124,8 @@ void hclge_report_hw_error(struct hclge_dev *hdev, enum hnae3_hw_error_type type); void hclge_inform_vf_promisc_info(struct hclge_vport *vport); int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len); +int hclge_check_mac_addr_valid(struct hclge_dev *hdev, u8 vf, + const u8 *mac_addr); int hclge_push_vf_link_status(struct hclge_vport *vport); int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en); int hclge_mac_update_stats(struct hclge_dev *hdev); diff --git a/drivers/roh/Kconfig b/drivers/roh/Kconfig index 0ff2de261827413db6613c31f3c23654f5e3db52..af42314b620d932c282b57e013b80ae8cc478b49 100644 --- a/drivers/roh/Kconfig +++ b/drivers/roh/Kconfig @@ -9,8 +9,14 @@ menuconfig ROH select IRQ_POLL select DIMLIB help - Core support for ROH. Make sure to also select + Core support for ROH. Make sure to also select any protocols you wish to use as well as drivers for your ROH hardware. To compile ROH core as module, choose M here. + +if ROH + +source "drivers/roh/hw/hns3/Kconfig" + +endif # ROH diff --git a/drivers/roh/Makefile b/drivers/roh/Makefile index e5ea16bd6b21b538392bb4e853af0f0a6c246e3f..8b2598e2de8ecb2d27ca3469e11cdbec54a6de8b 100644 --- a/drivers/roh/Makefile +++ b/drivers/roh/Makefile @@ -4,3 +4,4 @@ # obj-$(CONFIG_ROH) += core/ +obj-$(CONFIG_ROH) += hw/ diff --git a/drivers/roh/core/core.c b/drivers/roh/core/core.c index 39c1404e0d97922b5164e23c7a4c1e8e0ee81a2c..2883d605e9bceb17084888e2999d7fd393e72fe0 100644 --- a/drivers/roh/core/core.c +++ b/drivers/roh/core/core.c @@ -464,7 +464,7 @@ int roh_core_init(void) ret = class_register(&roh_class); if (ret) { - pr_err("roh_core: couldn't create roh device class.\n"); + pr_err("roh_core: couldn't create roh device class, ret = %d\n", ret); return ret; } diff --git a/drivers/roh/core/main.c b/drivers/roh/core/main.c index 0f766f85eaf5fd39201d2ca81cabf58f434f1bc6..b9c6a75dd10b79de1271311778a67caa4d131666 100644 --- a/drivers/roh/core/main.c +++ b/drivers/roh/core/main.c @@ -12,7 +12,7 @@ static int __init roh_init(void) ret = roh_core_init(); if (ret) { - pr_err("roh_core: roh core init failed.\n"); + pr_err("roh_core: roh core init failed, ret = %d\n", ret); return ret; } diff --git a/drivers/roh/hw/Makefile b/drivers/roh/hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e6f0e2a8825c04d7135943a5bcc938eca1cff257 --- /dev/null +++ b/drivers/roh/hw/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-$(CONFIG_ROH_HNS) += hns3/ \ No newline at end of file diff --git a/drivers/roh/hw/hns3/Kconfig b/drivers/roh/hw/hns3/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..79d14a30f833a67d5fab0e75d1099e2e95299d3d --- /dev/null +++ b/drivers/roh/hw/hns3/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0+ +config ROH_HNS + tristate "HNS ROH Driver" + depends on NET_VENDOR_HISILICON + depends on ARM64 + depends on PCI && HNS3 + help + This is a ROH driver for the Hisilicon ROH engine. The engine + is used in Hisilicon Hip09 and more further ICT SoC based on + PCI device. + + To compile HIP09 driver as module, choose M here. diff --git a/drivers/roh/hw/hns3/Makefile b/drivers/roh/hw/hns3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3a7fb499fddbd5a346524b7f332c8d9171cd7369 --- /dev/null +++ b/drivers/roh/hw/hns3/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Makefile for the Hisilicon ROH hns3 device drivers. +# + +ccflags-y := -I $(srctree)/drivers/net/ethernet/hisilicon/hns3 +ccflags-y += -I $(srctree)/drivers/roh/core +ccflags-y += -I $(srctree)/drivers/roh/hw/hns3 + +hns-roh-v1-objs := hns3_cmdq.o \ + hns3_main.o +obj-$(CONFIG_ROH_HNS) += hns-roh-v1.o diff --git a/drivers/roh/hw/hns3/hns3_cmdq.c b/drivers/roh/hw/hns3/hns3_cmdq.c new file mode 100644 index 0000000000000000000000000000000000000000..325b5a20f431371af098641e7b2628f8184fce74 --- /dev/null +++ b/drivers/roh/hw/hns3/hns3_cmdq.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2020-2022 Hisilicon Limited. + +#include +#include +#include +#include +#include + +#include "core.h" +#include "hns3_common.h" +#include "hns3_cmdq.h" +#include "hns3_reg.h" + +static int hns3_roh_alloc_cmdq_desc(struct hns3_roh_device *hroh_dev, + struct hns3_roh_cmdq_ring *ring) +{ + u32 size = ring->desc_num * sizeof(struct hns3_roh_desc); + + ring->desc = kzalloc(size, GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + + ring->desc_dma_addr = dma_map_single(hroh_dev->dev, ring->desc, size, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(hroh_dev->dev, ring->desc_dma_addr)) { + dev_err(hroh_dev->dev, "failed to dma mapping.\n"); + ring->desc_dma_addr = 0; + kfree(ring->desc); + ring->desc = NULL; + return -ENOMEM; + } + + return 0; +} + +static void hns3_roh_free_cmdq_desc(struct hns3_roh_device *hroh_dev, + struct hns3_roh_cmdq_ring *ring) +{ + dma_unmap_single(hroh_dev->dev, ring->desc_dma_addr, + ring->desc_num * sizeof(struct hns3_roh_desc), + DMA_BIDIRECTIONAL); + + ring->desc_dma_addr = 0; + kfree(ring->desc); + ring->desc = NULL; +} + +static int hns3_roh_init_cmdq_ring(struct hns3_roh_device *hroh_dev, u8 ring_type) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + struct hns3_roh_cmdq_ring *ring = + (ring_type == HNS3_ROH_CMDQ_CSQ) ? &priv->cmdq.csq : &priv->cmdq.crq; + + ring->flag = ring_type; + ring->next_to_clean = 0; + ring->next_to_use = 0; + + return hns3_roh_alloc_cmdq_desc(hroh_dev, ring); +} + +static void hns3_roh_cmdq_clear_regs(struct hns3_roh_device *hroh_dev) +{ + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_BASEADDR_L_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_BASEADDR_H_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_DEPTH_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_HEAD_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_TAIL_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_BASEADDR_L_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_BASEADDR_H_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_DEPTH_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_HEAD_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_TAIL_REG, 0); +} + +static void hns3_roh_cmdq_init_regs(struct hns3_roh_device *hroh_dev, u8 ring_type) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + struct hns3_roh_cmdq_ring *ring = + (ring_type == HNS3_ROH_CMDQ_CSQ) ? &priv->cmdq.csq : &priv->cmdq.crq; + dma_addr_t dma = ring->desc_dma_addr; + + if (ring_type == HNS3_ROH_CMDQ_CSQ) { + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_BASEADDR_L_REG, (u32)dma); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_BASEADDR_H_REG, + upper_32_bits(dma)); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_DEPTH_REG, + ring->desc_num >> HNS3_ROH_CMDQ_DESC_NUM); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_HEAD_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_TAIL_REG, 0); + } else { + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_BASEADDR_L_REG, (u32)dma); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_BASEADDR_H_REG, + upper_32_bits(dma)); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_DEPTH_REG, + ring->desc_num >> HNS3_ROH_CMDQ_DESC_NUM); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_HEAD_REG, 0); + hns3_roh_write(hroh_dev, HNS3_ROH_RX_CMDQ_TAIL_REG, 0); + } +} + +int hns3_roh_cmdq_init(struct hns3_roh_device *hroh_dev) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + int ret; + + /* Setup the lock for command queue */ + spin_lock_init(&priv->cmdq.csq.lock); + spin_lock_init(&priv->cmdq.crq.lock); + + /* Clear up all command register, + * in case there are some residual values + */ + hns3_roh_cmdq_clear_regs(hroh_dev); + + /* Setup the queue entries for command queue */ + priv->cmdq.csq.desc_num = HNS3_ROH_CMDQ_CSQ_DESC_NUM; + priv->cmdq.crq.desc_num = HNS3_ROH_CMDQ_CRQ_DESC_NUM; + + /* Setup Tx write back timeout */ + priv->cmdq.tx_timeout = HNS3_ROH_CMDQ_TX_TIMEOUT; + + /* Init CSQ */ + ret = hns3_roh_init_cmdq_ring(hroh_dev, HNS3_ROH_CMDQ_CSQ); + if (ret) { + dev_err(hroh_dev->dev, "failed to init csq, ret = %d\n", ret); + return ret; + } + + /* Init CRQ */ + ret = hns3_roh_init_cmdq_ring(hroh_dev, HNS3_ROH_CMDQ_CRQ); + if (ret) { + dev_err(hroh_dev->dev, "failed to init crq, ret = %d\n", ret); + goto err_crq; + } + + /* Init CSQ REG */ + hns3_roh_cmdq_init_regs(hroh_dev, HNS3_ROH_CMDQ_CSQ); + + /* Init CRQ REG */ + hns3_roh_cmdq_init_regs(hroh_dev, HNS3_ROH_CMDQ_CRQ); + + return 0; + +err_crq: + hns3_roh_free_cmdq_desc(hroh_dev, &priv->cmdq.csq); + return ret; +} + +void hns3_roh_cmdq_exit(struct hns3_roh_device *hroh_dev) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + + spin_lock_bh(&priv->cmdq.csq.lock); + spin_lock(&priv->cmdq.crq.lock); + hns3_roh_cmdq_clear_regs(hroh_dev); + spin_unlock(&priv->cmdq.crq.lock); + spin_unlock_bh(&priv->cmdq.csq.lock); + + hns3_roh_free_cmdq_desc(hroh_dev, &priv->cmdq.csq); + hns3_roh_free_cmdq_desc(hroh_dev, &priv->cmdq.crq); +} + +static int hns3_roh_cmdq_space(struct hns3_roh_cmdq_ring *ring) +{ + int ntu = ring->next_to_use; + int ntc = ring->next_to_clean; + int used = (ntu - ntc + ring->desc_num) % ring->desc_num; + + return ring->desc_num - used - 1; +} + +void hns3_roh_cmdq_setup_basic_desc(struct hns3_roh_desc *desc, + enum hns3_roh_opcode_type opcode, + bool is_read) +{ + memset((void *)desc, 0, sizeof(struct hns3_roh_desc)); + desc->opcode = cpu_to_le16(opcode); + desc->flag = cpu_to_le16(HNS3_ROH_CMD_FLAG_NO_INTR | HNS3_ROH_CMD_FLAG_IN); + if (is_read) + desc->flag |= cpu_to_le16(HNS3_ROH_CMD_FLAG_WR); +} + +static int hns3_roh_cmdq_csq_done(struct hns3_roh_device *hroh_dev) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + u32 head = hns3_roh_read(hroh_dev, HNS3_ROH_TX_CMDQ_HEAD_REG); + + return head == priv->cmdq.csq.next_to_use; +} + +static int hns3_roh_cmdq_csq_clean(struct hns3_roh_device *hroh_dev) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + struct hns3_roh_cmdq_ring *csq = &priv->cmdq.csq; + u16 ntc = csq->next_to_clean; + struct hns3_roh_desc *desc; + int clean = 0; + u32 head; + + desc = &csq->desc[ntc]; + head = hns3_roh_read(hroh_dev, HNS3_ROH_TX_CMDQ_HEAD_REG); + while (head != ntc) { + memset(desc, 0, sizeof(*desc)); + ntc++; + if (ntc == csq->desc_num) + ntc = 0; + desc = &csq->desc[ntc]; + clean++; + } + csq->next_to_clean = ntc; + + return clean; +} + +static int hns3_roh_cmdq_build(struct hns3_roh_device *hroh_dev, + struct hns3_roh_desc *desc, + int num, int *ntc) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + struct hns3_roh_cmdq_ring *csq = &priv->cmdq.csq; + struct hns3_roh_desc *desc_to_use = NULL; + int handle = 0; + + if (num > hns3_roh_cmdq_space(csq)) { + dev_err(hroh_dev->dev, "cmdq is full, opcode %x\n", desc->opcode); + return -EBUSY; + } + + *ntc = csq->next_to_use; + while (handle < num) { + desc_to_use = &csq->desc[csq->next_to_use]; + *desc_to_use = desc[handle]; + csq->next_to_use++; + if (csq->next_to_use == csq->desc_num) + csq->next_to_use = 0; + handle++; + } + + return 0; +} + +static int hns3_roh_cmdq_done_parse(struct hns3_roh_device *hroh_dev, + struct hns3_roh_desc *desc, + int num, int ntc) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + struct hns3_roh_cmdq_ring *csq = &priv->cmdq.csq; + struct hns3_roh_desc *desc_to_use = NULL; + int handle = 0; + u16 desc_ret; + int ret; + + if (hns3_roh_cmdq_csq_done(hroh_dev)) { + while (handle < num) { + desc_to_use = &csq->desc[ntc]; + desc[handle] = *desc_to_use; + desc_ret = le16_to_cpu(desc[handle].retval); + if (desc_ret == HNS3_ROH_CMD_EXEC_SUCCESS) { + ret = 0; + } else if (desc_ret == HNS3_ROH_CMD_EXEC_TIMEOUT) { + priv->cmdq.last_status = desc_ret; + ret = -ETIME; + } else { + pr_err("desc_ret = %d\n", desc_ret); + ret = -EIO; + } + + ntc++; + handle++; + if (ntc == csq->desc_num) + ntc = 0; + } + } else { + ret = -EAGAIN; + } + + return ret; +} + +int hns3_roh_cmdq_send(struct hns3_roh_device *hroh_dev, struct hns3_roh_desc *desc, int num) +{ + struct hns3_roh_priv *priv = (struct hns3_roh_priv *)hroh_dev->priv; + struct hns3_roh_cmdq_ring *csq = &priv->cmdq.csq; + u32 timeout = 0; + int handle = 0; + int ntc = 0; + int ret = 0; + + spin_lock_bh(&csq->lock); + ret = hns3_roh_cmdq_build(hroh_dev, desc, num, &ntc); + if (ret) { + spin_unlock_bh(&csq->lock); + return ret; + } + + /* Write to hardware */ + hns3_roh_write(hroh_dev, HNS3_ROH_TX_CMDQ_TAIL_REG, csq->next_to_use); + + if (desc->flag & cpu_to_le16(HNS3_ROH_CMD_FLAG_NO_INTR)) { + do { + if (hns3_roh_cmdq_csq_done(hroh_dev)) + break; + udelay(1); + timeout++; + } while (timeout < priv->cmdq.tx_timeout); + } + + ret = hns3_roh_cmdq_done_parse(hroh_dev, desc, num, ntc); + + handle = hns3_roh_cmdq_csq_clean(hroh_dev); + if (handle != num) + dev_warn(hroh_dev->dev, "cleaned %d, need to clean %d\n", handle, num); + spin_unlock_bh(&csq->lock); + + return ret; +} diff --git a/drivers/roh/hw/hns3/hns3_cmdq.h b/drivers/roh/hw/hns3/hns3_cmdq.h new file mode 100644 index 0000000000000000000000000000000000000000..ca6df81c43d94a8d297423955f59e4aed6657fa3 --- /dev/null +++ b/drivers/roh/hw/hns3/hns3_cmdq.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +// Copyright (c) 2020-2022 Hisilicon Limited. + +#ifndef __HNS3_ROH_CMDQ_H__ +#define __HNS3_ROH_CMDQ_H__ + +#include "hns3_common.h" + +#define HNS3_ROH_MAILBOX_SIZE 4096 +#define HNS3_ROH_CMDQ_DESC_NUM 3 +#define HNS3_ROH_CMDQ_TX_TIMEOUT 30000 + +#define HNS3_ROH_MAX_CMD_NUM 32 + +#define HNS3_ROH_CMDQ_CSQ_DESC_NUM 1024 +#define HNS3_ROH_CMDQ_CRQ_DESC_NUM 1024 + +#define HNS3_ROH_CMD_FLAG_IN BIT(0) +#define HNS3_ROH_CMD_FLAG_OUT BIT(1) +#define HNS3_ROH_CMD_FLAG_NEXT BIT(2) +#define HNS3_ROH_CMD_FLAG_WR BIT(3) +#define HNS3_ROH_CMD_FLAG_NO_INTR BIT(4) +#define HNS3_ROH_CMD_FLAG_ERR_INTR BIT(5) + +enum { HNS3_ROH_CMDQ_CRQ = 0, HNS3_ROH_CMDQ_CSQ }; + +enum hns3_roh_opcode_type { + HNS3_ROH_OPC_GET_INTR_INFO = 0x0023, + HNS3_ROH_OPC_SET_EID = 0x9001, + HNS3_ROH_OPC_GET_GUID = 0x9002, + HNS3_ROH_OPC_QUERY_MIB_PUBLIC = 0x9005, + HNS3_ROH_OPC_QUERY_MIB_PRIVATE = 0x9006, +}; + +enum hns3_roh_cmd_return_status { + HNS3_ROH_CMD_EXEC_SUCCESS = 0, + HNS3_ROH_CMD_NO_AUTH, + HNS3_ROH_CMD_NOT_EXIST, + HNS3_ROH_CMD_QUEUE_FULL, + HNS3_ROH_CMD_NEXT_ERR, + HNS3_ROH_CMD_NOT_EXEC, + HNS3_ROH_CMD_PARA_ERR, + HNS3_ROH_CMD_RESULT_ERR, + HNS3_ROH_CMD_EXEC_TIMEOUT +}; + +struct hns3_roh_set_eid_info { + __le32 base_eid; + __le32 num_eid; + u8 rsv[16]; +}; + +struct hns3_roh_get_guid_info { + u8 guid[16]; + u8 rsv[8]; +}; + +static inline void hns3_roh_mbx_ring_ptr_move_crq(struct hns3_roh_cmdq_ring *crq) +{ + crq->next_to_use = (crq->next_to_use + 1) % crq->desc_num; +} + +int hns3_roh_cmdq_init(struct hns3_roh_device *hroh_dev); +void hns3_roh_cmdq_exit(struct hns3_roh_device *hroh_dev); +int hns3_roh_cmdq_send(struct hns3_roh_device *hroh_dev, + struct hns3_roh_desc *desc, int num); +void hns3_roh_cmdq_setup_basic_desc(struct hns3_roh_desc *desc, + enum hns3_roh_opcode_type opcode, bool is_read); + +#endif /* __HNS3_ROH_CMDQ_H__ */ diff --git a/drivers/roh/hw/hns3/hns3_common.h b/drivers/roh/hw/hns3/hns3_common.h new file mode 100644 index 0000000000000000000000000000000000000000..5109b3aefb9781915142f0b63dc4c551c3e05372 --- /dev/null +++ b/drivers/roh/hw/hns3/hns3_common.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +// Copyright (c) 2022 Hisilicon Limited. +#ifndef __HNS3_ROH_COMMON_H__ +#define __HNS3_ROH_COMMON_H__ + +#include "core.h" +#include "hnae3.h" + +#define HNS3_ROH_VERSION "1.0" + +#define HNS3_ROH_NAME "roh" + +#define HNS3_ROH_DESC_DATA_LEN 6 + +struct hns3_roh_desc { + __le16 opcode; + +#define HNS3_ROH_CMDQ_RX_INVLD_B 0 +#define HNS3_ROH_CMDQ_RX_OUTVLD_B 1 + + __le16 flag; + __le16 retval; + __le16 rsv; + __le32 data[HNS3_ROH_DESC_DATA_LEN]; +}; + +struct hns3_roh_cmdq_ring { + dma_addr_t desc_dma_addr; + struct hns3_roh_desc *desc; + u32 head; + u32 tail; + + u16 buf_size; + u16 desc_num; + int next_to_use; + int next_to_clean; + u8 flag; + spinlock_t lock; /* CMDq lock */ +}; + +struct hns3_roh_cmdq { + struct hns3_roh_cmdq_ring csq; + struct hns3_roh_cmdq_ring crq; + u16 tx_timeout; + u16 last_status; +}; + +struct hns3_roh_priv { + struct hnae3_handle *handle; + struct hns3_roh_cmdq cmdq; + unsigned long state; +}; + +struct hns3_roh_device { + struct roh_device roh_dev; + struct pci_dev *pdev; + struct device *dev; + bool active; + struct net_device *netdev; + + u8 __iomem *reg_base; + const struct hns3_roh_hw *hw; + struct hns3_roh_priv *priv; +}; + +struct hns3_roh_hw { + int (*cmdq_init)(struct hns3_roh_device *hroh_dev); + void (*cmdq_exit)(struct hns3_roh_device *hroh_dev); +}; + +static inline struct hns3_roh_device *to_hroh_dev(struct roh_device *rohdev) +{ + return container_of(rohdev, struct hns3_roh_device, roh_dev); +} + +#define hns3_roh_set_field(origin, mask, shift, val) \ + do { \ + (origin) &= (~(mask)); \ + (origin) |= ((val) << (shift)) & (mask); \ + } while (0) +#define hns3_roh_get_field(origin, mask, shift) (((origin) & (mask)) >> (shift)) + +#define hns3_roh_set_bit(origin, shift, val) \ + hns3_roh_set_field(origin, 0x1 << (shift), shift, val) +#define hns3_roh_get_bit(origin, shift) \ + hns3_roh_get_field(origin, 0x1 << (shift), shift) + +#endif diff --git a/drivers/roh/hw/hns3/hns3_main.c b/drivers/roh/hw/hns3/hns3_main.c new file mode 100644 index 0000000000000000000000000000000000000000..85ff9b15bd4bd76437fd097d1a10d59cb3b29a1f --- /dev/null +++ b/drivers/roh/hw/hns3/hns3_main.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2022 Hisilicon Limited. + +#include +#include +#include + +#include "core.h" +#include "hnae3.h" +#include "hns3_common.h" +#include "hns3_cmdq.h" + +static const struct pci_device_id hns3_roh_pci_tbl[] = { + { PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_ROH), 0 }, + { PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_ROH), 0 }, + { PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), 0 }, + { + 0, + } +}; +MODULE_DEVICE_TABLE(pci, hns3_roh_pci_tbl); + +static void hns3_roh_unregister_device(struct hns3_roh_device *hroh_dev) +{ + hroh_dev->active = false; + roh_unregister_device(&hroh_dev->roh_dev); +} + +static int hns3_roh_register_device(struct hns3_roh_device *hroh_dev) +{ + struct roh_device *rohdev = &hroh_dev->roh_dev; + struct device *dev = hroh_dev->dev; + int ret; + + if (!strlen(rohdev->name)) + strlcpy(rohdev->name, "hns3_%d", ROH_DEVICE_NAME_MAX); + + rohdev->owner = THIS_MODULE; + rohdev->dev.parent = dev; + rohdev->netdev = hroh_dev->netdev; + + ret = roh_register_device(rohdev); + if (ret) { + dev_err(dev, "failed to register roh device, ret = %d\n", ret); + return ret; + } + + hroh_dev->active = true; + + return 0; +} + +static int hns3_roh_init_hw(struct hns3_roh_device *hroh_dev) +{ + struct device *dev = hroh_dev->dev; + int ret; + + ret = hroh_dev->hw->cmdq_init(hroh_dev); + if (ret) { + dev_err(dev, "failed to init cmdq, ret = %d\n", ret); + return ret; + } + + return 0; +} + +static void hns3_roh_uninit_hw(struct hns3_roh_device *hroh_dev) +{ + hroh_dev->hw->cmdq_exit(hroh_dev); +} + +static int hns3_roh_init(struct hns3_roh_device *hroh_dev) +{ + struct device *dev = hroh_dev->dev; + int ret; + + ret = hns3_roh_init_hw(hroh_dev); + if (ret) { + dev_err(dev, "failed to init hw resources, ret = %d\n", ret); + return ret; + } + + ret = hns3_roh_register_device(hroh_dev); + if (ret) { + dev_err(dev, "failed to register roh device, ret = %d\n", ret); + goto err_uninit_hw; + } + + dev_info(dev, "%s driver init success.\n", HNS3_ROH_NAME); + + return 0; + +err_uninit_hw: + hns3_roh_uninit_hw(hroh_dev); + return ret; +} + +static void hns3_roh_exit(struct hns3_roh_device *hroh_dev) +{ + hns3_roh_unregister_device(hroh_dev); + + hns3_roh_uninit_hw(hroh_dev); + + dev_info(&hroh_dev->pdev->dev, + "%s driver uninit success.\n", HNS3_ROH_NAME); +} + +static const struct hns3_roh_hw hns3_roh_hw = { + .cmdq_init = hns3_roh_cmdq_init, + .cmdq_exit = hns3_roh_cmdq_exit, +}; + +static void hns3_roh_get_cfg_from_frame(struct hns3_roh_device *hroh_dev, + struct hnae3_handle *handle) +{ + hroh_dev->pdev = handle->pdev; + hroh_dev->dev = &handle->pdev->dev; + + hroh_dev->netdev = handle->rohinfo.netdev; + hroh_dev->reg_base = handle->rohinfo.roh_io_base; + + hroh_dev->hw = &hns3_roh_hw; + + hroh_dev->priv->handle = handle; +} + +static int __hns3_roh_init_instance(struct hnae3_handle *handle) +{ + struct hns3_roh_device *hroh_dev; + int ret; + + hroh_dev = (struct hns3_roh_device *)roh_alloc_device(sizeof(*hroh_dev)); + if (!hroh_dev) { + dev_err(&handle->pdev->dev, "failed to alloc roh dev.\n"); + return -ENOMEM; + } + + hroh_dev->priv = kzalloc(sizeof(*hroh_dev->priv), GFP_KERNEL); + if (!hroh_dev->priv) { + ret = -ENOMEM; + goto err_roh_alloc_device; + } + + hns3_roh_get_cfg_from_frame(hroh_dev, handle); + + ret = hns3_roh_init(hroh_dev); + if (ret) { + dev_err(hroh_dev->dev, "failed to init roh, ret = %d\n", ret); + goto err_kzalloc; + } + handle->priv = hroh_dev; + + return 0; + +err_kzalloc: + kfree(hroh_dev->priv); +err_roh_alloc_device: + roh_dealloc_device(&hroh_dev->roh_dev); + return ret; +} + +static void __hns3_roh_uninit_instance(struct hnae3_handle *handle) +{ + struct hns3_roh_device *hroh_dev = (struct hns3_roh_device *)handle->priv; + + if (!hroh_dev) + return; + + handle->priv = NULL; + + hns3_roh_exit(hroh_dev); + + kfree(hroh_dev->priv); + + roh_dealloc_device(&hroh_dev->roh_dev); +} + +static int hns3_roh_init_instance(struct hnae3_handle *handle) +{ + struct device *dev = &handle->pdev->dev; + const struct pci_device_id *id; + int ret; + + id = pci_match_id(hns3_roh_pci_tbl, handle->pdev); + if (!id) { + dev_err(dev, "failed to match pci id.\n"); + return 0; + } + + if (id->driver_data) { + dev_err(dev, "not support vf.\n"); + return -EINVAL; + } + + ret = __hns3_roh_init_instance(handle); + if (ret) { + dev_err(dev, "failed to init instance, ret = %d\n", ret); + return ret; + } + + return 0; +} + +static void hns3_roh_uninit_instance(struct hnae3_handle *handle, bool reset) +{ + __hns3_roh_uninit_instance(handle); +} + +static const struct hnae3_client_ops hns3_roh_ops = { + .init_instance = hns3_roh_init_instance, + .uninit_instance = hns3_roh_uninit_instance, +}; + +static struct hnae3_client hns3_roh_client = { + .name = "hns3_roh_hw", + .type = HNAE3_CLIENT_ROH, + .ops = &hns3_roh_ops, +}; + +static int __init hns3_roh_module_init(void) +{ + return hnae3_register_client(&hns3_roh_client); +} + +static void __exit hns3_roh_module_cleanup(void) +{ + hnae3_unregister_client(&hns3_roh_client); +} + +module_init(hns3_roh_module_init); +module_exit(hns3_roh_module_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_VERSION(HNS3_ROH_VERSION); +MODULE_AUTHOR("Huawei Tech. Co., Ltd."); +MODULE_DESCRIPTION("Hisilicon Hip09 Family ROH Driver"); diff --git a/drivers/roh/hw/hns3/hns3_reg.h b/drivers/roh/hw/hns3/hns3_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..072c21ef190962a85bc4e59992aeed797b134f2a --- /dev/null +++ b/drivers/roh/hw/hns3/hns3_reg.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +// Copyright (c) 2020-2022 Hisilicon Limited. +#ifndef __HNS3_ROH_REG_H__ +#define __HNS3_ROH_REG_H__ + +/* CMDq Reg */ +#define HNS3_ROH_CMDQ_BASE 0x26000 +#define HNS3_ROH_TX_CMDQ_BASEADDR_L_REG (HNS3_ROH_CMDQ_BASE + 0x0) +#define HNS3_ROH_TX_CMDQ_BASEADDR_H_REG (HNS3_ROH_CMDQ_BASE + 0x4) +#define HNS3_ROH_TX_CMDQ_DEPTH_REG (HNS3_ROH_CMDQ_BASE + 0x8) +#define HNS3_ROH_TX_CMDQ_TAIL_REG (HNS3_ROH_CMDQ_BASE + 0x10) +#define HNS3_ROH_TX_CMDQ_HEAD_REG (HNS3_ROH_CMDQ_BASE + 0x14) + +#define HNS3_ROH_RX_CMDQ_BASEADDR_L_REG (HNS3_ROH_CMDQ_BASE + 0x18) +#define HNS3_ROH_RX_CMDQ_BASEADDR_H_REG (HNS3_ROH_CMDQ_BASE + 0x1c) +#define HNS3_ROH_RX_CMDQ_DEPTH_REG (HNS3_ROH_CMDQ_BASE + 0x20) +#define HNS3_ROH_RX_CMDQ_TAIL_REG (HNS3_ROH_CMDQ_BASE + 0x24) +#define HNS3_ROH_RX_CMDQ_HEAD_REG (HNS3_ROH_CMDQ_BASE + 0x28) + +/* Vector0 interrupt CMDQ event source register(RW) */ +#define HNS3_ROH_VECTOR0_CMDQ_SRC_REG (HNS3_ROH_CMDQ_BASE + 0x110) +#define HNS3_ROH_VECTOR0_RX_CMDQ_INT_B 1 + +#define HNS3_ROH_VECTOR0_INT_CTRL_REG 0x20404 + +#define hns3_roh_write(dev, reg, val) writel((val), (dev)->reg_base + (reg)) +#define hns3_roh_read(dev, reg) readl((dev)->reg_base + (reg)) +#define hns3_roh_raw_write(value, addr) \ + __raw_writel((__force u32)cpu_to_le32(value), (addr)) + +#endif /* __HNS3_ROH_REG_H__ */