From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id D96A45F1B for ; Thu, 28 Feb 2019 08:15:14 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Feb 2019 23:15:14 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,422,1544515200"; d="scan'208";a="142299806" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by orsmga001.jf.intel.com with ESMTP; 27 Feb 2019 23:15:11 -0800 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com Date: Thu, 28 Feb 2019 15:13:12 +0800 Message-Id: <1551338000-120348-4-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v1 03/11] drivers/raw/ifpga_rawdev: add OPAE share code for IPN3KE X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 07:15:16 -0000 Add OPAE share code for Intel FPGA Acceleration NIC IPN3KE. Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/Makefile | 7 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 69 ++- drivers/raw/ifpga_rawdev/base/ifpga_api.h | 1 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 86 +++- drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 342 +++++-------- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 170 +++++-- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 62 ++- drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 373 ++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 2 +- drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 21 +- drivers/raw/ifpga_rawdev/base/ifpga_port.c | 21 + drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c | 89 ++++ drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h | 14 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 189 ++++++- drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 46 +- drivers/raw/ifpga_rawdev/base/opae_i2c.c | 490 +++++++++++++++++++ drivers/raw/ifpga_rawdev/base/opae_i2c.h | 127 +++++ drivers/raw/ifpga_rawdev/base/opae_intel_max10.c | 106 ++++ drivers/raw/ifpga_rawdev/base/opae_intel_max10.h | 36 ++ drivers/raw/ifpga_rawdev/base/opae_mdio.c | 542 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/opae_mdio.h | 90 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 11 +- drivers/raw/ifpga_rawdev/base/opae_phy_group.c | 88 ++++ drivers/raw/ifpga_rawdev/base/opae_phy_group.h | 53 ++ drivers/raw/ifpga_rawdev/base/opae_spi.c | 260 ++++++++++ drivers/raw/ifpga_rawdev/base/opae_spi.h | 120 +++++ .../raw/ifpga_rawdev/base/opae_spi_transaction.c | 438 +++++++++++++++++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 1 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 10 + 29 files changed, 3549 insertions(+), 315 deletions(-) create mode 100644 drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_i2c.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_i2c.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_intel_max10.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_intel_max10.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_mdio.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_mdio.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_phy_group.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_phy_group.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_spi.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_spi.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile index d79da72..c77e751 100644 --- a/drivers/raw/ifpga_rawdev/base/Makefile +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -22,5 +22,12 @@ SRCS-y += opae_hw_api.c SRCS-y += opae_ifpga_hw_api.c SRCS-y += opae_debug.c SRCS-y += ifpga_fme_pr.c +SRCS-y += opae_spi.c +SRCS-y += opae_spi_transaction.c +SRCS-y += opae_mdio.c +SRCS-y += opae_i2c.c +SRCS-y += opae_at24_eeprom.c +SRCS-y += opae_phy_group.c +SRCS-y += opae_intel_max10.c SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c index 540e171..0fd8de1 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_api.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -170,7 +170,6 @@ struct opae_accelerator_ops ifpga_acc_ops = { }; /* Bridge APIs */ - static int ifpga_br_reset(struct opae_bridge *br) { struct ifpga_port_hw *port = br->data; @@ -196,13 +195,79 @@ struct opae_manager_ops ifpga_mgr_ops = { .flash = ifpga_mgr_flash, }; +static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset, + void *buf, int size) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_read_mac_rom(fme, offset, buf, size); +} + +static int ifpga_mgr_write_mac_rom(struct opae_manager *mgr, int offset, + void *buf, int size) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_write_mac_rom(fme, offset, buf, size); +} + +static int ifpga_mgr_read_phy_reg(struct opae_manager *mgr, int phy_group, + u8 entry, u16 reg, u32 *value) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_read_phy_reg(fme, phy_group, entry, reg, value); +} + +static int ifpga_mgr_write_phy_reg(struct opae_manager *mgr, int phy_group, + u8 entry, u16 reg, u32 value) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_write_phy_reg(fme, phy_group, entry, reg, value); +} + +static int ifpga_mgr_get_retimer_info(struct opae_manager *mgr, + struct opae_retimer_info *info) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_get_retimer_info(fme, info); +} + +static int ifpga_mgr_set_retimer_speed(struct opae_manager *mgr, int speed) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_set_retimer_speed(fme, speed); +} + +static int ifpga_mgr_get_retimer_status(struct opae_manager *mgr, int port, + struct opae_retimer_status *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_get_retimer_status(fme, port, status); +} + +/* Network APIs in FME */ +struct opae_manager_networking_ops ifpga_mgr_network_ops = { + .read_mac_rom = ifpga_mgr_read_mac_rom, + .write_mac_rom = ifpga_mgr_write_mac_rom, + .read_phy_reg = ifpga_mgr_read_phy_reg, + .write_phy_reg = ifpga_mgr_write_phy_reg, + .get_retimer_info = ifpga_mgr_get_retimer_info, + .set_retimer_speed = ifpga_mgr_set_retimer_speed, + .get_retimer_status = ifpga_mgr_get_retimer_status, +}; + /* Adapter APIs */ static int ifpga_adapter_enumerate(struct opae_adapter *adapter) { struct ifpga_hw *hw = malloc(sizeof(*hw)); if (hw) { - memset(hw, 0, sizeof(*hw)); + opae_memset(hw, 0, sizeof(*hw)); hw->pci_data = adapter->data; hw->adapter = adapter; if (ifpga_bus_enumerate(hw)) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h index dae7ca1..4a24769 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_api.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -12,6 +12,7 @@ extern struct opae_manager_ops ifpga_mgr_ops; extern struct opae_bridge_ops ifpga_br_ops; extern struct opae_accelerator_ops ifpga_acc_ops; +extern struct opae_manager_networking_ops ifpga_mgr_network_ops; /* common APIs */ int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h index aa02527..cbd97fe 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -15,9 +15,13 @@ #define FME_FEATURE_GLOBAL_IPERF "fme_iperf" #define FME_FEATURE_GLOBAL_ERR "fme_error" #define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_EMIF_MGMT "fme_emif" #define FME_FEATURE_HSSI_ETH "fme_hssi" #define FME_FEATURE_GLOBAL_DPERF "fme_dperf" #define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" +#define FME_FEATURE_MAX10_SPI "fme_max10_spi" +#define FME_FEATURE_I2C_MASTER "fme_i2c_master" +#define FME_FEATURE_PHY_GROUP "fme_phy_group" #define PORT_FEATURE_HEADER "port_hdr" #define PORT_FEATURE_UAFU "port_uafu" @@ -42,6 +46,9 @@ #define FME_HSSI_ETH_REVISION 0 #define FME_GLOBAL_DPERF_REVISION 0 #define FME_QSPI_REVISION 0 +#define FME_MAX10_SPI 0 +#define FME_I2C_MASTER 0 +#define FME_PHY_GROUP 0 #define PORT_HEADER_REVISION 0 /* UAFU's header info depends on the downloaded GBS */ @@ -59,7 +66,8 @@ #define FEATURE_FIU_ID_FME 0x0 #define FEATURE_FIU_ID_PORT 0x1 -#define FEATURE_ID_HEADER 0x0 +/* Reserved 0xfe for Header, 0xff for AFU*/ +#define FEATURE_ID_FIU_HEADER 0xfe #define FEATURE_ID_AFU 0xff enum fpga_id_type { @@ -68,31 +76,26 @@ enum fpga_id_type { FPGA_ID_MAX, }; -enum fme_feature_id { - FME_FEATURE_ID_HEADER = 0x0, - - FME_FEATURE_ID_THERMAL_MGMT = 0x1, - FME_FEATURE_ID_POWER_MGMT = 0x2, - FME_FEATURE_ID_GLOBAL_IPERF = 0x3, - FME_FEATURE_ID_GLOBAL_ERR = 0x4, - FME_FEATURE_ID_PR_MGMT = 0x5, - FME_FEATURE_ID_HSSI_ETH = 0x6, - FME_FEATURE_ID_GLOBAL_DPERF = 0x7, - FME_FEATURE_ID_QSPI_FLASH = 0x8, - - /* one for fme header. */ - FME_FEATURE_ID_MAX = 0x9, -}; - -enum port_feature_id { - PORT_FEATURE_ID_HEADER = 0x0, - PORT_FEATURE_ID_ERROR = 0x1, - PORT_FEATURE_ID_UMSG = 0x2, - PORT_FEATURE_ID_UINT = 0x3, - PORT_FEATURE_ID_STP = 0x4, - PORT_FEATURE_ID_UAFU = 0x5, - PORT_FEATURE_ID_MAX = 0x6, -}; +#define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER +#define FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define FME_FEATURE_ID_POWER_MGMT 0x2 +#define FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define FME_FEATURE_ID_PR_MGMT 0x5 +#define FME_FEATURE_ID_HSSI_ETH 0x6 +#define FME_FEATURE_ID_GLOBAL_DPERF 0x7 +#define FME_FEATURE_ID_QSPI_FLASH 0x8 +#define FME_FEATURE_ID_EMIF_MGMT 0x9 +#define FME_FEATURE_ID_MAX10_SPI 0xe +#define FME_FEATURE_ID_I2C_MASTER 0xf +#define FME_FEATURE_ID_PHY_GROUP 0x10 + +#define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER +#define PORT_FEATURE_ID_ERROR 0x10 +#define PORT_FEATURE_ID_UMSG 0x12 +#define PORT_FEATURE_ID_UINT 0x13 +#define PORT_FEATURE_ID_STP 0x14 +#define PORT_FEATURE_ID_UAFU FEATURE_ID_AFU /* * All headers and structures must be byte-packed to match the spec. @@ -1303,6 +1306,37 @@ struct feature_fme_hssi { struct feature_fme_hssi_eth_stat hssi_status; }; +/*FME SPI Master for VC*/ +struct feature_fme_spi { + struct feature_header header; + u64 reg[4]; +}; + +/* FME I2C Master */ +struct feature_fme_i2c { + struct feature_header header; + u64 reg[4]; +}; + +struct feature_fme_phy_group_info { + union { + u64 info; + struct { + u8 group_index:8; + u8 number:8; + u8 speed:8; + u8 direction:1; + u64 rsvd:39; + }; + }; +}; + +/* FME PHY Group */ +struct feature_fme_phy_group { + struct feature_header header; + struct feature_fme_phy_group_info phy_info; +}; + #define PORT_ERR_MASK 0xfff0703ff001f struct feature_port_err_key { union { diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c index 848e518..0a206cb 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -28,121 +28,24 @@ struct build_feature_devs_info { struct ifpga_hw *hw; }; -struct feature_info { - const char *name; - u32 resource_size; - int feature_index; - int revision_id; - unsigned int vec_start; - unsigned int vec_cnt; - - struct feature_ops *ops; -}; +static int feature_revision(void __iomem *start) +{ + struct feature_header header; -/* indexed by fme feature IDs which are defined in 'enum fme_feature_id'. */ -static struct feature_info fme_features[] = { - { - .name = FME_FEATURE_HEADER, - .resource_size = sizeof(struct feature_fme_header), - .feature_index = FME_FEATURE_ID_HEADER, - .revision_id = FME_HEADER_REVISION, - .ops = &fme_hdr_ops, - }, - { - .name = FME_FEATURE_THERMAL_MGMT, - .resource_size = sizeof(struct feature_fme_thermal), - .feature_index = FME_FEATURE_ID_THERMAL_MGMT, - .revision_id = FME_THERMAL_MGMT_REVISION, - .ops = &fme_thermal_mgmt_ops, - }, - { - .name = FME_FEATURE_POWER_MGMT, - .resource_size = sizeof(struct feature_fme_power), - .feature_index = FME_FEATURE_ID_POWER_MGMT, - .revision_id = FME_POWER_MGMT_REVISION, - .ops = &fme_power_mgmt_ops, - }, - { - .name = FME_FEATURE_GLOBAL_IPERF, - .resource_size = sizeof(struct feature_fme_iperf), - .feature_index = FME_FEATURE_ID_GLOBAL_IPERF, - .revision_id = FME_GLOBAL_IPERF_REVISION, - .ops = &fme_global_iperf_ops, - }, - { - .name = FME_FEATURE_GLOBAL_ERR, - .resource_size = sizeof(struct feature_fme_err), - .feature_index = FME_FEATURE_ID_GLOBAL_ERR, - .revision_id = FME_GLOBAL_ERR_REVISION, - .ops = &fme_global_err_ops, - }, - { - .name = FME_FEATURE_PR_MGMT, - .resource_size = sizeof(struct feature_fme_pr), - .feature_index = FME_FEATURE_ID_PR_MGMT, - .revision_id = FME_PR_MGMT_REVISION, - .ops = &fme_pr_mgmt_ops, - }, - { - .name = FME_FEATURE_HSSI_ETH, - .resource_size = sizeof(struct feature_fme_hssi), - .feature_index = FME_FEATURE_ID_HSSI_ETH, - .revision_id = FME_HSSI_ETH_REVISION - }, - { - .name = FME_FEATURE_GLOBAL_DPERF, - .resource_size = sizeof(struct feature_fme_dperf), - .feature_index = FME_FEATURE_ID_GLOBAL_DPERF, - .revision_id = FME_GLOBAL_DPERF_REVISION, - .ops = &fme_global_dperf_ops, - } -}; + header.csr = readq(start); -static struct feature_info port_features[] = { - { - .name = PORT_FEATURE_HEADER, - .resource_size = sizeof(struct feature_port_header), - .feature_index = PORT_FEATURE_ID_HEADER, - .revision_id = PORT_HEADER_REVISION, - .ops = &ifpga_rawdev_port_hdr_ops, - }, - { - .name = PORT_FEATURE_ERR, - .resource_size = sizeof(struct feature_port_error), - .feature_index = PORT_FEATURE_ID_ERROR, - .revision_id = PORT_ERR_REVISION, - .ops = &ifpga_rawdev_port_error_ops, - }, - { - .name = PORT_FEATURE_UMSG, - .resource_size = sizeof(struct feature_port_umsg), - .feature_index = PORT_FEATURE_ID_UMSG, - .revision_id = PORT_UMSG_REVISION, - }, - { - .name = PORT_FEATURE_UINT, - .resource_size = sizeof(struct feature_port_uint), - .feature_index = PORT_FEATURE_ID_UINT, - .revision_id = PORT_UINT_REVISION, - .ops = &ifpga_rawdev_port_uint_ops, - }, - { - .name = PORT_FEATURE_STP, - .resource_size = PORT_FEATURE_STP_REGION_SIZE, - .feature_index = PORT_FEATURE_ID_STP, - .revision_id = PORT_STP_REVISION, - .ops = &ifpga_rawdev_port_stp_ops, - }, - { - .name = PORT_FEATURE_UAFU, - /* UAFU feature size should be read from PORT_CAP.MMIOSIZE. - * Will set uafu feature size while parse port device. - */ - .resource_size = 0, - .feature_index = PORT_FEATURE_ID_UAFU, - .revision_id = PORT_UAFU_REVISION - }, -}; + return header.revision; +} + +static u32 feature_size(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + /*the size of private feature is 4KB aligned*/ + return header.next_header_offset ? header.next_header_offset:4096; +} static u64 feature_id(void __iomem *start) { @@ -152,7 +55,7 @@ static u64 feature_id(void __iomem *start) switch (header.type) { case FEATURE_TYPE_FIU: - return FEATURE_ID_HEADER; + return FEATURE_ID_FIU_HEADER; case FEATURE_TYPE_PRIVATE: return header.id; case FEATURE_TYPE_AFU: @@ -165,37 +68,35 @@ static u64 feature_id(void __iomem *start) static int build_info_add_sub_feature(struct build_feature_devs_info *binfo, - struct feature_info *finfo, void __iomem *start) + void __iomem *start, u64 fid, unsigned int size, + unsigned int vec_start, + unsigned int vec_cnt) { struct ifpga_hw *hw = binfo->hw; struct feature *feature = NULL; - int feature_idx = finfo->feature_index; - unsigned int vec_start = finfo->vec_start; - unsigned int vec_cnt = finfo->vec_cnt; struct feature_irq_ctx *ctx = NULL; int port_id, ret = 0; unsigned int i; - if (binfo->current_type == FME_ID) { - feature = &hw->fme.sub_feature[feature_idx]; - feature->parent = &hw->fme; - } else if (binfo->current_type == PORT_ID) { - port_id = binfo->current_port_id; - feature = &hw->port[port_id].sub_feature[feature_idx]; - feature->parent = &hw->port[port_id]; - } else { - return -EFAULT; - } + fid = fid?fid:feature_id(start); + size = size?size:feature_size(start); + + feature = opae_malloc(sizeof(struct feature)); + if (!feature) + return -ENOMEM; feature->state = IFPGA_FEATURE_ATTACHED; feature->addr = start; - feature->id = feature_id(start); - feature->size = finfo->resource_size; - feature->name = finfo->name; - feature->revision = finfo->revision_id; - feature->ops = finfo->ops; + feature->id = fid; + feature->size = size; + feature->revision = feature_revision(start); feature->phys_addr = binfo->phys_addr + ((u8 *)start - (u8 *)binfo->ioaddr); + feature->vec_start = vec_start; + feature->vec_cnt = vec_cnt; + + dev_debug(binfo, "%s: id=0x%lx, phys_addr=0x%lx, size=%d\n", + __func__, feature->id, feature->phys_addr, size); if (vec_cnt) { if (vec_start + vec_cnt <= vec_start) @@ -215,22 +116,32 @@ static u64 feature_id(void __iomem *start) feature->ctx_num = vec_cnt; feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + if (binfo->current_type == FME_ID) { + feature->parent = &hw->fme; + feature->type = FEATURE_FME_TYPE; + feature->name = get_fme_feature_name(fid); + TAILQ_INSERT_TAIL(&hw->fme.feature_list, feature, next); + } else if (binfo->current_type == PORT_ID) { + port_id = binfo->current_port_id; + feature->parent = &hw->port[port_id]; + feature->type = FEATURE_PORT_TYPE; + feature->name = get_port_feature_name(fid); + TAILQ_INSERT_TAIL(&hw->port[port_id].feature_list, + feature, next); + } else { + return -EFAULT; + } return ret; } static int create_feature_instance(struct build_feature_devs_info *binfo, - void __iomem *start, struct feature_info *finfo) + void __iomem *start, u64 fid, + unsigned int size, unsigned int vec_start, + unsigned int vec_cnt) { - struct feature_header *hdr = start; - - if (finfo->revision_id != SKIP_REVISION_CHECK && - hdr->revision > finfo->revision_id) { - dev_err(binfo, "feature %s revision :default:%x, now at:%x, mis-match.\n", - finfo->name, finfo->revision_id, hdr->revision); - } - - return build_info_add_sub_feature(binfo, finfo, start); + return build_info_add_sub_feature(binfo, start, fid, size, vec_start, + vec_cnt); } /* @@ -249,31 +160,31 @@ static bool feature_is_UAFU(struct build_feature_devs_info *binfo) static int parse_feature_port_uafu(struct build_feature_devs_info *binfo, struct feature_header *hdr) { - enum port_feature_id id = PORT_FEATURE_ID_UAFU; + u64 id = PORT_FEATURE_ID_UAFU; struct ifpga_afu_info *info; void *start = (void *)hdr; + struct feature_port_header *port_hdr = binfo->ioaddr; + struct feature_port_capability capability; int ret; + int size; - if (port_features[id].resource_size) { - ret = create_feature_instance(binfo, hdr, &port_features[id]); - } else { - dev_err(binfo, "the uafu feature header is mis-configured.\n"); - ret = -EINVAL; - } + capability.csr = readq(&port_hdr->capability); + + size = capability.mmio_size << 10; + ret = create_feature_instance(binfo, hdr, id, size, 0, 0); if (ret) return ret; /* FIXME: need to figure out a better name */ - info = malloc(sizeof(*info)); + info = opae_malloc(sizeof(*info)); if (!info) return -ENOMEM; info->region[0].addr = start; info->region[0].phys_addr = binfo->phys_addr + (uint8_t *)start - (uint8_t *)binfo->ioaddr; - info->region[0].len = port_features[id].resource_size; - port_features[id].resource_size = 0; + info->region[0].len = size; info->num_regions = 1; binfo->acc_info = info; @@ -320,6 +231,8 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) struct opae_manager *mgr; struct opae_bridge *br; struct opae_accelerator *acc; + struct ifpga_port_hw *port; + struct feature *feature; if (!binfo->fiu) return 0; @@ -337,7 +250,11 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) br->id = binfo->current_port_id; /* update irq info */ - info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + port = &hw->port[binfo->current_port_id]; + feature = get_feature_by_id(&port->feature_list, + PORT_FEATURE_ID_UINT); + if (feature) + info->num_irqs = feature->vec_cnt; acc = opae_accelerator_alloc(hw->adapter->name, &ifpga_acc_ops, info); @@ -353,7 +270,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) } else if (binfo->current_type == FME_ID) { mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, - binfo->fiu); + &ifpga_mgr_network_ops, binfo->fiu); if (!mgr) return -ENOMEM; @@ -402,10 +319,10 @@ static int parse_feature_fme(struct build_feature_devs_info *binfo, /* Update FME states */ fme->state = IFPGA_FME_IMPLEMENTED; fme->parent = hw; + TAILQ_INIT(&fme->feature_list); spinlock_init(&fme->lock); - return create_feature_instance(binfo, start, - &fme_features[FME_FEATURE_ID_HEADER]); + return create_feature_instance(binfo, start, 0, 0, 0, 0); } static int parse_feature_port(struct build_feature_devs_info *binfo, @@ -433,29 +350,19 @@ static int parse_feature_port(struct build_feature_devs_info *binfo, port->parent = hw; port->state = IFPGA_PORT_ATTACHED; spinlock_init(&port->lock); + TAILQ_INIT(&port->feature_list); - return create_feature_instance(binfo, start, - &port_features[PORT_FEATURE_ID_HEADER]); + return create_feature_instance(binfo, start, 0, 0, 0, 0); } static void enable_port_uafu(struct build_feature_devs_info *binfo, void __iomem *start) { - enum port_feature_id id = PORT_FEATURE_ID_UAFU; - struct feature_port_header *port_hdr; - struct feature_port_capability capability; struct ifpga_port_hw *port = &binfo->hw->port[binfo->current_port_id]; - port_hdr = (struct feature_port_header *)start; - capability.csr = readq(&port_hdr->capability); - port_features[id].resource_size = (capability.mmio_size << 10); - - /* - * From spec, to Enable UAFU, we should reset related port, - * or the whole mmio space in this UAFU will be invalid - */ - if (port_features[id].resource_size) - fpga_port_reset(port); + UNUSED(start); + + fpga_port_reset(port); } static int parse_feature_fiu(struct build_feature_devs_info *binfo, @@ -505,44 +412,45 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo, } static void parse_feature_irqs(struct build_feature_devs_info *binfo, - void __iomem *start, struct feature_info *finfo) + void __iomem *start, unsigned int *vec_start, + unsigned int *vec_cnt) { - finfo->vec_start = 0; - finfo->vec_cnt = 0; - UNUSED(binfo); + u64 id; + + id = feature_id(start); - if (!strcmp(finfo->name, PORT_FEATURE_UINT)) { + if (id == PORT_FEATURE_ID_UINT) { struct feature_port_uint *port_uint = start; struct feature_port_uint_cap uint_cap; uint_cap.csr = readq(&port_uint->capability); if (uint_cap.intr_num) { - finfo->vec_start = uint_cap.first_vec_num; - finfo->vec_cnt = uint_cap.intr_num; + *vec_start = uint_cap.first_vec_num; + *vec_cnt = uint_cap.intr_num; } else { dev_debug(binfo, "UAFU doesn't support interrupt\n"); } - } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + } else if (id == PORT_FEATURE_ID_ERROR) { struct feature_port_error *port_err = start; struct feature_port_err_capability port_err_cap; port_err_cap.csr = readq(&port_err->error_capability); if (port_err_cap.support_intr) { - finfo->vec_start = port_err_cap.intr_vector_num; - finfo->vec_cnt = 1; + *vec_start = port_err_cap.intr_vector_num; + *vec_cnt = 1; } else { dev_debug(&binfo, "Port error doesn't support interrupt\n"); } - } else if (!strcmp(finfo->name, FME_FEATURE_GLOBAL_ERR)) { + } else if (id == FME_FEATURE_ID_GLOBAL_ERR) { struct feature_fme_err *fme_err = start; struct feature_fme_error_capability fme_err_cap; fme_err_cap.csr = readq(&fme_err->fme_err_capability); if (fme_err_cap.support_intr) { - finfo->vec_start = fme_err_cap.intr_vector_num; - finfo->vec_cnt = 1; + *vec_start = fme_err_cap.intr_vector_num; + *vec_cnt = 1; } else { dev_debug(&binfo, "FME error doesn't support interrupt\n"); } @@ -552,43 +460,23 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo, static int parse_feature_fme_private(struct build_feature_devs_info *binfo, struct feature_header *hdr) { - struct feature_header header; - - header.csr = readq(hdr); - - if (header.id >= ARRAY_SIZE(fme_features)) { - dev_err(binfo, "FME feature id %x is not supported yet.\n", - header.id); - return 0; - } + unsigned int vec_start = 0; + unsigned int vec_cnt = 0; - parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + parse_feature_irqs(binfo, hdr, &vec_start, &vec_cnt); - return create_feature_instance(binfo, hdr, &fme_features[header.id]); + return create_feature_instance(binfo, hdr, 0, 0, vec_start, vec_cnt); } static int parse_feature_port_private(struct build_feature_devs_info *binfo, struct feature_header *hdr) { - struct feature_header header; - enum port_feature_id id; + unsigned int vec_start = 0; + unsigned int vec_cnt = 0; - header.csr = readq(hdr); - /* - * the region of port feature id is [0x10, 0x13], + 1 to reserve 0 - * which is dedicated for port-hdr. - */ - id = (header.id & 0x000f) + 1; - - if (id >= ARRAY_SIZE(port_features)) { - dev_err(binfo, "Port feature id %x is not supported yet.\n", - header.id); - return 0; - } - - parse_feature_irqs(binfo, hdr, &port_features[id]); + parse_feature_irqs(binfo, hdr, &vec_start, &vec_cnt); - return create_feature_instance(binfo, hdr, &port_features[id]); + return create_feature_instance(binfo, hdr, 0, 0, vec_start, vec_cnt); } static int parse_feature_private(struct build_feature_devs_info *binfo, @@ -651,12 +539,19 @@ static int parse_feature(struct build_feature_devs_info *binfo, } hdr = (struct feature_header *)start; + header.csr = readq(hdr); + + /*debug*/ + dev_debug(binfo, "%s: address=0x%llx, val=0x%lx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\n", + __func__, (unsigned long long)(hdr), header.csr, + header.id, header.next_header_offset, + header.end_of_list, header.type); + ret = parse_feature(binfo, hdr); if (ret) return ret; - header.csr = readq(hdr); - if (!header.next_header_offset) + if (header.end_of_list || !header.next_header_offset) break; } @@ -746,13 +641,12 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw) struct ifpga_fme_hw *fme = &hw->fme; struct ifpga_port_hw *port; struct feature *feature; - int i, j; + int i; dev_info(hw, "found fme_device, is in PF: %s\n", is_ifpga_hw_pf(hw) ? "yes" : "no"); - for (i = 0; i < FME_FEATURE_ID_MAX; i++) { - feature = &fme->sub_feature[i]; + ifpga_for_each_fme_feature(fme, feature) { if (feature->state != IFPGA_FEATURE_ATTACHED) continue; @@ -760,6 +654,7 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw) feature->name, feature->addr, feature->addr + feature->size - 1, (unsigned long)feature->phys_addr); + } for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { @@ -770,8 +665,7 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw) dev_info(hw, "port device: %d\n", port->port_id); - for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { - feature = &port->sub_feature[j]; + ifpga_for_each_port_feature(port, feature) { if (feature->state != IFPGA_FEATURE_ATTACHED) continue; @@ -782,6 +676,7 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw) feature->size - 1, (unsigned long)feature->phys_addr); } + } } @@ -812,10 +707,13 @@ int ifpga_bus_enumerate(struct ifpga_hw *hw) int ifpga_bus_init(struct ifpga_hw *hw) { int i; + struct ifpga_port_hw *port; fme_hw_init(&hw->fme); - for (i = 0; i < MAX_FPGA_PORT_NUM; i++) - port_hw_init(&hw->port[i]); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + port_hw_init(port); + } return 0; } diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c index be7ac9e..88465d6 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -70,6 +70,9 @@ int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) struct feature_port_header *port_hdr; u64 guidl, guidh; + if (!uuid) + return -EINVAL; + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); spinlock_lock(&port->lock); @@ -77,8 +80,8 @@ int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) guidh = readq(&port_hdr->afu_header.guid.b[8]); spinlock_unlock(&port->lock); - memcpy(uuid->b, &guidl, sizeof(u64)); - memcpy(uuid->b + 8, &guidh, sizeof(u64)); + opae_memcpy(uuid->b, &guidl, sizeof(u64)); + opae_memcpy(uuid->b + 8, &guidh, sizeof(u64)); return 0; } @@ -177,77 +180,152 @@ int port_clear_error(struct ifpga_port_hw *port) return port_err_clear(port, error.csr); } -void fme_hw_uinit(struct ifpga_fme_hw *fme) +static struct feature_driver fme_feature_drvs[] = { + {FEATURE_DRV(FME_FEATURE_ID_HEADER, FME_FEATURE_HEADER, + &fme_hdr_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_THERMAL_MGMT, FME_FEATURE_THERMAL_MGMT, + &fme_thermal_mgmt_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_POWER_MGMT, FME_FEATURE_POWER_MGMT, + &fme_power_mgmt_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_GLOBAL_ERR, FME_FEATURE_GLOBAL_ERR, + &fme_global_err_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_PR_MGMT, FME_FEATURE_PR_MGMT, + &fme_pr_mgmt_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_GLOBAL_DPERF, FME_FEATURE_GLOBAL_DPERF, + &fme_global_dperf_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_HSSI_ETH, FME_FEATURE_HSSI_ETH, + &fme_hssi_eth_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT, + &fme_emif_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_MAX10_SPI, FME_FEATURE_MAX10_SPI, + &fme_spi_master_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_I2C_MASTER, FME_FEATURE_I2C_MASTER, + &fme_i2c_master_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_PHY_GROUP, FME_FEATURE_PHY_GROUP, + &fme_phy_group_ops),}, + {0, NULL, NULL}, /* end of arrary */ +}; + +static struct feature_driver port_feature_drvs[] = { + {FEATURE_DRV(PORT_FEATURE_ID_HEADER, PORT_FEATURE_HEADER, + &ifpga_rawdev_port_hdr_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_ERROR, PORT_FEATURE_ERR, + &ifpga_rawdev_port_error_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_UINT, PORT_FEATURE_UINT, + &ifpga_rawdev_port_uint_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_STP, PORT_FEATURE_STP, + &ifpga_rawdev_port_stp_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_UAFU, PORT_FEATURE_UAFU, + &ifpga_rawdev_port_afu_ops)}, + {0, NULL, NULL}, /* end of array */ +}; + +const char *get_fme_feature_name(unsigned int id) { - struct feature *feature; - int i; + struct feature_driver *drv = fme_feature_drvs; - if (fme->state != IFPGA_FME_IMPLEMENTED) - return; + while (drv->name) { + if (drv->id == id) + return drv->name; - for (i = 0; i < FME_FEATURE_ID_MAX; i++) { - feature = &fme->sub_feature[i]; - if (feature->state == IFPGA_FEATURE_ATTACHED && - feature->ops && feature->ops->uinit) - feature->ops->uinit(feature); + drv++; } + + return NULL; } -int fme_hw_init(struct ifpga_fme_hw *fme) +const char *get_port_feature_name(unsigned int id) +{ + struct feature_driver *drv = port_feature_drvs; + + while (drv->name) { + if (drv->id == id) + return drv->name; + + drv++; + } + + return NULL; +} + +static void feature_uinit(struct ifpga_feature_list *list) { struct feature *feature; - int i, ret; - if (fme->state != IFPGA_FME_IMPLEMENTED) - return -EINVAL; + TAILQ_FOREACH(feature, list, next) { + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + if (feature->ops && feature->ops->uinit) + feature->ops->uinit(feature); + } +} - for (i = 0; i < FME_FEATURE_ID_MAX; i++) { - feature = &fme->sub_feature[i]; - if (feature->state == IFPGA_FEATURE_ATTACHED && - feature->ops && feature->ops->init) { - ret = feature->ops->init(feature); - if (ret) { - fme_hw_uinit(fme); - return ret; +static int feature_init(struct feature_driver *drv, + struct ifpga_feature_list *list) +{ + struct feature *feature; + int ret; + + while (drv->ops) { + TAILQ_FOREACH(feature, list, next) { + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + if (feature->id == drv->id) { + feature->ops = drv->ops; + feature->name = drv->name; + if (feature->ops->init) { + ret = feature->ops->init(feature); + if (ret) + goto error; + } } } + drv++; } return 0; +error: + feature_uinit(list); + return ret; } -void port_hw_uinit(struct ifpga_port_hw *port) +int fme_hw_init(struct ifpga_fme_hw *fme) { - struct feature *feature; - int i; + int ret; - for (i = 0; i < PORT_FEATURE_ID_MAX; i++) { - feature = &port->sub_feature[i]; - if (feature->state == IFPGA_FEATURE_ATTACHED && - feature->ops && feature->ops->uinit) - feature->ops->uinit(feature); - } + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -ENODEV; + + ret = feature_init(fme_feature_drvs, &fme->feature_list); + if (ret) + return ret; + + return 0; +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + feature_uinit(&fme->feature_list); +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + feature_uinit(&port->feature_list); } int port_hw_init(struct ifpga_port_hw *port) { - struct feature *feature; - int i, ret; + int ret; if (port->state == IFPGA_PORT_UNUSED) return 0; - for (i = 0; i < PORT_FEATURE_ID_MAX; i++) { - feature = &port->sub_feature[i]; - if (feature->ops && feature->ops->init) { - ret = feature->ops->init(feature); - if (ret) { - port_hw_uinit(port); - return ret; - } - } - } + ret = feature_init(port_feature_drvs, &port->feature_list); + if (ret) + goto error; return 0; +error: + port_hw_uinit(port); + return ret; } - diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h index 4391f2f..067e9aa 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -7,6 +7,18 @@ #include "ifpga_hw.h" +struct feature_driver { + u64 id; + const char *name; + struct feature_ops *ops; +}; + +/** + * FEATURE_DRV - macro used to describe a specific feature driver + */ +#define FEATURE_DRV(n, s, p) \ + .id = (n), .name = (s), .ops = (p) + static inline struct ifpga_port_hw * get_port(struct ifpga_hw *hw, u32 port_id) { @@ -17,12 +29,10 @@ } #define ifpga_for_each_fme_feature(hw, feature) \ - for ((feature) = (hw)->sub_feature; \ - (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + TAILQ_FOREACH(feature, &hw->feature_list, next) -#define ifpga_for_each_port_feature(hw, feature) \ - for ((feature) = (hw)->sub_feature; \ - (feature) < (hw)->sub_feature + (PORT_FEATURE_ID_MAX); (feature)++) +#define ifpga_for_each_port_feature(port, feature) \ + TAILQ_FOREACH(feature, &port->feature_list, next) static inline struct feature * get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) @@ -50,16 +60,32 @@ return NULL; } +static inline struct feature * +get_feature_by_id(struct ifpga_feature_list *list, u64 id) +{ + struct feature *feature; + + TAILQ_FOREACH(feature, list, next) + if (feature->id == id) + return feature; + + return NULL; +} + static inline void * get_fme_feature_ioaddr_by_index(struct ifpga_fme_hw *fme, int index) { - return fme->sub_feature[index].addr; + struct feature *feature = get_feature_by_id(&fme->feature_list, index); + + return feature ? feature->addr : NULL; } static inline void * get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) { - return port->sub_feature[index].addr; + struct feature *feature = get_feature_by_id(&port->feature_list, index); + + return feature ? feature->addr : NULL; } static inline bool @@ -143,6 +169,11 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, extern struct feature_ops fme_pr_mgmt_ops; extern struct feature_ops fme_global_iperf_ops; extern struct feature_ops fme_global_dperf_ops; +extern struct feature_ops fme_hssi_eth_ops; +extern struct feature_ops fme_emif_ops; +extern struct feature_ops fme_spi_master_ops; +extern struct feature_ops fme_i2c_master_ops; +extern struct feature_ops fme_phy_group_ops; int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop); int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop); @@ -155,14 +186,31 @@ struct fpga_uafu_irq_set { }; int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); +const char *get_fme_feature_name(unsigned int id); +const char *get_port_feature_name(unsigned int id); extern struct feature_ops ifpga_rawdev_port_hdr_ops; extern struct feature_ops ifpga_rawdev_port_error_ops; extern struct feature_ops ifpga_rawdev_port_stp_ops; extern struct feature_ops ifpga_rawdev_port_uint_ops; +extern struct feature_ops ifpga_rawdev_port_afu_ops; /* help functions for feature ops */ int fpga_msix_set_block(struct feature *feature, unsigned int start, unsigned int count, s32 *fds); +/* FME network function ops*/ +int fme_mgr_read_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size); +int fme_mgr_write_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size); +int fme_mgr_read_phy_reg(struct ifpga_fme_hw *fme, int phy_group, + u8 entry, u16 reg, u32 *value); +int fme_mgr_write_phy_reg(struct ifpga_fme_hw *fme, int phy_group, + u8 entry, u16 reg, u32 value); +int fme_mgr_get_retimer_info(struct ifpga_fme_hw *fme, + struct opae_retimer_info *info); +int fme_mgr_set_retimer_speed(struct ifpga_fme_hw *fme, int speed); +int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme, int port, + struct opae_retimer_status *status); #endif /* _IFPGA_FEATURE_DEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c index 4be60c0..df87b5f 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -3,6 +3,12 @@ */ #include "ifpga_feature_dev.h" +#include "opae_i2c.h" +#include "opae_spi.h" +#include "opae_at24_eeprom.h" +#include "opae_phy_group.h" +#include "opae_intel_max10.h" +#include "opae_mdio.h" #define PWR_THRESHOLD_MAX 0x7F @@ -732,3 +738,370 @@ struct feature_ops fme_power_mgmt_ops = { .get_prop = fme_power_mgmt_get_prop, .set_prop = fme_power_mgmt_set_prop, }; + +static int spi_self_checking(void) +{ + u32 val; + int ret; + + ret = max10_reg_read(0x30043c, &val); + if (ret) + return -EIO; + + if (val != 0x87654321) { + dev_err(NULL, "Read MAX10 test register fail: 0x%x\n", val); + return -EIO; + } + + dev_info(NULL, "Read MAX10 test register success, SPI self-test done\n"); + + return 0; +} + +static int fme_spi_init(struct feature *feature) +{ + struct feature_fme_spi *spi; + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + struct altera_spi_device *spi_master; + struct intel_max10_device *max10; + int ret = 0; + + spi = (struct feature_fme_spi *)feature->addr; + + dev_info(fme, "FME SPI Master (Max10) Init.\n"); + dev_debug(fme, "FME SPI base addr %llx.\n", + (unsigned long long)spi); + dev_debug(fme, "spi param=0x%lx\n", opae_readq(feature->addr + 0x8)); + + spi_master = altera_spi_init(feature->addr); + if (!spi_master) + return -ENODEV; + + max10 = intel_max10_device_probe(spi_master, 0); + if (!max10) { + ret = -ENODEV; + dev_err(fme, "max10 init fail\n"); + goto spi_fail; + } + + fme->max10_dev = max10; + + /* SPI self test */ + if (spi_self_checking()) + return -EIO; + + return ret; + +spi_fail: + altera_spi_release(spi_master); + return ret; +} + +static void fme_spi_uinit(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + + if (fme->max10_dev) + intel_max10_device_remove(fme->max10_dev); +} + +struct feature_ops fme_spi_master_ops = { + .init = fme_spi_init, + .uinit = fme_spi_uinit, + +}; + +static int i2c_mac_rom_test(struct altera_i2c_dev *dev) +{ + char buf[20]; + int ret; + char read_buf[20] = {0,}; + const char *string = "1a2b3c4d5e"; + unsigned int i; + + opae_memcpy(buf, string, strlen(string)); + + printf("data writing into mac rom:\n"); + for (i = 0; i < strlen(string); i++) + printf("%x ", *((char *)buf+i)); + printf("\n"); + + ret = at24_eeprom_write(dev, AT24512_SLAVE_ADDR, 0, + (u8 *)buf, strlen(string)); + if (ret < 0) + printf("write i2c error:%d\n", ret); + + ret = at24_eeprom_read(dev, AT24512_SLAVE_ADDR, 0, + (u8 *)read_buf, strlen(string)); + if (ret < 0) + printf("read i2c error:%d\n", ret); + + printf("read from mac rom\n"); + for (i = 0; i < strlen(string); i++) + printf("%x ", *((char *)read_buf+i)); + printf("\n"); + + if (!memcmp(buf, read_buf, strlen(string))) { + printf("%s test success!\n", __func__); + return -EFAULT; + } + + printf("%s test fail\n", __func__); + + return 0; +} + +static int fme_i2c_init(struct feature *feature) +{ + struct feature_fme_i2c *i2c; + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + + i2c = (struct feature_fme_i2c *)feature->addr; + + dev_info(NULL, "FME I2C Master Init.\n"); + + fme->i2c_master = altera_i2c_probe(i2c); + if (!fme->i2c_master) + return -ENODEV; + + if (i2c_mac_rom_test(fme->i2c_master)) + return -ENODEV; + + return 0; +} + +static void fme_i2c_uninit(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + + altera_i2c_remove(fme->i2c_master); +} + +struct feature_ops fme_i2c_master_ops = { + .init = fme_i2c_init, + .uinit = fme_i2c_uninit, +}; + +static int fme_phy_group_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + struct phy_group_device *dev; + + dev = (struct phy_group_device *)phy_group_probe(feature->addr); + if (!dev) + return -ENODEV; + + fme->phy_dev[dev->group_index] = dev; + + dev_info(NULL, "FME PHY Group %d Init.\n", dev->group_index); + dev_info(NULL, "FME PHY Group register base address %llx.\n", + (unsigned long long)dev->base); + + return 0; +} + +static void fme_phy_group_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +struct feature_ops fme_phy_group_ops = { + .init = fme_phy_group_init, + .uinit = fme_phy_group_uinit, +}; + +static int fme_hssi_eth_init(struct feature *feature) +{ + UNUSED(feature); + return 0; +} + +static void fme_hssi_eth_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +struct feature_ops fme_hssi_eth_ops = { + .init = fme_hssi_eth_init, + .uinit = fme_hssi_eth_uinit, +}; + +static int fme_emif_init(struct feature *feature) +{ + UNUSED(feature); + return 0; +} + +static void fme_emif_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +struct feature_ops fme_emif_ops = { + .init = fme_emif_init, + .uinit = fme_emif_uinit, +}; + +static int fme_check_retimter_ports(struct ifpga_fme_hw *fme, int port) +{ + struct intel_max10_device *dev; + int ports; + + dev = (struct intel_max10_device *)fme->max10_dev; + if (!dev) + return -ENODEV; + + ports = dev->num_retimer * dev->num_port; + + if (port > ports || port < 0) + return -EINVAL; + + return 0; +} + +int fme_mgr_read_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size) +{ + struct altera_i2c_dev *dev; + + dev = fme->i2c_master; + if (!dev) + return -ENODEV; + + if (fme_check_retimter_ports(fme, offset/size)) + return -EINVAL; + + return at24_eeprom_read(dev, AT24512_SLAVE_ADDR, offset, buf, size); +} + +int fme_mgr_write_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size) +{ + struct altera_i2c_dev *dev; + + dev = fme->i2c_master; + if (!dev) + return -ENODEV; + + if (fme_check_retimter_ports(fme, offset/size)) + return -EINVAL; + + return at24_eeprom_write(dev, AT24512_SLAVE_ADDR, offset, buf, size); +} + +int fme_mgr_read_phy_reg(struct ifpga_fme_hw *fme, int phy_group, + u8 entry, u16 reg, u32 *value) +{ + struct phy_group_device *dev; + + if (phy_group > (MAX_PHY_GROUP_DEVICES - 1)) + return -EINVAL; + + dev = (struct phy_group_device *)fme->phy_dev[phy_group]; + if (!dev) + return -ENODEV; + + if (entry > dev->entries) + return -EINVAL; + + + return phy_group_read_reg(dev, entry, reg, value); +} + +int fme_mgr_write_phy_reg(struct ifpga_fme_hw *fme, int phy_group, + u8 entry, u16 reg, u32 value) +{ + struct phy_group_device *dev; + + if (phy_group > (MAX_PHY_GROUP_DEVICES - 1)) + return -EINVAL; + + dev = (struct phy_group_device *)fme->phy_dev[phy_group]; + if (!dev) + return -ENODEV; + + return phy_group_write_reg(dev, entry, reg, value); +} + +int fme_mgr_get_retimer_info(struct ifpga_fme_hw *fme, + struct opae_retimer_info *info) +{ + struct intel_max10_device *dev; + + dev = (struct intel_max10_device *)fme->max10_dev; + if (!dev) + return -ENODEV; + + info->num_retimer = dev->num_retimer; + info->num_port = dev->num_port; + + return 0; +} + +int fme_mgr_set_retimer_speed(struct ifpga_fme_hw *fme, int speed) +{ + struct intel_max10_device *dev; + int i, j, num; + int ret = 0; + + dev = (struct intel_max10_device *)fme->max10_dev; + if (!dev) + return -ENODEV; + + num = dev->num_retimer < INTEL_MAX10_MAX_MDIO_DEVS ? + dev->num_retimer : INTEL_MAX10_MAX_MDIO_DEVS; + + for (i = 0; i < num; i++) + for (j = 0; j < dev->num_port; j++) { + ret = pkvl_set_speed_mode(dev->mdio[i], j, speed); + if (ret) { + printf("pkvl_%d set port_%d speed %d fail\n", + i, j, speed); + break; + } + } + + return ret; +} + +int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme, int port, + struct opae_retimer_status *status) +{ + struct intel_max10_device *dev; + struct altera_mdio_dev *mdio; + int ports; + int ret; + + dev = (struct intel_max10_device *)fme->max10_dev; + if (!dev) + return -ENODEV; + + ports = dev->num_retimer * dev->num_port; + + if (port > ports || port < 0) + return -EINVAL; + + mdio = dev->mdio[port/dev->num_port]; + port = port % dev->num_port; + + ret = pkvl_get_port_speed_status(mdio, port, &status->speed); + if (ret) + goto error; + + ret = pkvl_get_port_line_link_status(mdio, port, &status->line_link); + if (ret) + goto error; + + ret = pkvl_get_port_host_link_status(mdio, port, &status->host_link); + if (ret) + goto error; + + dev_info(NULL, "get retimer status: pkvl:%d, port:%d, speed:%d, line:%d, host:%d\n", + mdio->index, port, status->speed, + status->line_link, status->host_link); + + return 0; + +error: + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c index ec0beeb..8890f4b 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -257,7 +257,7 @@ static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, return -EINVAL; } - memset(&info, 0, sizeof(struct fpga_pr_info)); + opae_memset(&info, 0, sizeof(struct fpga_pr_info)); info.flags = FPGA_MGR_PARTIAL_RECONFIG; info.port_id = port_id; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h index a20520c..6ac54c6 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -7,19 +7,30 @@ #include "ifpga_defines.h" #include "opae_ifpga_hw_api.h" +#include "opae_phy_group.h" + +/** List of private feateues */ +TAILQ_HEAD(ifpga_feature_list, feature); enum ifpga_feature_state { IFPGA_FEATURE_UNUSED = 0, IFPGA_FEATURE_ATTACHED, }; +enum feature_type { + FEATURE_FME_TYPE = 0, + FEATURE_PORT_TYPE, +}; + struct feature_irq_ctx { int eventfd; int idx; }; struct feature { + TAILQ_ENTRY(feature)next; enum ifpga_feature_state state; + enum feature_type type; const char *name; u64 id; u8 *addr; @@ -34,6 +45,8 @@ struct feature { void *parent; /* to parent hw data structure */ struct feature_ops *ops;/* callback to this private feature */ + unsigned int vec_start; + unsigned int vec_cnt; }; struct feature_ops { @@ -52,7 +65,7 @@ enum ifpga_fme_state { struct ifpga_fme_hw { enum ifpga_fme_state state; - struct feature sub_feature[FME_FEATURE_ID_MAX]; + struct ifpga_feature_list feature_list; spinlock_t lock; /* protect hardware access */ void *parent; /* pointer to ifpga_hw */ @@ -67,6 +80,10 @@ struct ifpga_fme_hw { u32 cache_size; u32 capability; + + void *i2c_master; /* I2C Master device */ + void *max10_dev; /* MAX10 device */ + void *phy_dev[MAX_PHY_GROUP_DEVICES]; }; enum ifpga_port_state { @@ -78,7 +95,7 @@ enum ifpga_port_state { struct ifpga_port_hw { enum ifpga_port_state state; - struct feature sub_feature[PORT_FEATURE_ID_MAX]; + struct ifpga_feature_list feature_list; spinlock_t lock; /* protect access to hw */ void *parent; /* pointer to ifpga_hw */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c index 8b5668d..4628783 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_port.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -386,3 +386,24 @@ struct feature_ops ifpga_rawdev_port_uint_ops = { .init = port_uint_init, .uinit = port_uint_uinit, }; + +static int port_afu_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT AFU Init.\n"); + + return 0; +} + +static void port_afu_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT AFU UInit.\n"); +} + +struct feature_ops ifpga_rawdev_port_afu_ops = { + .init = port_afu_init, + .uinit = port_afu_uinit, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c new file mode 100644 index 0000000..cc4901a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c @@ -0,0 +1,89 @@ + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_i2c.h" +#include "opae_at24_eeprom.h" + +#define AT24_READ_RETRY 10 + +static int at24_eeprom_read_and_try(struct altera_i2c_dev *dev, + unsigned int slave_addr, + u32 offset, u8 *buf, u32 len) +{ + int i; + int ret = 0; + + for (i = 0; i < AT24_READ_RETRY; i++) { + ret = i2c_read16(dev, slave_addr, offset, + buf, len); + if (ret == 0) + break; + + opae_udelay(100); + } + + return ret; +} + +int at24_eeprom_read(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count) +{ + int len; + int status; + int read_count = 0; + + if (!count) + return count; + + if (count > AT24C512_IO_LIMIT) + len = AT24C512_IO_LIMIT; + else + len = count; + + while (count) { + status = at24_eeprom_read_and_try(dev, slave_addr, offset, + buf, len); + if (status) + break; + + buf += len; + offset += len; + count -= len; + read_count += len; + } + + return read_count; +} + +int at24_eeprom_write(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count) +{ + int len; + int status; + int write_count = 0; + + if (!count) + return count; + + if (count > AT24C512_PAGE_SIZE) + len = AT24C512_PAGE_SIZE; + else + len = count; + + while (count) { + status = i2c_write16(dev, slave_addr, offset, buf, len); + if (status) + break; + + buf += len; + offset += len; + count -= len; + write_count += len; + } + + return write_count; +} + diff --git a/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h new file mode 100644 index 0000000..4aa0ee2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h @@ -0,0 +1,14 @@ + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define AT24C512_PAGE_SIZE 128 +#define AT24C512_IO_LIMIT 128 + +#define AT24512_SLAVE_ADDR 0x51 + +int at24_eeprom_read(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count); +int at24_eeprom_write(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count); diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c index 1541b67..c04bff2 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -210,12 +210,14 @@ int opae_acc_get_uuid(struct opae_accelerator *acc, * opae_manager_alloc - alloc opae_manager data structure * @name: manager name. * @ops: ops of this manager. + * @network_ops: ops of network management. * @data: private data of this manager. * * Return: opae_manager on success, otherwise NULL. */ struct opae_manager * -opae_manager_alloc(const char *name, struct opae_manager_ops *ops, void *data) +opae_manager_alloc(const char *name, struct opae_manager_ops *ops, + struct opae_manager_networking_ops *network_ops, void *data) { struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); @@ -224,6 +226,7 @@ struct opae_manager * mgr->name = name; mgr->ops = ops; + mgr->network_ops = network_ops; mgr->data = data; opae_log("%s %p\n", __func__, mgr); @@ -304,7 +307,7 @@ static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) /** * opae_adapter_init - init opae_adapter data structure - * @adapter: pointer of opae_adapter data structure + * @adpdate: pointer of opae_adater data structure * @name: adapter name. * @data: private data of this adapter. * @@ -325,6 +328,26 @@ int opae_adapter_init(struct opae_adapter *adapter, } /** + * opae_adapter_alloc - alloc opae_adapter data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + if (opae_adapter_init(adapter, name, data)) + return NULL; + + return adapter; +} + +/** * opae_adapter_enumerate - enumerate this adapter * @adapter: adapter to enumerate. * @@ -341,7 +364,7 @@ int opae_adapter_enumerate(struct opae_adapter *adapter) ret = adapter->ops->enumerate(adapter); if (!ret) - opae_adapter_dump(adapter, 1); + opae_adapter_dump(adapter, 0); return ret; } @@ -379,3 +402,163 @@ struct opae_accelerator * return NULL; } + +/** + * opae_manager_read_mac_rom - read the content of the MAC ROM + * @mgr: opae_manager for MAC ROM + * @port: the port number of retimer + * @addr: buffer of the MAC address + * + * Return: return the bytes of read successfully + */ +int opae_manager_read_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->read_mac_rom) + return mgr->network_ops->read_mac_rom(mgr, + port * sizeof(struct opae_ether_addr), + addr, sizeof(struct opae_ether_addr)); + + return -ENOENT; +} + +/** + * opae_manager_write_mac_rom - write data into MAC ROM + * @mgr: opae_manager for MAC ROM + * @port: the port number of the retimer + * @addr: data of the MAC address + * + * Return: return written bytes + */ +int opae_manager_write_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops && mgr->network_ops->write_mac_rom) + return mgr->network_ops->write_mac_rom(mgr, + port * sizeof(struct opae_ether_addr), + addr, sizeof(struct opae_ether_addr)); + + return -ENOENT; +} + +/** + * opae_manager_read_phy_reg - read phy register + * @mgr: opae_manager for PHY + * @phy_group: PHY group index + * @entry: PHY entries + * @reg: register address in PHY group + * @val: register value + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_read_phy_reg(struct opae_manager *mgr, int phy_group, + u8 entry, u32 reg, u32 *val) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->read_phy_reg) + return mgr->network_ops->read_phy_reg(mgr, phy_group, + entry, reg, val); + + return -ENOENT; +} + +/** + * opae_manager_write_phy_reg - write PHY group register + * @mgr: opae_manager for PHY Group + * @phy_group: PHY Group index + * @entry: PHY Group entries + * @reg: register address of PHY Group + * @val: data will write to register + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_write_phy_reg(struct opae_manager *mgr, int phy_group, + u8 entry, u32 reg, u32 val) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->write_phy_reg) + return mgr->network_ops->write_phy_reg(mgr, phy_group, + entry, reg, val); + + return -ENOENT; +} + +/** + * opae_manager_get_retimer_info - get retimer info like PKVL chip + * @mgr: opae_manager for retimer + * @info: info return to caller + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_get_retimer_info(struct opae_manager *mgr, + struct opae_retimer_info *info) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + //if (mgr->network_ops->get_retimer_info) + // return mgr->network_ops->get_retimer_info(mgr, info); + + //return -ENOENT; + info->num_retimer = 4; + info->num_port = 8; + info->support_speed = MXD_10GB; + + return 0; +} + +/** + * opae_manager_set_retimer_speed - configure the speed of retimer, + * like 10GB or 25GB + * @mgr: opae_manager of MDIO + * @speed: the speed of retimer + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_set_retimer_speed(struct opae_manager *mgr, int speed) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + //if (mgr->network_ops->set_retimer_speed) + // return mgr->network_ops->set_retimer_speed(mgr, speed); + UNUSED(speed); + + return 0; +} + +/** + * opae_manager_get_retimer_status - get retimer status + * @mgr: opae_manager of retimer + * @status: status of retimer + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_get_retimer_status(struct opae_manager *mgr, + int port, struct opae_retimer_status *status) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + //if (mgr->network_ops->get_retimer_status) + // return mgr->network_ops->get_retimer_status(mgr, + // port, status); + + //return -ENOENT; + UNUSED(port); + status->speed = MXD_10GB; + status->line_link = 1; + status->host_link = 1; + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h index 332e0f3..0bfe5cc 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -11,6 +11,7 @@ #include #include "opae_osdep.h" +#include "opae_mdio.h" #ifndef PCI_MAX_RESOURCE #define PCI_MAX_RESOURCE 6 @@ -25,6 +26,7 @@ enum opae_adapter_type { /* OPAE Manager Data Structure */ struct opae_manager_ops; +struct opae_manager_networking_ops; /* * opae_manager has pointer to its parent adapter, as it could be able to manage @@ -35,6 +37,7 @@ struct opae_manager { const char *name; struct opae_adapter *adapter; struct opae_manager_ops *ops; + struct opae_manager_networking_ops *network_ops; void *data; }; @@ -44,9 +47,27 @@ struct opae_manager_ops { u32 size, u64 *status); }; +/* networking management ops in FME */ +struct opae_manager_networking_ops { + int (*read_mac_rom)(struct opae_manager *mgr, int offset, void *buf, + int size); + int (*write_mac_rom)(struct opae_manager *mgr, int offset, void *buf, + int size); + int (*read_phy_reg)(struct opae_manager *mgr, int phy_group, + u8 entry, u16 reg, u32 *value); + int (*write_phy_reg)(struct opae_manager *mgr, int phy_group, + u8 entry, u16 reg, u32 value); + int (*get_retimer_info)(struct opae_manager *mgr, + struct opae_retimer_info *info); + int (*set_retimer_speed)(struct opae_manager *mgr, int speed); + int (*get_retimer_status)(struct opae_manager *mgr, int port, + struct opae_retimer_status *status); +}; + /* OPAE Manager APIs */ struct opae_manager * -opae_manager_alloc(const char *name, struct opae_manager_ops *ops, void *data); +opae_manager_alloc(const char *name, struct opae_manager_ops *ops, + struct opae_manager_networking_ops *network_ops, void *data); #define opae_manager_free(mgr) opae_free(mgr) int opae_manager_flash(struct opae_manager *mgr, int acc_id, void *buf, u32 size, u64 *status); @@ -227,6 +248,7 @@ struct opae_adapter { int opae_adapter_init(struct opae_adapter *adapter, const char *name, void *data); +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); #define opae_adapter_free(adapter) opae_free(adapter) int opae_adapter_enumerate(struct opae_adapter *adapter); @@ -251,4 +273,26 @@ static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, { TAILQ_REMOVE(&adapter->acc_list, acc, node); } + +/* OPAE vBNG network datastruct */ +#define OPAE_ETHER_ADDR_LEN 6 + +struct opae_ether_addr { + unsigned char addr_bytes[OPAE_ETHER_ADDR_LEN]; +} __attribute__((__packed__)); + +/* OPAE vBNG network API*/ +int opae_manager_read_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr); +int opae_manager_write_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr); +int opae_manager_read_phy_reg(struct opae_manager *mgr, int phy_group, + u8 entry, u32 reg, u32 *value); +int opae_manager_write_phy_reg(struct opae_manager *mgr, int phy_group, + u8 entry, u32 reg, u32 value); +int opae_manager_get_retimer_info(struct opae_manager *mgr, + struct opae_retimer_info *info); +int opae_manager_set_retimer_speed(struct opae_manager *mgr, int speed); +int opae_manager_get_retimer_status(struct opae_manager *mgr, int port, + struct opae_retimer_status *status); #endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_i2c.c b/drivers/raw/ifpga_rawdev/base/opae_i2c.c new file mode 100644 index 0000000..415afab --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_i2c.c @@ -0,0 +1,490 @@ + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_i2c.h" + +static int i2c_transfer(struct altera_i2c_dev *dev, + struct i2c_msg *msg, int num) +{ + int ret, try; + + for (ret = 0, try = 0; try < I2C_XFER_RETRY; try++) { + ret = dev->xfer(dev, msg, num); + if (ret != -EAGAIN) + break; + } + + return ret; +} + +/** + * i2c read function + */ +int i2c_read(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buf, u32 count) +{ + u8 msgbuf[2]; + int i = 0; + + if (flags & I2C_FLAG_ADDR16) + msgbuf[i++] = offset >> 8; + + msgbuf[i++] = offset; + + struct i2c_msg msg[2] = { + { + .addr = slave_addr, + .flags = 0, + .len = i, + .buf = msgbuf, + }, + { + .addr = slave_addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }, + }; + + if (!dev->xfer) + return -ENODEV; + + return i2c_transfer(dev, msg, 2); +} + +int i2c_write(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buffer, int len) +{ + struct i2c_msg msg; + u8 *buf; + int ret; + int i = 0; + + if (!dev->xfer) + return -ENODEV; + + buf = opae_malloc(I2C_MAX_OFFSET_LEN + len); + if (!buf) + return -ENOMEM; + + msg.addr = slave_addr; + msg.flags = 0; + msg.buf = buf; + + if (flags & I2C_FLAG_ADDR16) + msg.buf[i++] = offset >> 8; + + msg.buf[i++] = offset; + opae_memcpy(&msg.buf[i], buffer, len); + msg.len = i + len; + + ret = i2c_transfer(dev, &msg, 1); + + opae_free(buf); + return ret; +} + +int i2c_read8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_read(dev, 0, slave_addr, offset, buf, count); +} + +int i2c_read16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_read(dev, I2C_FLAG_ADDR16, slave_addr, offset, + buf, count); +} + +int i2c_write8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_write(dev, 0, slave_addr, offset, buf, count); +} + +int i2c_write16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_write(dev, I2C_FLAG_ADDR16, slave_addr, offset, + buf, count); +} + +static void i2c_indirect_write(struct altera_i2c_dev *dev, u32 reg, + u32 value) +{ + u64 ctrl; + + ctrl = I2C_CTRL_W | (reg >> 2); + + opae_writeq(value & I2C_WRITE_DATA_MASK, dev->base + I2C_WRITE); + opae_writeq(ctrl, dev->base + I2C_CTRL); +} + +static u32 i2c_indirect_read(struct altera_i2c_dev *dev, u32 reg) +{ + u64 tmp; + u64 ctrl; + u32 value; + + ctrl = I2C_CTRL_R | (reg >> 2); + opae_writeq(ctrl, dev->base + I2C_CTRL); + + /* FIXME: Read one more time to avoid HW timing issue. */ + tmp = opae_readq(dev->base + I2C_READ); + tmp = opae_readq(dev->base + I2C_READ); + + value = tmp & I2C_READ_DATA_MASK; + + return value; +} + +static void altera_i2c_transfer(struct altera_i2c_dev *dev, u32 data) +{ + /*send STOP on last byte*/ + if (dev->msg_len == 1) + data |= ALTERA_I2C_TFR_CMD_STO; + if (dev->msg_len > 0) + i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD, data); +} + +static void altera_i2c_disable(struct altera_i2c_dev *dev) +{ + u32 val = i2c_indirect_read(dev, ALTERA_I2C_CTRL); + + i2c_indirect_write(dev, ALTERA_I2C_CTRL, val&~ALTERA_I2C_CTRL_EN); +} + +static void altera_i2c_enable(struct altera_i2c_dev *dev) +{ + u32 val = i2c_indirect_read(dev, ALTERA_I2C_CTRL); + + i2c_indirect_write(dev, ALTERA_I2C_CTRL, val | ALTERA_I2C_CTRL_EN); +} + +static void altera_i2c_reset(struct altera_i2c_dev *dev) +{ + altera_i2c_disable(dev); + altera_i2c_enable(dev); +} + +static int altera_i2c_wait_core_idle(struct altera_i2c_dev *dev) +{ + int retry = 0; + + while (i2c_indirect_read(dev, ALTERA_I2C_STATUS) + & ALTERA_I2C_STAT_CORE) { + if (retry++ > ALTERA_I2C_TIMEOUT_US) { + dev_err(dev, "timeout: Core Status not IDLE...\n"); + return -EBUSY; + } + udelay(1); + } + + return 0; +} + +static void altera_i2c_enable_interrupt(struct altera_i2c_dev *dev, + u32 mask, bool enable) +{ + u32 status; + + status = i2c_indirect_read(dev, ALTERA_I2C_ISER); + if (enable) + dev->isr_mask = status | mask; + else + dev->isr_mask = status&~mask; + + i2c_indirect_write(dev, ALTERA_I2C_ISER, dev->isr_mask); +} + +static void altera_i2c_interrupt_clear(struct altera_i2c_dev *dev, u32 mask) +{ + u32 int_en; + + int_en = i2c_indirect_read(dev, ALTERA_I2C_ISR); + + i2c_indirect_write(dev, ALTERA_I2C_ISR, int_en | mask); +} + +static void altera_i2c_read_rx_fifo(struct altera_i2c_dev *dev) +{ + size_t rx_avail; + size_t bytes; + + rx_avail = i2c_indirect_read(dev, ALTERA_I2C_RX_FIFO_LVL); + bytes = min(rx_avail, dev->msg_len); + + while (bytes-- > 0) { + *dev->buf++ = i2c_indirect_read(dev, ALTERA_I2C_RX_DATA); + dev->msg_len--; + altera_i2c_transfer(dev, 0); + } +} + +static void altera_i2c_stop(struct altera_i2c_dev *dev) +{ + i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD, ALTERA_I2C_TFR_CMD_STO); +} + +static int altera_i2c_fill_tx_fifo(struct altera_i2c_dev *dev) +{ + size_t tx_avail; + int bytes; + int ret; + + tx_avail = dev->fifo_size - + i2c_indirect_read(dev, ALTERA_I2C_TC_FIFO_LVL); + bytes = min(tx_avail, dev->msg_len); + ret = dev->msg_len - bytes; + + while (bytes-- > 0) { + altera_i2c_transfer(dev, *dev->buf++); + dev->msg_len--; + } + + return ret; +} + +static u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg) +{ + return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0); +} + +static int altera_i2c_wait_complete(struct altera_i2c_dev *dev, + u32 *status) +{ + int retry = 0; + + while (!((*status = i2c_indirect_read(dev, ALTERA_I2C_ISR)) + & dev->isr_mask)) { + if (retry++ > ALTERA_I2C_TIMEOUT_US) + return -EBUSY; + + udelay(1000); + } + + return 0; +} + +static bool altera_handle_i2c_status(struct altera_i2c_dev *dev, u32 status) +{ + bool read, finish = false; + int ret; + + read = (dev->msg->flags & I2C_M_RD) != 0; + + if (status & ALTERA_I2C_ISR_ARB) { + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_ARB); + dev->msg_err = -EAGAIN; + finish = true; + } else if (status & ALTERA_I2C_ISR_NACK) { + dev_debug(dev, "could not get ACK\n"); + dev->msg_err = -ENXIO; + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_NACK); + altera_i2c_stop(dev); + finish = true; + } else if (read && (status & ALTERA_I2C_ISR_RXOF)) { + /* RX FIFO Overflow */ + altera_i2c_read_rx_fifo(dev); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISER_RXOF_EN); + altera_i2c_stop(dev); + dev_err(dev, "error: RX FIFO overflow\n"); + finish = true; + } else if (read && (status & ALTERA_I2C_ISR_RXRDY)) { + altera_i2c_read_rx_fifo(dev); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_RXRDY); + if (!dev->msg_len) + finish = true; + } else if (!read && (status & ALTERA_I2C_ISR_TXRDY)) { + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_TXRDY); + if (dev->msg_len > 0) + altera_i2c_fill_tx_fifo(dev); + else + finish = true; + } else { + dev_err(dev, "unexpected status:0x%x\n", status); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ALL_IRQ); + } + + if (finish) { + ret = altera_i2c_wait_core_idle(dev); + if (ret) + dev_err(dev, "message timeout\n"); + + altera_i2c_enable_interrupt(dev, ALTERA_I2C_ALL_IRQ, false); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ALL_IRQ); + dev_debug(dev, "message done\n"); + } + + return finish; +} + +static bool altera_i2c_poll_status(struct altera_i2c_dev *dev) +{ + u32 status; + bool finish = false; + int i = 0; + + do { + if (altera_i2c_wait_complete(dev, &status)) { + dev_err(dev, "altera i2c wait complete timeout, status=0x%x\n", + status); + return -EBUSY; + } + + finish = altera_handle_i2c_status(dev, status); + + if (i++ > I2C_XFER_RETRY) + break; + + } while (!finish); + + return finish; +} + +static int altera_i2c_xfer_msg(struct altera_i2c_dev *dev, + struct i2c_msg *msg) +{ + u32 int_mask = ALTERA_I2C_ISR_RXOF | + ALTERA_I2C_ISR_ARB | ALTERA_I2C_ISR_NACK; + u8 addr = i2c_8bit_addr_from_msg(msg); + bool finish; + + dev->msg = msg; + dev->msg_len = msg->len; + dev->buf = msg->buf; + dev->msg_err = 0; + altera_i2c_enable(dev); + + /*make sure RX FIFO is emtry*/ + do { + i2c_indirect_read(dev, ALTERA_I2C_RX_DATA); + } while (i2c_indirect_read(dev, ALTERA_I2C_RX_FIFO_LVL)); + + i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD_RW_D, + ALTERA_I2C_TFR_CMD_STA | addr); + + /*enable irq*/ + if (msg->flags & I2C_M_RD) { + int_mask |= ALTERA_I2C_ISR_RXOF | ALTERA_I2C_ISR_RXRDY; + /* in polling mode, we should set this ISR register? */ + altera_i2c_enable_interrupt(dev, int_mask, true); + altera_i2c_transfer(dev, 0); + } else { + int_mask |= ALTERA_I2C_ISR_TXRDY; + altera_i2c_enable_interrupt(dev, int_mask, true); + altera_i2c_fill_tx_fifo(dev); + } + + finish = altera_i2c_poll_status(dev); + if (!finish) { + dev->msg_err = -ETIMEDOUT; + dev_err(dev, "%s: i2c transfer error\n", __func__); + } + + altera_i2c_enable_interrupt(dev, int_mask, false); + + if (i2c_indirect_read(dev, ALTERA_I2C_STATUS) & ALTERA_I2C_STAT_CORE) + dev_info(dev, "core not idle...\n"); + + altera_i2c_disable(dev); + + return dev->msg_err; +} + +static int altera_i2c_xfer(struct altera_i2c_dev *dev, + struct i2c_msg *msg, int num) +{ + int ret = 0; + int i; + + for (i = 0; i < num; i++, msg++) { + ret = altera_i2c_xfer_msg(dev, msg); + if (ret) + break; + } + + return ret; +} + +static void altera_i2c_hardware_init(struct altera_i2c_dev *dev) +{ + u32 divisor = dev->i2c_clk / dev->bus_clk_rate; + u32 clk_mhz = dev->i2c_clk / 1000000; + u32 tmp = (ALTERA_I2C_THRESHOLD << ALTERA_I2C_CTRL_RXT_SHFT) | + (ALTERA_I2C_THRESHOLD << ALTERA_I2C_CTRL_TCT_SHFT); + u32 t_high, t_low; + + if (dev->bus_clk_rate <= 100000) { + tmp &= ~ALTERA_I2C_CTRL_BSPEED; + /*standard mode SCL 50/50*/ + t_high = divisor*1/2; + t_low = divisor*1/2; + } else { + tmp |= ALTERA_I2C_CTRL_BSPEED; + /*Fast mode SCL 33/66*/ + t_high = divisor*1/3; + t_low = divisor*2/3; + } + + i2c_indirect_write(dev, ALTERA_I2C_CTRL, tmp); + + dev_info(dev, "%s: rate=%uHz per_clk=%uMHz -> ratio=1:%u\n", + __func__, dev->bus_clk_rate, clk_mhz, divisor); + + /*reset the i2c*/ + altera_i2c_reset(dev); + + /*Set SCL high Time*/ + i2c_indirect_write(dev, ALTERA_I2C_SCL_HIGH, t_high); + /*Set SCL low time*/ + i2c_indirect_write(dev, ALTERA_I2C_SCL_LOW, t_low); + /*Set SDA Hold time, 300ms*/ + i2c_indirect_write(dev, ALTERA_I2C_SDA_HOLD, (300*clk_mhz)/1000); + + altera_i2c_enable_interrupt(dev, ALTERA_I2C_ALL_IRQ, false); +} + +struct altera_i2c_dev *altera_i2c_probe(void *base) +{ + struct altera_i2c_dev *dev; + + dev = opae_malloc(sizeof(*dev)); + if (!dev) + return NULL; + + dev->base = (u8 *)base; + dev->i2c_param.info = opae_readq(dev->base + I2C_PARAM); + + if (dev->i2c_param.devid != 0xEE011) { + dev_err(dev, "find a invalid i2c master\n"); + return NULL; + } + + dev->fifo_size = dev->i2c_param.fifo_depth; + + if (dev->i2c_param.max_req == ALTERA_I2C_100KHZ) + dev->bus_clk_rate = 100000; + else if (dev->i2c_param.max_req == ALTERA_I2C_400KHZ) + /* i2c bus clk 400KHz*/ + dev->bus_clk_rate = 400000; + + /* i2c input clock for vista creek is 100MHz */ + dev->i2c_clk = dev->i2c_param.ref_clk * 1000000; + dev->xfer = altera_i2c_xfer; + + altera_i2c_hardware_init(dev); + + return dev; +} + +int altera_i2c_remove(struct altera_i2c_dev *dev) +{ + altera_i2c_disable(dev); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_i2c.h b/drivers/raw/ifpga_rawdev/base/opae_i2c.h new file mode 100644 index 0000000..36f5927 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_i2c.h @@ -0,0 +1,127 @@ + +#ifndef _OPAE_I2C_H +#define _OPAE_I2C_H + +#include "opae_osdep.h" + +#define ALTERA_I2C_TFR_CMD 0x00 /* Transfer Command register */ +#define ALTERA_I2C_TFR_CMD_STA BIT(9) /* send START before byte */ +#define ALTERA_I2C_TFR_CMD_STO BIT(8) /* send STOP after byte */ +#define ALTERA_I2C_TFR_CMD_RW_D BIT(0) /* Direction of transfer */ +#define ALTERA_I2C_RX_DATA 0x04 /* RX data FIFO register */ +#define ALTERA_I2C_CTRL 0x8 /* Control register */ +#define ALTERA_I2C_CTRL_RXT_SHFT 4 /* RX FIFO Threshold */ +#define ALTERA_I2C_CTRL_TCT_SHFT 2 /* TFER CMD FIFO Threshold */ +#define ALTERA_I2C_CTRL_BSPEED BIT(1) /* Bus Speed */ +#define ALTERA_I2C_CTRL_EN BIT(0) /* Enable Core */ +#define ALTERA_I2C_ISER 0xc /* Interrupt Status Enable register */ +#define ALTERA_I2C_ISER_RXOF_EN BIT(4) /* Enable RX OVERFLOW IRQ */ +#define ALTERA_I2C_ISER_ARB_EN BIT(3) /* Enable ARB LOST IRQ */ +#define ALTERA_I2C_ISER_NACK_EN BIT(2) /* Enable NACK DET IRQ */ +#define ALTERA_I2C_ISER_RXRDY_EN BIT(1) /* Enable RX Ready IRQ */ +#define ALTERA_I2C_ISER_TXRDY_EN BIT(0) /* Enable TX Ready IRQ */ +#define ALTERA_I2C_ISR 0x10 /* Interrupt Status register */ +#define ALTERA_I2C_ISR_RXOF BIT(4) /* RX OVERFLOW */ +#define ALTERA_I2C_ISR_ARB BIT(3) /* ARB LOST */ +#define ALTERA_I2C_ISR_NACK BIT(2) /* NACK DET */ +#define ALTERA_I2C_ISR_RXRDY BIT(1) /* RX Ready */ +#define ALTERA_I2C_ISR_TXRDY BIT(0) /* TX Ready */ +#define ALTERA_I2C_STATUS 0x14 /* Status register */ +#define ALTERA_I2C_STAT_CORE BIT(0) /* Core Status */ +#define ALTERA_I2C_TC_FIFO_LVL 0x18 /* Transfer FIFO LVL register */ +#define ALTERA_I2C_RX_FIFO_LVL 0x1c /* Receive FIFO LVL register */ +#define ALTERA_I2C_SCL_LOW 0x20 /* SCL low count register */ +#define ALTERA_I2C_SCL_HIGH 0x24 /* SCL high count register */ +#define ALTERA_I2C_SDA_HOLD 0x28 /* SDA hold count register */ + +#define ALTERA_I2C_ALL_IRQ (ALTERA_I2C_ISR_RXOF | ALTERA_I2C_ISR_ARB | \ + ALTERA_I2C_ISR_NACK | ALTERA_I2C_ISR_RXRDY | \ + ALTERA_I2C_ISR_TXRDY) + +#define ALTERA_I2C_THRESHOLD 0 +#define ALTERA_I2C_DFLT_FIFO_SZ 8 +#define ALTERA_I2C_TIMEOUT_US 250000 /* 250ms */ + +#define I2C_PARAM 0x8 +#define I2C_CTRL 0x10 +#define I2C_CTRL_R BIT_ULL(9) +#define I2C_CTRL_W BIT_ULL(8) +#define I2C_CTRL_ADDR_MASK GENMASK_ULL(3, 0) +#define I2C_READ 0x18 +#define I2C_READ_DATA_VALID BIT_ULL(32) +#define I2C_READ_DATA_MASK GENMASK_ULL(31, 0) +#define I2C_WRITE 0x20 +#define I2C_WRITE_DATA_MASK GENMASK_ULL(31, 0) + +#define ALTERA_I2C_100KHZ 0 +#define ALTERA_I2C_400KHZ 1 + +/* i2c slave using 16bit address */ +#define I2C_FLAG_ADDR16 1 + +#define I2C_XFER_RETRY 10 + +struct i2c_core_param { + union { + u64 info; + struct { + u16 fifo_depth:9; + u8 interface:1; + /*reference clock of I2C core in MHz*/ + u32 ref_clk:10; + /*Max I2C interface freq*/ + u8 max_req:4; + u64 devid:32; + /* number of MAC address*/ + u8 nu_macs:8; + }; + }; +}; + +struct altera_i2c_dev { + u8 *base; + struct i2c_core_param i2c_param; + u32 fifo_size; + u32 bus_clk_rate; /* i2c bus clock */ + u32 i2c_clk; /* i2c input clock */ + struct i2c_msg *msg; + size_t msg_len; + int msg_err; + u32 isr_mask; + u8 *buf; + int (*xfer)(struct altera_i2c_dev *dev, struct i2c_msg *msg, int num); +}; + +/** + * struct i2c_msg: an I2C message + */ +struct i2c_msg { + unsigned int addr; + unsigned int flags; + unsigned int len; + u8 *buf; +}; + +#define I2C_MAX_OFFSET_LEN 4 + +enum i2c_msg_flags { + I2C_M_TEN = 0x0010, /*ten-bit chip address*/ + I2C_M_RD = 0x0001, /*read data*/ + I2C_M_STOP = 0x8000, /*send stop after this message*/ +}; + +struct altera_i2c_dev *altera_i2c_probe(void *base); +int altera_i2c_remove(struct altera_i2c_dev *dev); +int i2c_read(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buf, u32 count); +int i2c_write(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buffer, int len); +int i2c_read8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +int i2c_read16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +int i2c_write8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +int i2c_write16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +#endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_intel_max10.c b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.c new file mode 100644 index 0000000..37292f4 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.c @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_intel_max10.h" + +static struct intel_max10_device *g_max10; + +int max10_reg_read(unsigned int reg, unsigned int *val) +{ + if (!g_max10) + return -ENODEV; + + return spi_transaction_read(g_max10->spi_tran_dev, + reg, 4, (unsigned char *)val); +} + +int max10_reg_write(unsigned int reg, unsigned int val) +{ + if (!g_max10) + return -ENODEV; + + return spi_transaction_write(g_max10->spi_tran_dev, + reg, 4, (unsigned char *)&val); +} + +struct resource mdio_resource[INTEL_MAX10_MAX_MDIO_DEVS] = { + { + .start = 0x200100, + .end = 0x2001ff, + }, + { + .start = 0x200200, + .end = 0x2002ff, + }, +}; + +struct intel_max10_device * +intel_max10_device_probe(struct altera_spi_device *spi, + int chipselect) +{ + struct intel_max10_device *dev; + int i; + + dev = opae_malloc(sizeof(*dev)); + if (!dev) + return NULL; + + dev->spi_master = spi; + + dev->spi_tran_dev = spi_transaction_init(spi, chipselect); + if (!dev->spi_tran_dev) { + dev_err(dev, "%s spi tran init fail\n", __func__); + goto free_dev; + } + + g_max10 = dev; + + for (i = 0; i < INTEL_MAX10_MAX_MDIO_DEVS; i++) { + dev->mdio[i] = altera_mdio_probe(i, mdio_resource[i].start, + mdio_resource[i].end, dev->spi_tran_dev); + if (!dev->mdio[i]) { + dev_err(dev, "%s mido init fail\n", __func__); + goto mdio_fail; + } + } + + /* FIXME: should read this info from MAX10 device table */ + dev->num_retimer = INTEL_MAX10_MAX_MDIO_DEVS; + dev->num_port = PKVL_NUMBER_PORTS; + + return dev; + +mdio_fail: + for (i = 0; i < INTEL_MAX10_MAX_MDIO_DEVS; i++) + if (dev->mdio[i]) + opae_free(dev->mdio[i]); + + spi_transaction_remove(dev->spi_tran_dev); +free_dev: + g_max10 = NULL; + opae_free(dev); + + return NULL; +} + +int intel_max10_device_remove(struct intel_max10_device *dev) +{ + int i; + + if (!dev) + return 0; + + if (dev->spi_tran_dev) + spi_transaction_remove(dev->spi_tran_dev); + + for (i = 0; i < INTEL_MAX10_MAX_MDIO_DEVS; i++) + if (dev->mdio[i]) + altera_mdio_release(dev->mdio[i]); + + g_max10 = NULL; + + opae_free(dev); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h new file mode 100644 index 0000000..b212825 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#ifndef _OPAE_INTEL_MAX10_H_ +#define _OPAE_INTEL_MAX10_H_ + +#include "opae_osdep.h" +#include "opae_spi.h" +#include "opae_mdio.h" + +#define INTEL_MAX10_MAX_MDIO_DEVS 2 +#define PKVL_NUMBER_PORTS 4 + +struct intel_max10_device { + struct altera_spi_device *spi_master; + struct spi_transaction_dev *spi_tran_dev; + struct altera_mdio_dev *mdio[INTEL_MAX10_MAX_MDIO_DEVS]; + int num_retimer; /* number of retimer */ + int num_port; /* number of ports in retimer */ +}; + +struct resource { + u32 start; + u32 end; + u32 flags; +}; + +int max10_reg_read(unsigned int reg, unsigned int *val); +int max10_reg_write(unsigned int reg, unsigned int val); +struct intel_max10_device * +intel_max10_device_probe(struct altera_spi_device *spi, + int chipselect); +int intel_max10_device_remove(struct intel_max10_device *dev); + +#endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_mdio.c b/drivers/raw/ifpga_rawdev/base/opae_mdio.c new file mode 100644 index 0000000..6eb093b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_mdio.c @@ -0,0 +1,542 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_spi.h" +#include "opae_mdio.h" +#include "opae_intel_max10.h" + +#define PHY_MAX_ADDR 32 +#define MAX_NUM_IDS 8 +#define MDIO_PHYSID1 2 +#define MDIO_PHYSID2 3 +#define MDIO_DEVS2 6 +#define MDIO_DEVS1 5 + +static int max10_mdio_reg_read(struct altera_mdio_dev *dev, + unsigned int reg, unsigned int *val) +{ + struct spi_transaction_dev *spi_tran_dev = + dev->sub_dev; + + if (!spi_tran_dev) + return -ENODEV; + + return spi_transaction_read(spi_tran_dev, + reg, 4, (unsigned char *)val); +} + +int altera_mdio_read(struct altera_mdio_dev *dev, u32 dev_addr, + u32 port_addr, u32 reg, u32 *value) +{ + int ret; + struct altera_mdio_addr mdio_addr = {.csr = 0}; + + if (!dev) + return -ENODEV; + + mdio_addr.devad = dev_addr; + mdio_addr.prtad = port_addr; + mdio_addr.regad = reg; + + dev_debug(dev, "%s reg=0x%x, dev:%x, port:%x, reg:0x%x\n", __func__, + mdio_addr.csr, dev_addr, port_addr, reg); + + ret = max10_reg_write(dev->start + ALTERA_MDIO_ADDRESS_OFST, + mdio_addr.csr); + if (ret) + return -EIO; + + return max10_mdio_reg_read(dev, dev->start + ALTERA_MDIO_DATA_OFST, + value); +} + +int altera_mdio_write(struct altera_mdio_dev *dev, u32 dev_addr, + u32 port_addr, u32 reg, u32 value) +{ + int ret; + struct altera_mdio_addr mdio_addr = {.csr = 0}; + + if (!dev) + return -ENODEV; + + mdio_addr.devad = dev_addr; + mdio_addr.prtad = port_addr; + mdio_addr.regad = reg; + + ret = max10_reg_write(dev->start + ALTERA_MDIO_ADDRESS_OFST, + mdio_addr.csr); + if (ret) + return -EIO; + + return max10_reg_write(dev->start + ALTERA_MDIO_DATA_OFST, + value); +} + +int pkvl_reg_read(struct altera_mdio_dev *dev, u32 dev_addr, + u32 reg, u32 *val) +{ + int port_id = dev->port_id; + + if (port_id < 0) + return -ENODEV; + + return altera_mdio_read(dev, dev_addr, port_id, reg, val); +} + +int pkvl_reg_write(struct altera_mdio_dev *dev, u32 dev_addr, + u32 reg, u32 val) +{ + int port_id = dev->port_id; + + if (port_id < 0) + return -ENODEV; + + return altera_mdio_write(dev, dev_addr, port_id, reg, val); +} + +static int pkvl_reg_set_mask(struct altera_mdio_dev *dev, u32 dev_addr, + u32 reg, u32 mask, u32 val) +{ + int ret; + u32 v; + + ret = pkvl_reg_read(dev, dev_addr, reg, &v); + if (ret) + return -EIO; + + v = (v&~mask) | (val & mask); + + return pkvl_reg_write(dev, dev_addr, reg, v); +} + +static int get_phy_package_id(struct altera_mdio_dev *dev, + int addr, int dev_addr, int *id) +{ + int ret; + u32 val = 0; + + ret = altera_mdio_read(dev, dev_addr, addr, MDIO_DEVS2, &val); + if (ret) + return -EIO; + + *id = (val & 0xffff) << 16; + + ret = altera_mdio_read(dev, dev_addr, addr, MDIO_DEVS1, &val); + if (ret) + return -EIO; + + *id |= (val & 0xffff); + + return 0; +} + +static int get_phy_device_id(struct altera_mdio_dev *dev, + int addr, int dev_addr, int *id) +{ + int ret; + u32 val = 0; + + ret = altera_mdio_read(dev, dev_addr, addr, MDIO_PHYSID1, &val); + if (ret) + return -EIO; + + *id = (val & 0xffff) << 16; + + ret = altera_mdio_read(dev, dev_addr, addr, MDIO_PHYSID2, &val); + if (ret) + return -EIO; + + *id |= (val & 0xffff); + + return 0; +} + +static int get_phy_c45_ids(struct altera_mdio_dev *dev, + int addr, int *phy_id, int *device_id) +{ + int i; + int ret; + int id; + + for (i = 1; i < MAX_NUM_IDS; i++) { + ret = get_phy_package_id(dev, addr, i, phy_id); + if (ret) + return -EIO; + + if ((*phy_id & 0x1fffffff) != 0x1fffffff) + break; + } + + ret = get_phy_device_id(dev, addr, 1, &id); + if (ret) + return -EIO; + + *device_id = id; + + return 0; +} + +static int mdio_phy_scan(struct altera_mdio_dev *dev, int *port_id, + int *phy_id, int *device_id) +{ + int i; + int ret; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + ret = get_phy_c45_ids(dev, i, phy_id, device_id); + if (ret) + return -EIO; + + if ((*phy_id & 0x1fffffff) != 0x1fffffff) { + *port_id = i; + break; + } + } + + return 0; +} + +#define PKVL_READ pkvl_reg_read +#define PKVL_WRITE pkvl_reg_write +#define PKVL_SET_MASK pkvl_reg_set_mask + +static int pkvl_check_smbus_cmd(struct altera_mdio_dev *dev) +{ + int retry = 0; + u32 val; + + for (retry = 0; retry < 10; retry++) { + PKVL_READ(dev, 31, 0xf443, &val); + if ((val & 0x3) == 0) + break; + opae_udelay(1); + } + + if (val & 0x3) { + dev_err(dev, "pkvl execute indirect smbus cmd fail\n"); + return -EBUSY; + } + + return 0; +} + +static int pkvl_execute_smbus_cmd(struct altera_mdio_dev *dev) +{ + int ret; + + ret = pkvl_check_smbus_cmd(dev); + if (ret) + return ret; + + PKVL_WRITE(dev, 31, 0xf443, 0x1); + + ret = pkvl_check_smbus_cmd(dev); + if (ret) + return ret; + + return 0; +} + +static int pkvl_indirect_smbus_set(struct altera_mdio_dev *dev, + u32 addr, u32 reg, u32 hv, u32 lv, u32 *v) +{ + int ret; + + PKVL_WRITE(dev, 31, 0xf441, 0x21); + PKVL_WRITE(dev, 31, 0xf442, + ((addr & 0xff) << 8) | (reg & 0xff)); + PKVL_WRITE(dev, 31, 0xf445, hv); + PKVL_WRITE(dev, 31, 0xf444, lv); + PKVL_WRITE(dev, 31, 0xf440, 0); + + ret = pkvl_execute_smbus_cmd(dev); + if (ret) + return ret; + + PKVL_READ(dev, 31, 0xf446, v); + PKVL_WRITE(dev, 31, 0xf443, 0); + + return 0; +} + +static int pkvl_serdes_intr_set(struct altera_mdio_dev *dev, + u32 reg, u32 hv, u32 lv) +{ + u32 addr; + u32 v; + int ret; + + addr = (reg & 0xff00) >> 8; + + ret = pkvl_indirect_smbus_set(dev, addr, 0x3, hv, lv, &v); + if (ret) + return ret; + + if ((v & 0x7) != 1) { + dev_err(dev, "%s(0x%x, 0x%x, 0x%x) fail\n", + __func__, reg, hv, lv); + return -EBUSY; + } + + return 0; +} + +#define PKVL_SERDES_SET pkvl_serdes_intr_set + +static int pkvl_set_line_side_mode(struct altera_mdio_dev *dev, + int port, int mode) +{ + u32 val = 0; + + /* check PKVL exist */ + PKVL_READ(dev, 1, 0, &val); + if (val == 0 || val == 0xffff) { + dev_err(dev, "reading reg 0x0 from PKVL fail\n"); + return -ENODEV; + } + + PKVL_WRITE(dev, 31, 0xf003, 0); + PKVL_WRITE(dev, 3, 0x2000 + 0x200*port, + 0x2040); + PKVL_SET_MASK(dev, 7, 0x200*port, 1<<12, 0); + PKVL_SET_MASK(dev, 7, 0x11+0x200*port, + 0xf3a0, 0); + PKVL_SET_MASK(dev, 7, 0x8014+0x200*port, + 0x330, 0); + PKVL_WRITE(dev, 7, 0x12+0x200*port, 0); + PKVL_WRITE(dev, 7, 0x8015+0x200*port, 0); + PKVL_SET_MASK(dev, 3, 0xf0ba, 0x8000 | (0x800<index, port, val); + return 0; +} + +static int pkvl_set_host_side_mode(struct altera_mdio_dev *dev, + int port, int mode) +{ + u32 val = 0; + + PKVL_WRITE(dev, 4, 0x2000 + 0x200 * port, 0x2040); + PKVL_SET_MASK(dev, 7, 0x1000 + 0x200 * port, + 1<<12, 0); + PKVL_SET_MASK(dev, 7, 0x1011 + 0x200 * port, + 0xf3a0, 0); + PKVL_SET_MASK(dev, 7, 0x9014 + 0x200 * port, + 0x330, 0); + PKVL_WRITE(dev, 7, 0x1012 + 0x200 * port, 0); + PKVL_WRITE(dev, 7, 0x9015 + 0x200 * port, 0); + PKVL_SET_MASK(dev, 4, 0xf0ba, 0x8000 | (0x800 << port), + 0x8000); + PKVL_SET_MASK(dev, 4, 0xf0a6, 0x8000 | (0x800 << port), + 0x8000); + PKVL_WRITE(dev, 4, 0xf378, 0); + PKVL_WRITE(dev, 4, 0xf258 + 0x80 * port, 0); + PKVL_WRITE(dev, 4, 0xf259 + 0x80 * port, 0); + PKVL_WRITE(dev, 4, 0xf25a + 0x80 * port, 0); + PKVL_WRITE(dev, 4, 0xf25b + 0x80 * port, 0); + PKVL_SET_MASK(dev, 4, 0xf26f + 0x80 * port, + 3<<14, 0); + PKVL_SET_MASK(dev, 4, 0xf060, 1<<2, 0); + PKVL_WRITE(dev, 4, 0xf053, 0); + PKVL_WRITE(dev, 4, 0xf056, 0); + PKVL_WRITE(dev, 4, 0xf059, 0); + PKVL_WRITE(dev, 7, 0x9200, 0); + PKVL_WRITE(dev, 7, 0x9400, 0); + PKVL_WRITE(dev, 7, 0x9600, 0); + PKVL_WRITE(dev, 4, 0xf0e7, 0); + + if (mode == MXD_10GB) { + PKVL_SET_MASK(dev, 4, 0xf25c + 0x80 * port, + 0x2, 0x2); + PKVL_WRITE(dev, 4, 0xf220 + 0x80 * port, 0x1918); + PKVL_WRITE(dev, 4, 0xf221 + 0x80 * port, 0x1819); + PKVL_WRITE(dev, 4, 0xf230 + 0x80 * port, 0x7); + PKVL_WRITE(dev, 4, 0xf231 + 0x80 * port, 0xaff); + PKVL_WRITE(dev, 4, 0xf232 + 0x80 * port, 0); + PKVL_WRITE(dev, 4, 0xf250 + 0x80 * port, 0x1111); + PKVL_WRITE(dev, 4, 0xf251 + 0x80 * port, 0x1111); + PKVL_SET_MASK(dev, 4, 0xf258 + 0x80 * port, + 0x7, 0x7); + } + + PKVL_SET_MASK(dev, 4, 0xf25c + 0x80 * port, 0x2, 0x2); + PKVL_WRITE(dev, 4, 0xf22b + 0x80 * port, 0x1918); + PKVL_WRITE(dev, 4, 0xf246 + 0x80 * port, 0x4033); + PKVL_WRITE(dev, 4, 0xf247 + 0x80 * port, 0x4820); + PKVL_WRITE(dev, 4, 0xf255 + 0x80 * port, 0x1100); + PKVL_SET_MASK(dev, 4, 0xf259 + 0x80 * port, 0xc0, 0xc0); + + PKVL_SERDES_SET(dev, 0x103 + 0x100 * port, 0x3d, 0x9004); + PKVL_SERDES_SET(dev, 0x103 + 0x100 * port, 0x3d, 0xa002); + PKVL_SERDES_SET(dev, 0x103 + 0x100 * port, 0x3d, 0xb012); + + PKVL_WRITE(dev, 4, 0xf000 + port, 0x8020 | mode); + PKVL_READ(dev, 4, 0xf000 + port, &val); + + dev_info(dev, "PKVL:%d port:%d host side mode:0x%x\n", + dev->index, port, val); + + return 0; +} + +int pkvl_set_speed_mode(struct altera_mdio_dev *dev, int port, int mode) +{ + int ret; + + ret = pkvl_set_line_side_mode(dev, port, mode); + if (ret) + return ret; + + return pkvl_set_host_side_mode(dev, port, mode); +} + +int pkvl_get_port_speed_status(struct altera_mdio_dev *dev, + int port, unsigned int *speed) +{ + int ret; + + ret = pkvl_reg_read(dev, 4, 0xf000 + port, speed); + if (ret) + return ret; + + *speed = *speed & 0x7; + + return 0; +} + +int pkvl_get_port_line_link_status(struct altera_mdio_dev *dev, + int port, unsigned int *link) +{ + int ret; + + ret = pkvl_reg_read(dev, 3, 0xa002 + 0x200 * port, link); + if (ret) + return ret; + + *link = (*link & (1<<2)) ? 1:0; + + return 0; +} + +int pkvl_get_port_host_link_status(struct altera_mdio_dev *dev, + int port, unsigned int *link) +{ + int ret; + + ret = pkvl_reg_read(dev, 4, 0xa002 + 0x200 * port, link); + if (ret) + return ret; + + *link = (*link & (1<<2)) ? 1:0; + + return 0; +} + +static struct altera_mdio_dev *altera_spi_mdio_init(int index, u32 start, + u32 end, void *sub_dev) +{ + struct altera_mdio_dev *dev; + int ret; + int port_id = 0; + int phy_id = 0; + int device_id = 0; + + dev = opae_malloc(sizeof(*dev)); + if (!dev) + return NULL; + + dev->sub_dev = sub_dev; + dev->start = start; + dev->end = end; + dev->port_id = -1; + dev->index = index; + + ret = mdio_phy_scan(dev, &port_id, &phy_id, &device_id); + if (ret) { + dev_err(dev, "Cannot found Phy Device on MIDO Bus\n"); + opae_free(dev); + return NULL; + } + + dev->port_id = port_id; + dev->phy_device_id = device_id; + + dev_info(dev, "Found MDIO Phy Device %d, port_id=%d, phy_id=0x%x, device_id=0x%x\n", + index, port_id, phy_id, device_id); + + return dev; +} + +struct altera_mdio_dev *altera_mdio_probe(int index, u32 start, u32 end, + void *sub_dev) +{ + return altera_spi_mdio_init(index, start, end, sub_dev); +} + +void altera_mdio_release(struct altera_mdio_dev *dev) +{ + if (dev) + opae_free(dev); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_mdio.h b/drivers/raw/ifpga_rawdev/base/opae_mdio.h new file mode 100644 index 0000000..8c868d6 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_mdio.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#ifndef _OPAE_MDIO_H_ +#define _OPAE_MDIO_H_ + +#include "opae_osdep.h" + +/* retimer speed */ +enum retimer_speed { + MXD_1GB = 0, + MXD_2_5GB, + MXD_5GB, + MXD_10GB, + MXD_25GB, + MXD_40GB, + MXD_100GB, + MXD_SPEED_UNKNOWN, +}; + +/* retimer info */ +struct opae_retimer_info { + int num_retimer; + int num_port; + enum retimer_speed support_speed; +}; + +/* retimer status*/ +struct opae_retimer_status { + enum retimer_speed speed; + unsigned int line_link; + unsigned int host_link; +}; + +/** + * read MDIO need about 62us delay, SPI keep + * reading before get valid data, so we let + * SPI master read more than 100 bytes + */ +#define MDIO_READ_DELAY 100 + +/* register offset definition */ +#define ALTERA_MDIO_DATA_OFST 0x80 +#define ALTERA_MDIO_ADDRESS_OFST 0x84 + +struct altera_mdio_dev; + +struct altera_mdio_dev { + void *sub_dev; /* sub dev link to spi tran device*/ + u32 start; /* start address*/ + u32 end; /* end of address */ + int index; + int port_id; + int phy_device_id; +}; + +struct altera_mdio_addr { + union { + unsigned int csr; + struct{ + u8 devad:5; + u8 rsvd1:3; + u8 prtad:5; + u8 rsvd2:3; + u16 regad:16; + }; + }; +}; + +/* function declaration */ +struct altera_mdio_dev *altera_mdio_probe(int index, u32 start, + u32 end, void *sub_dev); +void altera_mdio_release(struct altera_mdio_dev *dev); +int altera_mdio_read(struct altera_mdio_dev *dev, u32 dev_addr, + u32 port_id, u32 reg, u32 *value); +int altera_mdio_write(struct altera_mdio_dev *dev, u32 dev_addr, + u32 port_id, u32 reg, u32 value); +int pkvl_reg_read(struct altera_mdio_dev *dev, u32 dev_addr, + u32 reg, u32 *value); +int pkvl_reg_write(struct altera_mdio_dev *dev, u32 dev_addr, + u32 reg, u32 value); +int pkvl_set_speed_mode(struct altera_mdio_dev *dev, int port, int mode); +int pkvl_get_port_speed_status(struct altera_mdio_dev *dev, + int port, unsigned int *speed); +int pkvl_get_port_line_link_status(struct altera_mdio_dev *dev, + int port, unsigned int *link); +int pkvl_get_port_host_link_status(struct altera_mdio_dev *dev, + int port, unsigned int *link); +#endif /* _OPAE_MDIO_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h index 90f54f7..6fb8f08 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_osdep.h +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -5,6 +5,8 @@ #ifndef _OPAE_OSDEP_H #define _OPAE_OSDEP_H +//#define OPAE_DEBUG + #include #include @@ -35,6 +37,7 @@ struct uuid { #ifndef BIT #define BIT(a) (1UL << (a)) #endif /* BIT */ +#define U64_C(x) x ## ULL #ifndef BIT_ULL #define BIT_ULL(a) (1ULL << (a)) #endif /* BIT_ULL */ @@ -52,12 +55,7 @@ struct uuid { #define dev_err(x, args...) dev_printf(ERR, args) #define dev_info(x, args...) dev_printf(INFO, args) #define dev_warn(x, args...) dev_printf(WARNING, args) - -#ifdef OPAE_DEBUG #define dev_debug(x, args...) dev_printf(DEBUG, args) -#else -#define dev_debug(x, args...) do { } while (0) -#endif #define pr_err(y, args...) dev_err(0, y, ##args) #define pr_warn(y, args...) dev_warn(0, y, ##args) @@ -75,5 +73,8 @@ struct uuid { #define udelay(x) opae_udelay(x) #define msleep(x) opae_udelay(1000 * (x)) #define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) +#define time_after(a, b) ((long)((b) - (a)) < 0) +#define time_before(a, b) time_after(b, a) +#define opae_memset(a, b, c) memset((a), (b), (c)) #endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_phy_group.c b/drivers/raw/ifpga_rawdev/base/opae_phy_group.c new file mode 100644 index 0000000..9234129 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_phy_group.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_phy_group.h" + +static int phy_indirect_wait(struct phy_group_device *dev) +{ + int retry = 0; + u64 val; + + while (!((val = opae_readq(dev->base + PHY_GROUP_STAT)) & + STAT_DATA_VALID)) { + if (retry++ > 1000) + return -EBUSY; + + udelay(1); + } + + return 0; +} + +static void phy_indirect_write(struct phy_group_device *dev, u8 entry, + u16 addr, u32 value) +{ + u64 ctrl; + + ctrl = CMD_RD << CTRL_COMMAND_SHIFT | + (entry & CTRL_PHY_NUM_MASK) << CTRL_PHY_NUM_SHIFT | + (addr & CTRL_PHY_ADDR_MASK) << CTRL_PHY_ADDR_SHIFT | + (value & CTRL_WRITE_DATA_MASK); + + opae_writeq(ctrl, dev->base + PHY_GROUP_CTRL); +} + +static int phy_indirect_read(struct phy_group_device *dev, u8 entry, u16 addr, + u32 *value) +{ + u64 tmp; + u64 ctrl = 0; + + ctrl = CMD_RD << CTRL_COMMAND_SHIFT | + (entry & CTRL_PHY_NUM_MASK) << CTRL_PHY_NUM_SHIFT | + (addr & CTRL_PHY_ADDR_MASK) << CTRL_PHY_ADDR_SHIFT; + opae_writeq(ctrl, dev->base + PHY_GROUP_CTRL); + + if (phy_indirect_wait(dev)) + return -ETIMEDOUT; + + tmp = opae_readq(dev->base + PHY_GROUP_STAT); + *value = tmp & STAT_READ_DATA_MASK; + + return 0; +} + +int phy_group_read_reg(struct phy_group_device *dev, u8 entry, + u16 addr, u32 *value) +{ + return phy_indirect_read(dev, entry, addr, value); +} + +int phy_group_write_reg(struct phy_group_device *dev, u8 entry, + u16 addr, u32 value) +{ + phy_indirect_write(dev, entry, addr, value); + + return 0; +} + +struct phy_group_device *phy_group_probe(void *base) +{ + struct phy_group_device *dev; + + dev = opae_malloc(sizeof(*dev)); + if (!dev) + return NULL; + + dev->base = (u8 *)base; + + dev->info.info = opae_readq(dev->base + PHY_GROUP_INFO); + dev->group_index = dev->info.group_number; + dev->entries = dev->info.num_phys; + dev->speed = dev->info.speed; + dev->entry_size = PHY_GROUP_ENTRY_SIZE; + + return dev; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_phy_group.h b/drivers/raw/ifpga_rawdev/base/opae_phy_group.h new file mode 100644 index 0000000..d4def6d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_phy_group.h @@ -0,0 +1,53 @@ +#ifndef _OPAE_PHY_MAC_H +#define _OPAE_PHY_MAC_H + +#include "opae_osdep.h" + +#define MAX_PHY_GROUP_DEVICES 8 +#define PHY_GROUP_ENTRY_SIZE 0x1000 + +#define PHY_GROUP_INFO 0x8 +#define PHY_GROUP_CTRL 0x10 +#define CTRL_COMMAND_SHIFT 62 +#define CMD_RD 0x1UL +#define CMD_WR 0x2UL +#define CTRL_PHY_NUM_SHIFT 43 +#define CTRL_PHY_NUM_MASK GENMASK_ULL(45, 43) +#define CTRL_RESET BIT_ULL(42) +#define CTRL_PHY_ADDR_SHIFT 32 +#define CTRL_PHY_ADDR_MASK GENMASK_ULL(41, 32) +#define CTRL_WRITE_DATA_MASK GENMASK_ULL(31, 0) +#define PHY_GROUP_STAT 0x18 +#define STAT_DATA_VALID BIT_ULL(32) +#define STAT_READ_DATA_MASK GENMASK_ULL(31, 0) + +struct phy_group_info { + union { + u64 info; + struct { + u8 group_number:8; + u8 num_phys:8; + u8 speed:8; + u8 direction:1; + u64 resvd:39; + }; + }; +}; + +struct phy_group_device { + u8 *base; + struct phy_group_info info; + u32 group_index; + u32 entries; + u32 speed; + u32 entry_size; + u32 flags; +}; + +struct phy_group_device *phy_group_probe(void *base); +int phy_group_write_reg(struct phy_group_device *dev, + u8 entry, u16 addr, u32 value); +int phy_group_read_reg(struct phy_group_device *dev, + u8 entry, u16 addr, u32 *value); + +#endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_spi.c b/drivers/raw/ifpga_rawdev/base/opae_spi.c new file mode 100644 index 0000000..d21aece --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_spi.c @@ -0,0 +1,260 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_spi.h" + +static void spi_indirect_write(struct altera_spi_device *dev, u32 reg, + u32 value) +{ + u64 ctrl; + + opae_writeq(value & WRITE_DATA_MASK, dev->regs + SPI_WRITE); + + ctrl = CTRL_W | (reg >> 2); + opae_writeq(ctrl, dev->regs + SPI_CTRL); +} + +static u32 spi_indirect_read(struct altera_spi_device *dev, u32 reg) +{ + u64 tmp; + u64 ctrl; + u32 value; + + ctrl = CTRL_R | (reg >> 2); + opae_writeq(ctrl, dev->regs + SPI_CTRL); + + /** + * FIXME: Read one more time to avoid HW timing issue. This is + * a short term workaround solution, and must be removed once + * hardware fixing is done. + */ + tmp = opae_readq(dev->regs + SPI_READ); + tmp = opae_readq(dev->regs + SPI_READ); + + value = (u32)tmp; + + return value; +} + +void spi_cs_activate(struct altera_spi_device *dev, unsigned int chip_select) +{ + spi_indirect_write(dev, ALTERA_SPI_SLAVE_SEL, 1 << chip_select); + spi_indirect_write(dev, ALTERA_SPI_CONTROL, ALTERA_SPI_CONTROL_SSO_MSK); +} + +void spi_cs_deactivate(struct altera_spi_device *dev) +{ + spi_indirect_write(dev, ALTERA_SPI_CONTROL, 0); +} + +static void spi_flush_rx(struct altera_spi_device *dev) +{ + if (spi_indirect_read(dev, ALTERA_SPI_STATUS) & + ALTERA_SPI_STATUS_RRDY_MSK) + spi_indirect_read(dev, ALTERA_SPI_RXDATA); +} + +int spi_read(struct altera_spi_device *dev, unsigned int bytes, void *buffer) +{ + char data; + char *rxbuf = buffer; + + if (bytes <= 0 || !rxbuf) + return -EINVAL; + + /* empty read buffer */ + spi_flush_rx(dev); + + while (bytes--) { + while (!(spi_indirect_read(dev, ALTERA_SPI_STATUS) & + ALTERA_SPI_STATUS_RRDY_MSK)) + ; + data = spi_indirect_read(dev, ALTERA_SPI_RXDATA); + if (buffer) + *rxbuf++ = data; + } + + return 0; +} + +int spi_write(struct altera_spi_device *dev, unsigned int bytes, void *buffer) +{ + unsigned char data; + char *txbuf = buffer; + + if (bytes <= 0 || !txbuf) + return -EINVAL; + + while (bytes--) { + while (!(spi_indirect_read(dev, ALTERA_SPI_STATUS) & + ALTERA_SPI_STATUS_TRDY_MSK)) + ; + data = *txbuf++; + spi_indirect_write(dev, ALTERA_SPI_TXDATA, data); + } + + return 0; +} + +static unsigned int spi_write_bytes(struct altera_spi_device *dev, int count) +{ + unsigned int val = 0; + u16 *p16; + u32 *p32; + + if (dev->txbuf) { + switch (dev->data_width) { + case 1: + val = dev->txbuf[count]; + break; + case 2: + p16 = (u16 *)(dev->txbuf + 2*count); + val = *p16; + if (dev->endian == SPI_BIG_ENDIAN) + val = cpu_to_be16(val); + break; + case 4: + p32 = (u32 *)(dev->txbuf + 4*count); + val = *p32; + if (dev->endian == SPI_BIG_ENDIAN) + val = (val); + break; + } + } + + return val; +} + +static void spi_fill_readbuffer(struct altera_spi_device *dev, + unsigned int value, int count) +{ + u16 *p16; + u32 *p32; + + if (dev->rxbuf) { + switch (dev->data_width) { + case 1: + dev->rxbuf[count] = value; + break; + case 2: + p16 = (u16 *)(dev->rxbuf + 2*count); + if (dev->endian == SPI_BIG_ENDIAN) + *p16 = cpu_to_be16((u16)value); + else + *p16 = (u16)value; + break; + case 4: + p32 = (u32 *)(dev->rxbuf + 4*count); + if (dev->endian == SPI_BIG_ENDIAN) + *p32 = cpu_to_be32(value); + else + *p32 = value; + break; + } + } +} + +static int spi_txrx(struct altera_spi_device *dev) +{ + unsigned int count = 0; + unsigned int rxd; + unsigned int tx_data; + unsigned int status; + int retry = 0; + + while (count < dev->len) { + tx_data = spi_write_bytes(dev, count); + spi_indirect_write(dev, ALTERA_SPI_TXDATA, tx_data); + + while (1) { + status = spi_indirect_read(dev, ALTERA_SPI_STATUS); + if (status & ALTERA_SPI_STATUS_RRDY_MSK) + break; + if (retry++ > SPI_MAX_RETRY) { + dev_err(dev, "%s, read timeout\n", __func__); + return -EBUSY; + } + } + + rxd = spi_indirect_read(dev, ALTERA_SPI_RXDATA); + spi_fill_readbuffer(dev, rxd, count); + + count++; + } + + return 0; +} + +int spi_command(struct altera_spi_device *dev, unsigned int chip_select, + unsigned int wlen, void *wdata, + unsigned int rlen, void *rdata) +{ + if (((wlen > 0) && !wdata) || ((rlen > 0) && !rdata)) { + dev_err(dev, "error on spi command checking\n"); + return -EINVAL; + } + + wlen = wlen / dev->data_width; + rlen = rlen / dev->data_width; + + /* flush rx buffer */ + spi_flush_rx(dev); + + // TODO: GET MUTEX LOCK + spi_cs_activate(dev, chip_select); + if (wlen) { + dev->txbuf = wdata; + dev->rxbuf = rdata; + dev->len = wlen; + spi_txrx(dev); + } + if (rlen) { + dev->rxbuf = rdata; + dev->txbuf = NULL; + dev->len = rlen; + spi_txrx(dev); + } + spi_cs_deactivate(dev); + // TODO: RELEASE MUTEX LOCK + return 0; +} + +struct altera_spi_device *altera_spi_init(void *base) +{ + struct altera_spi_device *spi_dev = + opae_malloc(sizeof(struct altera_spi_device)); + + if (!spi_dev) + return NULL; + + spi_dev->regs = base; + + spi_dev->spi_param.info = opae_readq(spi_dev->regs + SPI_CORE_PARAM); + + spi_dev->data_width = spi_dev->spi_param.data_width / 8; + spi_dev->endian = spi_dev->spi_param.endian; + spi_dev->num_chipselect = spi_dev->spi_param.num_chipselect; + dev_info(spi_dev, "spi param: type=%d, data width:%d, endian:%d, clock_polarity=%d, clock=%dMHz, chips=%d, cpha=%d\n", + spi_dev->spi_param.type, + spi_dev->data_width, spi_dev->endian, + spi_dev->spi_param.clock_polarity, + spi_dev->spi_param.clock, + spi_dev->num_chipselect, + spi_dev->spi_param.clock_phase); + + /* clear */ + spi_indirect_write(spi_dev, ALTERA_SPI_CONTROL, 0); + spi_indirect_write(spi_dev, ALTERA_SPI_STATUS, 0); + /* flush rxdata */ + spi_flush_rx(spi_dev); + + return spi_dev; +} + +void altera_spi_release(struct altera_spi_device *dev) +{ + if (dev) + opae_free(dev); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_spi.h b/drivers/raw/ifpga_rawdev/base/opae_spi.h new file mode 100644 index 0000000..d93ff09 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_spi.h @@ -0,0 +1,120 @@ +#ifndef _OPAE_SPI_H +#define _OPAE_SPI_H + +#include "opae_osdep.h" + +#define ALTERA_SPI_RXDATA 0 +#define ALTERA_SPI_TXDATA 4 +#define ALTERA_SPI_STATUS 8 +#define ALTERA_SPI_CONTROL 12 +#define ALTERA_SPI_SLAVE_SEL 20 + +#define ALTERA_SPI_STATUS_ROE_MSK 0x8 +#define ALTERA_SPI_STATUS_TOE_MSK 0x10 +#define ALTERA_SPI_STATUS_TMT_MSK 0x20 +#define ALTERA_SPI_STATUS_TRDY_MSK 0x40 +#define ALTERA_SPI_STATUS_RRDY_MSK 0x80 +#define ALTERA_SPI_STATUS_E_MSK 0x100 + +#define ALTERA_SPI_CONTROL_IROE_MSK 0x8 +#define ALTERA_SPI_CONTROL_ITOE_MSK 0x10 +#define ALTERA_SPI_CONTROL_ITRDY_MSK 0x40 +#define ALTERA_SPI_CONTROL_IRRDY_MSK 0x80 +#define ALTERA_SPI_CONTROL_IE_MSK 0x100 +#define ALTERA_SPI_CONTROL_SSO_MSK 0x400 + +#define SPI_CORE_PARAM 0x8 +#define SPI_CTRL 0x10 +#define CTRL_R BIT_ULL(9) +#define CTRL_W BIT_ULL(8) +#define CTRL_ADDR_MASK GENMASK_ULL(2, 0) +#define SPI_READ 0x18 +#define READ_DATA_VALID BIT_ULL(32) +#define READ_DATA_MASK GENMASK_ULL(31, 0) +#define SPI_WRITE 0x20 +#define WRITE_DATA_MASK GENMASK_ULL(31, 0) + +#define SPI_MAX_RETRY 100000 + +struct spi_core_param { + union { + u64 info; + struct { + u8 type:1; + u8 endian:1; + u8 data_width:6; + u8 num_chipselect:6; + u8 clock_polarity:1; + u8 clock_phase:1; + u8 stages:2; + u8 resvd:4; + u16 clock:10; + u16 peripheral_id:16; + u8 controller_type:1; + u16 resvd1:15; + }; + }; +}; + +struct altera_spi_device { + u8 *regs; + struct spi_core_param spi_param; + int data_width; /* how many bytes for data width */ + int endian; + #define SPI_BIG_ENDIAN 0 + #define SPI_LITTLE_ENDIAN 1 + int num_chipselect; + unsigned char *rxbuf; + unsigned char *txbuf; + unsigned int len; +}; + +#define HEADER_LEN 8 +#define RESPONSE_LEN 4 +#define SPI_TRANSACTION_MAX_LEN 1024 +#define TRAN_SEND_MAX_LEN (SPI_TRANSACTION_MAX_LEN + HEADER_LEN) +#define TRAN_RESP_MAX_LEN SPI_TRANSACTION_MAX_LEN +#define PACKET_SEND_MAX_LEN (2*TRAN_SEND_MAX_LEN + 4) +#define PACKET_RESP_MAX_LEN (2*TRAN_RESP_MAX_LEN + 4) +#define BYTES_SEND_MAX_LEN (2*PACKET_SEND_MAX_LEN) +#define BYTES_RESP_MAX_LEN (2*PACKET_RESP_MAX_LEN) + +struct spi_tran_buffer { + unsigned char tran_send[TRAN_SEND_MAX_LEN]; + unsigned char tran_resp[TRAN_RESP_MAX_LEN]; + unsigned char packet_send[PACKET_SEND_MAX_LEN]; + unsigned char packet_resp[PACKET_RESP_MAX_LEN]; + unsigned char bytes_send[BYTES_SEND_MAX_LEN]; + unsigned char bytes_resp[2*BYTES_RESP_MAX_LEN]; +}; + +struct spi_transaction_dev { + struct altera_spi_device *dev; + int chipselect; + struct spi_tran_buffer *buffer; +}; + +struct spi_tran_header { + u8 trans_type; + u8 reserve; + u16 size; + u32 addr; +}; + +int spi_write(struct altera_spi_device *dev, unsigned int bytes, void *buffer); +int spi_read(struct altera_spi_device *dev, unsigned int bytes, + void *buffer); +int spi_command(struct altera_spi_device *dev, unsigned int chip_select, + unsigned int wlen, void *wdata, unsigned int rlen, void *rdata); +void spi_cs_deactivate(struct altera_spi_device *dev); +void spi_cs_activate(struct altera_spi_device *dev, unsigned int chip_select); +struct altera_spi_device *altera_spi_init(void *base); +void altera_spi_release(struct altera_spi_device *dev); +int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data); +int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data); +struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev, + int chipselect); +void spi_transaction_remove(struct spi_transaction_dev *dev); +#endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c b/drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c new file mode 100644 index 0000000..d781b62 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c @@ -0,0 +1,438 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_spi.h" +#include "ifpga_compat.h" + +/*transaction opcodes*/ +#define SPI_TRAN_SEQ_WRITE 0x04 /* SPI transaction sequential write */ +#define SPI_TRAN_SEQ_READ 0x14 /* SPI transaction sequential read */ +#define SPI_TRAN_NON_SEQ_WRITE 0x00 /* SPI transaction non-sequential write */ +#define SPI_TRAN_NON_SEQ_READ 0x10 /* SPI transaction non-sequential read*/ + +/*specail packet characters*/ +#define SPI_PACKET_SOP 0x7a +#define SPI_PACKET_EOP 0x7b +#define SPI_PACKET_CHANNEL 0x7c +#define SPI_PACKET_ESC 0x7d + +/*special byte characters*/ +#define SPI_BYTE_IDLE 0x4a +#define SPI_BYTE_ESC 0x4d + +#define SPI_REG_BYTES 4 + +#define INIT_SPI_TRAN_HEADER(trans_type, size, address) \ +({ \ + header.trans_type = trans_type; \ + header.reserve = 0; \ + header.size = cpu_to_be16(size); \ + header.addr = cpu_to_be32(addr); \ +}) + +#ifdef OPAE_DEBUG +static void print_buffer(const char *string, void *buffer, int len) +{ + int i; + unsigned char *p = buffer; + + printf("%s print buffer, len=%d\n", string, len); + + for (i = 0; i < len; i++) + printf("%x ", *(p+i)); + printf("\n"); +} +#else +static void print_buffer(const char *string, void *buffer, int len) +{ + UNUSED(string); + UNUSED(buffer); + UNUSED(len); +} +#endif + +static unsigned char xor_20(unsigned char val) +{ + return val^0x20; +} + +static void reorder_phy_data(u8 bits_per_word, + void *buf, unsigned int len) +{ + unsigned int count = len / (bits_per_word/8); + u32 *p; + + if (bits_per_word == 32) { + p = (u32 *)buf; + while (count--) { + *p = cpu_to_be32(*p); + p++; + } + } +} + +enum { + SPI_FOUND_SOP, + SPI_FOUND_EOP, + SPI_NOT_FOUND, +}; + +static int resp_find_sop_eop(unsigned char *resp, unsigned int len, + int flags) +{ + int ret = SPI_NOT_FOUND; + + unsigned char *b = resp; + + /* find SOP */ + if (flags != SPI_FOUND_SOP) { + while (b < resp + len && *b != SPI_PACKET_SOP) + b++; + + if (*b != SPI_PACKET_SOP) + goto done; + + ret = SPI_FOUND_SOP; + } + + /* find EOP */ + while (b < resp + len && *b != SPI_PACKET_EOP) + b++; + + if (*b != SPI_PACKET_EOP) + goto done; + + ret = SPI_FOUND_EOP; + +done: + return ret; +} + +static int byte_to_core_convert(struct spi_transaction_dev *dev, + unsigned int send_len, unsigned char *send_data, + unsigned int resp_len, unsigned char *resp_data, + unsigned int *valid_resp_len) +{ + unsigned int i; + int ret = 0; + unsigned char *send_packet = dev->buffer->bytes_send; + unsigned char *resp_packet = dev->buffer->bytes_resp; + unsigned char *p; + unsigned char current_byte; + unsigned char *tx_buffer; + unsigned int tx_len = 0; + unsigned char *rx_buffer; + unsigned int rx_len = 0; + int retry = 0; + int spi_flags; + unsigned int resp_max_len = 2 * resp_len; + + print_buffer("before bytes:", send_data, send_len); + + p = send_packet; + + for (i = 0; i < send_len; i++) { + current_byte = send_data[i]; + switch (current_byte) { + case SPI_BYTE_IDLE: + *p++ = SPI_BYTE_IDLE; + *p++ = xor_20(current_byte); + break; + case SPI_BYTE_ESC: + *p++ = SPI_BYTE_ESC; + *p++ = xor_20(current_byte); + break; + default: + *p++ = current_byte; + break; + } + } + + print_buffer("before spi:", send_packet, p-send_packet); + + reorder_phy_data(32, send_packet, p - send_packet); + + print_buffer("after order to spi:", send_packet, p-send_packet); + + /* call spi */ + tx_buffer = send_packet; + tx_len = p - send_packet; + rx_buffer = resp_packet; + rx_len = resp_max_len; + spi_flags = SPI_NOT_FOUND; + +read_again: + ret = spi_command(dev->dev, dev->chipselect, tx_len, tx_buffer, + rx_len, rx_buffer); + if (ret) + return -EBUSY; + + print_buffer("read from spi:", rx_buffer, rx_len); + + /* look for SOP firstly*/ + ret = resp_find_sop_eop(rx_buffer, rx_len - 1, spi_flags); + if (ret != SPI_FOUND_EOP) { + tx_buffer = NULL; + tx_len = 0; + if (retry++ > 10) { + dev_err(NULL, "cannot found valid data from SPI\n"); + return -EBUSY; + } + + if (ret == SPI_FOUND_SOP) { + rx_buffer += rx_len; + resp_max_len += rx_len; + } + + spi_flags = ret; + goto read_again; + } + + print_buffer("found valid data:", resp_packet, resp_max_len); + + /* analyze response packet */ + i = 0; + p = resp_data; + while (i < resp_max_len) { + current_byte = resp_packet[i]; + switch (current_byte) { + case SPI_BYTE_IDLE: + i++; + break; + case SPI_BYTE_ESC: + i++; + current_byte = resp_packet[i]; + *p++ = xor_20(current_byte); + i++; + break; + default: + *p++ = current_byte; + i++; + break; + } + } + + /* receive "4a" means the SPI is idle, not valid data */ + *valid_resp_len = p - resp_data; + if (*valid_resp_len == 0) { + dev_err(NULL, "error: repond package without valid data\n"); + return -EINVAL; + } + + return 0; +} + +static int packet_to_byte_conver(struct spi_transaction_dev *dev, + unsigned int send_len, unsigned char *send_buf, + unsigned int resp_len, unsigned char *resp_buf, + unsigned int *valid) +{ + int ret = 0; + unsigned int i; + unsigned char current_byte; + unsigned int resp_max_len; + unsigned char *send_packet = dev->buffer->packet_send; + unsigned char *resp_packet = dev->buffer->packet_resp; + unsigned char *p; + unsigned int valid_resp_len = 0; + + print_buffer("before packet:", send_buf, send_len); + + resp_max_len = 2 * resp_len + 4; + + p = send_packet; + + /* SOP header */ + *p++ = SPI_PACKET_SOP; + + *p++ = SPI_PACKET_CHANNEL; + *p++ = 0; + + /* append the data into a packet */ + for (i = 0; i < send_len; i++) { + current_byte = send_buf[i]; + + /* EOP for last byte */ + if (i == send_len - 1) + *p++ = SPI_PACKET_EOP; + + switch (current_byte) { + case SPI_PACKET_SOP: + case SPI_PACKET_EOP: + case SPI_PACKET_CHANNEL: + case SPI_PACKET_ESC: + *p++ = SPI_PACKET_ESC; + *p++ = xor_20(current_byte); + break; + default: + *p++ = current_byte; + } + } + + ret = byte_to_core_convert(dev, p - send_packet, + send_packet, resp_max_len, resp_packet, + &valid_resp_len); + if (ret) + return -EBUSY; + + print_buffer("after byte conver:", resp_packet, valid_resp_len); + + /* analyze the response packet */ + p = resp_buf; + + /* look for SOP */ + for (i = 0; i < valid_resp_len; i++) { + if (resp_packet[i] == SPI_PACKET_SOP) + break; + } + + if (i == valid_resp_len) { + dev_err(NULL, "error on analyze response packet 0x%x\n", + resp_packet[i]); + return -EINVAL; + } + + i++; + + /* continue parsing data after SOP */ + while (i < valid_resp_len) { + current_byte = resp_packet[i]; + + switch (current_byte) { + case SPI_PACKET_ESC: + case SPI_PACKET_CHANNEL: + case SPI_PACKET_SOP: + i++; + current_byte = resp_packet[i]; + *p++ = xor_20(current_byte); + i++; + break; + case SPI_PACKET_EOP: + i++; + current_byte = resp_packet[i]; + if (current_byte == SPI_PACKET_ESC || + current_byte == SPI_PACKET_CHANNEL || + current_byte == SPI_PACKET_SOP) { + i++; + current_byte = resp_packet[i]; + *p++ = xor_20(current_byte); + } else + *p++ = current_byte; + i = valid_resp_len; + break; + default: + *p++ = current_byte; + i++; + } + + } + + *valid = p - resp_buf; + + print_buffer("after packet:", resp_buf, *valid); + + return ret; +} + +static int do_transaction(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data, + unsigned int trans_type) +{ + + struct spi_tran_header header; + unsigned char *transaction = dev->buffer->tran_send; + unsigned char *response = dev->buffer->tran_resp; + unsigned char *p; + int ret = 0; + unsigned int i; + unsigned int valid_len = 0; + + /* make transacation header */ + INIT_SPI_TRAN_HEADER(trans_type, size, addr); + + /* fill the header */ + p = transaction; + opae_memcpy(p, &header, sizeof(struct spi_tran_header)); + p = p + sizeof(struct spi_tran_header); + + switch (trans_type) { + case SPI_TRAN_SEQ_WRITE: + case SPI_TRAN_NON_SEQ_WRITE: + for (i = 0; i < size; i++) + *p++ = *data++; + + ret = packet_to_byte_conver(dev, size + HEADER_LEN, + transaction, RESPONSE_LEN, response, + &valid_len); + if (ret) + return -EBUSY; + + /* check the result */ + if (size != ((unsigned int)(response[2] & 0xff) << 8 | + (unsigned int)(response[3] & 0xff))) + ret = -EBUSY; + + break; + case SPI_TRAN_SEQ_READ: + case SPI_TRAN_NON_SEQ_READ: + ret = packet_to_byte_conver(dev, HEADER_LEN, + transaction, size, response, + &valid_len); + if (ret || valid_len != size) + return -EBUSY; + + for (i = 0; i < size; i++) + *data++ = *response++; + + ret = 0; + break; + } + + return ret; +} + +int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data) +{ + return do_transaction(dev, addr, size, data, + (size > SPI_REG_BYTES) ? + SPI_TRAN_SEQ_READ : SPI_TRAN_NON_SEQ_READ); +} + +int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data) +{ + return do_transaction(dev, addr, size, data, + (size > SPI_REG_BYTES) ? + SPI_TRAN_SEQ_WRITE : SPI_TRAN_NON_SEQ_WRITE); +} + +struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev, + int chipselect) +{ + struct spi_transaction_dev *spi_tran_dev; + + spi_tran_dev = opae_malloc(sizeof(struct spi_transaction_dev)); + if (!spi_tran_dev) + return NULL; + + spi_tran_dev->dev = dev; + spi_tran_dev->chipselect = chipselect; + + spi_tran_dev->buffer = opae_malloc(sizeof(struct spi_tran_buffer)); + if (!spi_tran_dev->buffer) { + opae_free(spi_tran_dev); + return NULL; + } + + return spi_tran_dev; +} + +void spi_transaction_remove(struct spi_transaction_dev *dev) +{ + if (dev && dev->buffer) + opae_free(dev->buffer); + if (dev) + opae_free(dev); +} diff --git a/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h index 895a1d8..6769109 100644 --- a/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -71,5 +71,6 @@ static inline void opae_writeq(uint64_t value, volatile void *addr) } #define opae_free(addr) free(addr) +#define opae_memcpy(a, b, c) memcpy((a), (b), (c)) #endif diff --git a/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h index 76902e2..cd5b7c9 100644 --- a/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #define dev_printf(level, fmt, args...) \ RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) @@ -42,4 +44,12 @@ #define spinlock_lock(x) rte_spinlock_lock(x) #define spinlock_unlock(x) rte_spinlock_unlock(x) +#define cpu_to_be16(o) rte_cpu_to_be_16(o) +#define cpu_to_be32(o) rte_cpu_to_be_32(o) +#define cpu_to_be64(o) rte_cpu_to_be_64(o) +#define cpu_to_le16(o) rte_cpu_to_le_16(o) +#define cpu_to_le32(o) rte_cpu_to_le_32(o) +#define cpu_to_le64(o) rte_cpu_to_le_64(o) + +#define opae_memcpy(a, b, c) rte_memcpy((a), (b), (c)) #endif -- 1.8.3.1