[PATCH] PCI:tegra:Correct typo for PCIe endpoint mode in Tegra194
In config PCIE_TEGRA194_EP the mode incorrectly referred to host mode. Signed-off-by: Wesley Sheng --- drivers/pci/controller/dwc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 044a3761c44f..6960babe6161 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -273,7 +273,7 @@ config PCIE_TEGRA194_EP select PCIE_TEGRA194 help Enables support for the PCIe controller in the NVIDIA Tegra194 SoC to - work in host mode. There are two instances of PCIe controllers in + work in endpoint mode. There are two instances of PCIe controllers in Tegra194. This controller can work either as EP or RC. In order to enable host-specific features PCIE_TEGRA194_HOST must be selected and in order to enable device-specific features PCIE_TEGRA194_EP must be -- 2.16.2
[PATCH] iommu/amd: Add prefetch iommu pages command build function
Add function to build prefetch iommu pages command Signed-off-by: Wesley Sheng --- drivers/iommu/amd/amd_iommu_types.h | 2 ++ drivers/iommu/amd/iommu.c | 19 +++ 2 files changed, 21 insertions(+) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index baa31cd2411c..73734a0c4679 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -173,6 +173,7 @@ #define CMD_INV_IOMMU_PAGES0x03 #define CMD_INV_IOTLB_PAGES0x04 #define CMD_INV_IRT0x05 +#define CMD_PF_IOMMU_PAGES 0x06 #define CMD_COMPLETE_PPR 0x07 #define CMD_INV_ALL0x08 @@ -181,6 +182,7 @@ #define CMD_INV_IOMMU_PAGES_SIZE_MASK 0x01 #define CMD_INV_IOMMU_PAGES_PDE_MASK 0x02 #define CMD_INV_IOMMU_PAGES_GN_MASK0x04 +#define CMD_PF_IOMMU_PAGES_INV_MASK0x10 #define PPR_STATUS_MASK0xf #define PPR_STATUS_SHIFT 12 diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index ba9f3dbc5b94..b3971595b0e9 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -976,6 +976,25 @@ static void build_inv_irt(struct iommu_cmd *cmd, u16 devid) CMD_SET_TYPE(cmd, CMD_INV_IRT); } +static void build_pf_iommu_pages(struct iommu_cmd *cmd, u64 address, + u16 devid, int pfcnt, bool size, + bool inv) +{ + memset(cmd, 0, sizeof(*cmd)); + + address &= PAGE_MASK; + + cmd->data[0] = devid; + cmd->data[0] |= (pfcnt & 0xff) << 24; + cmd->data[2] = lower_32_bits(address); + cmd->data[3] = upper_32_bits(address); + if (size) + cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; + if (inv) + cmd->data[2] |= CMD_PF_IOMMU_PAGES_INV_MASK; + CMD_SET_TYPE(cmd, CMD_PF_IOMMU_PAGES); +} + /* * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. -- 2.16.2
[PATCH] iommu/amd: Add prefetch iommu pages command build function
Add function to build prefetch iommu pages command Signed-off-by: Wesley Sheng --- drivers/iommu/amd/amd_iommu_types.h | 2 ++ drivers/iommu/amd/iommu.c | 19 +++ 2 files changed, 21 insertions(+) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index baa31cd2411c..73734a0c4679 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -173,6 +173,7 @@ #define CMD_INV_IOMMU_PAGES0x03 #define CMD_INV_IOTLB_PAGES0x04 #define CMD_INV_IRT0x05 +#define CMD_PF_IOMMU_PAGES 0x06 #define CMD_COMPLETE_PPR 0x07 #define CMD_INV_ALL0x08 @@ -181,6 +182,7 @@ #define CMD_INV_IOMMU_PAGES_SIZE_MASK 0x01 #define CMD_INV_IOMMU_PAGES_PDE_MASK 0x02 #define CMD_INV_IOMMU_PAGES_GN_MASK0x04 +#define CMD_PF_IOMMU_PAGES_INV_MASK0x10 #define PPR_STATUS_MASK0xf #define PPR_STATUS_SHIFT 12 diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index ba9f3dbc5b94..b3971595b0e9 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -976,6 +976,25 @@ static void build_inv_irt(struct iommu_cmd *cmd, u16 devid) CMD_SET_TYPE(cmd, CMD_INV_IRT); } +static void build_pf_iommu_pages(struct iommu_cmd *cmd, u64 address, + u16 devid, int pfcnt, bool size, + bool inv) +{ + memset(cmd, 0, sizeof(*cmd)); + + address &= PAGE_MASK; + + cmd->data[0] = devid; + cmd->data[0] |= (pfcnt & 0xff) << 24; + cmd->data[2] = lower_32_bits(address); + cmd->data[3] = upper_32_bits(address; + if (size) + cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; + if (inv) + cmd->data[2] |= CMD_PF_IOMMU_PAGES_INV_MASK; + CMD_SET_TYPE(cmd, CMD_PF_IOMMU_PAGES); +} + /* * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. -- 2.16.2
[PATCH 1/2] iommu/amd: Unify reserved member naming convention in struct
Unify reserved member naming convention to rsvd_x in struct Signed-off-by: Wesley Sheng --- drivers/iommu/amd/amd_iommu_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 30a5d412255a..e5b05a97eb46 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -841,7 +841,7 @@ union irte_ga_lo { no_fault: 1, /* -- */ ga_log_intr : 1, - rsvd1 : 3, + rsvd_1 : 3, is_run : 1, /* -- */ guest_mode : 1, -- 2.16.2
[PATCH 2/2] iommu/amd: Revise ga_tag member in struct of fields_remap
Per <> ga_tag member is only available when IRTE[GuestMode]=1, this field should be reserved when IRTE[GuestMode]=0. So change the ga_tag to rsvd_1 in struct of fields_remap. Signed-off-by: Wesley Sheng --- drivers/iommu/amd/amd_iommu_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index e5b05a97eb46..baa31cd2411c 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -832,7 +832,7 @@ union irte_ga_lo { /* -- */ guest_mode : 1, destination : 24, - ga_tag : 32; + rsvd_1 : 32; } fields_remap; /* For guest vAPIC */ -- 2.16.2
[PATCH] NTB: correct ntb_peer_spad_addr and ntb_peer_spad_read comment typos
The comment for ntb_peer_spad_addr and ntb_peer_spad_read incorrectly referred to peer doorbell register and local scratchpad register. Signed-off-by: Wesley Sheng --- include/linux/ntb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/ntb.h b/include/linux/ntb.h index 8c13538aeffe..b9b0d805d0f9 100644 --- a/include/linux/ntb.h +++ b/include/linux/ntb.h @@ -1351,7 +1351,7 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val) * @sidx: Scratchpad index. * @spad_addr: OUT - The address of the peer scratchpad register. * - * Return the address of the peer doorbell register. This may be used, for + * Return the address of the peer scratchpad register. This may be used, for * example, by drivers that offload memory copy operations to a dma engine. * * Return: Zero on success, otherwise an error number. @@ -1373,7 +1373,7 @@ static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx, * * Read the peer scratchpad register, and return the value. * - * Return: The value of the local scratchpad register. + * Return: The value of the peer scratchpad register. */ static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx) { -- 2.16.2
[PATCH] NTB: correct ntb_dev_ops and ntb_dev comment typos
The comment for ntb_dev_ops and ntb_dev incorrectly referred to ntb_ctx_ops and ntb_device. Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- include/linux/ntb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/ntb.h b/include/linux/ntb.h index 56a92e3..604abc8 100644 --- a/include/linux/ntb.h +++ b/include/linux/ntb.h @@ -205,7 +205,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) } /** - * struct ntb_ctx_ops - ntb device operations + * struct ntb_dev_ops - ntb device operations * @port_number: See ntb_port_number(). * @peer_port_count: See ntb_peer_port_count(). * @peer_port_number: See ntb_peer_port_number(). @@ -404,7 +404,7 @@ struct ntb_client { #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv) /** - * struct ntb_device - ntb device + * struct ntb_dev - ntb device * @dev: Linux device object. * @pdev: PCI device entry of the ntb. * @topo: Detected topology of the ntb. -- 2.7.4
[PATCH 1/3] ntb_hw_switchtec: Remove redundant steps of switchtec_ntb_reinit_peer() function
From: Joey Zhang When a re-initialization is caused by a link event, the driver will re-setup the shared memory window. But at that time, the shared memory is still valid, and it's unnecessary to free, reallocate and then initialize it again. We only need to reconfigure the hardware registers. Remove the redundant steps from switchtec_ntb_reinit_peer() function. Signed-off-by: Joey Zhang Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index d905d36..947ed0b 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1457,10 +1457,13 @@ static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) { - dev_info(>stdev->dev, "peer reinitialized\n"); - switchtec_ntb_deinit_shared_mw(sndev); - switchtec_ntb_init_mw(sndev); - return switchtec_ntb_init_shared_mw(sndev); + int rc; + + dev_info(>stdev->dev, "reinitialize shared memory window\n"); + rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, +sndev->self_partition, +sndev->self_shared_dma); + return rc; } static int switchtec_ntb_add(struct device *dev, -- 2.7.4
[PATCH 2/3] ntb_hw_switchtec: Skip unnecessary re-setup of shared memory window for crosslink case
In case of NTB crosslink topology, the setting of shared memory window in the virtual partition doesn't reset on peer's reboot. So skip the unnecessary re-setup of shared memory window for that case. Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 947ed0b..6cf15c18 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1459,6 +1459,9 @@ static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) { int rc; + if (crosslink_is_enabled(sndev)) + return 0; + dev_info(>stdev->dev, "reinitialize shared memory window\n"); rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, sndev->self_partition, -- 2.7.4
[PATCH 3/3] ntb_hw_switchtec: Fix setup MW with failure bug
From: Joey Zhang Switchtec does not support setting multiple MWs simultaneously. The driver takes a hardware lock to ensure that two peers are not doing this simultaneously and it fails if someone else takes the lock. In most cases, this is fine as clients only setup the MWs once on one side of the link. However, there's a race condition when a re-initialization is caused by a link event. The driver will re-setup the shared memory window asynchronously and this races with the client setting up it's memory windows on the link up event. To fix this we ensure do the entire initialization in a work queue and signal the client once it's done. Signed-off-by: Joey Zhang Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 66 -- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 6cf15c18..f9a 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -95,7 +95,8 @@ struct switchtec_ntb { bool link_is_up; enum ntb_speed link_speed; enum ntb_width link_width; - struct work_struct link_reinit_work; + struct work_struct check_link_status_work; + bool link_force_down; }; static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) @@ -494,33 +495,11 @@ enum switchtec_msg { static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); -static void link_reinit_work(struct work_struct *work) -{ - struct switchtec_ntb *sndev; - - sndev = container_of(work, struct switchtec_ntb, link_reinit_work); - - switchtec_ntb_reinit_peer(sndev); -} - -static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, -enum switchtec_msg msg) +static void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev) { int link_sta; int old = sndev->link_is_up; - if (msg == MSG_LINK_FORCE_DOWN) { - schedule_work(>link_reinit_work); - - if (sndev->link_is_up) { - sndev->link_is_up = 0; - ntb_link_event(>ntb); - dev_info(>stdev->dev, "ntb link forced down\n"); - } - - return; - } - link_sta = sndev->self_shared->link_sta; if (link_sta) { u64 peer = ioread64(>peer_shared->magic); @@ -545,6 +524,38 @@ static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, } } +static void check_link_status_work(struct work_struct *work) +{ + struct switchtec_ntb *sndev; + + sndev = container_of(work, struct switchtec_ntb, +check_link_status_work); + + if (sndev->link_force_down) { + sndev->link_force_down = false; + switchtec_ntb_reinit_peer(sndev); + + if (sndev->link_is_up) { + sndev->link_is_up = 0; + ntb_link_event(>ntb); + dev_info(>stdev->dev, "ntb link forced down\n"); + } + + return; + } + + switchtec_ntb_link_status_update(sndev); +} + +static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, + enum switchtec_msg msg) +{ + if (msg == MSG_LINK_FORCE_DOWN) + sndev->link_force_down = true; + + schedule_work(>check_link_status_work); +} + static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) { struct switchtec_ntb *sndev = stdev->sndev; @@ -577,7 +588,7 @@ static int switchtec_ntb_link_enable(struct ntb_dev *ntb, sndev->self_shared->link_sta = 1; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); - switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); + switchtec_ntb_link_status_update(sndev); return 0; } @@ -591,7 +602,7 @@ static int switchtec_ntb_link_disable(struct ntb_dev *ntb) sndev->self_shared->link_sta = 0; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); - switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); + switchtec_ntb_link_status_update(sndev); return 0; } @@ -844,7 +855,8 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) sndev->ntb.topo = NTB_TOPO_SWITCH; sndev->ntb.ops = _ntb_ops; - INIT_WORK(>link_reinit_work, link_reinit_work); + INIT_WORK(>check_link_status_work, check_link_status_work); + sndev->link_force_down = false; sndev->self_partition = sndev->stdev->partition; -- 2.7.4
[PATCH 0/3] Redundant steps removal and bug fix of ntb_hw_switchtec
Hi, Everyone, This patch series remove redundant steps and fix one bug of the ntb_hw_switchtec module. When a re-initialization is caused by a link event, the driver will re-setup the shared memory windows. But at that time, the shared memory is still valid, and it's unnecessary to free, reallocate and then initialize it again. Remove these redundant steps. In case of NTB crosslink topology, the setting of shared memory window in the virtual partition doesn't reset on peer's reboot. So skip the re-setup of shared memory window for that case. Switchtec does not support setting multiple MWs simultaneously. However, there's a race condition when a re-initialization is caused by a link event, the driver will re-setup the shared memory window asynchronously and this races with the client setting up its memory windows on the link up event. Fix this by ensure do the entire initialization in a work queue and signal the client once it's done. Regard, Wesley -- Changed since v1: - It's a resend of v1 -- Joey Zhang (2): ntb_hw_switchtec: Remove redundant steps of switchtec_ntb_reinit_peer() function ntb_hw_switchtec: Fix setup MW with failure bug Wesley Sheng (1): ntb_hw_switchtec: Skip unnecessary re-setup of shared memory window for crosslink case drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 80 +- 1 file changed, 49 insertions(+), 31 deletions(-) -- 2.7.4
[PATCH v2 1/2] switchtec: Fix false maximum supported PCIe function number issue
The hardware supports up to 255 PFFs and the driver only supports 48, so this patch updates the driver to support them all. To be backward compatible, a new ioctl and corresponding data structure are created, while keep the deprecated one. Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 39 +--- include/linux/switchtec.h| 2 +- include/uapi/linux/switchtec_ioctl.h | 13 +++- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index e22766c..7df9a69 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -658,19 +658,25 @@ static int ioctl_flash_part_info(struct switchtec_dev *stdev, static int ioctl_event_summary(struct switchtec_dev *stdev, struct switchtec_user *stuser, - struct switchtec_ioctl_event_summary __user *usum) + struct switchtec_ioctl_event_summary __user *usum, + size_t size) { - struct switchtec_ioctl_event_summary s = {0}; + struct switchtec_ioctl_event_summary *s; int i; u32 reg; + int ret = 0; - s.global = ioread32(>mmio_sw_event->global_summary); - s.part_bitmap = ioread32(>mmio_sw_event->part_event_bitmap); - s.local_part = ioread32(>mmio_part_cfg->part_event_summary); + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->global = ioread32(>mmio_sw_event->global_summary); + s->part_bitmap = ioread32(>mmio_sw_event->part_event_bitmap); + s->local_part = ioread32(>mmio_part_cfg->part_event_summary); for (i = 0; i < stdev->partition_count; i++) { reg = ioread32(>mmio_part_cfg_all[i].part_event_summary); - s.part[i] = reg; + s->part[i] = reg; } for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { @@ -679,15 +685,19 @@ static int ioctl_event_summary(struct switchtec_dev *stdev, break; reg = ioread32(>mmio_pff_csr[i].pff_event_summary); - s.pff[i] = reg; + s->pff[i] = reg; } - if (copy_to_user(usum, , sizeof(s))) - return -EFAULT; + if (copy_to_user(usum, s, size)) { + ret = -EFAULT; + goto error_case; + } stuser->event_cnt = atomic_read(>event_cnt); - return 0; +error_case: + kfree(s); + return ret; } static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev, @@ -977,8 +987,9 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, case SWITCHTEC_IOCTL_FLASH_PART_INFO: rc = ioctl_flash_part_info(stdev, argp); break; - case SWITCHTEC_IOCTL_EVENT_SUMMARY: - rc = ioctl_event_summary(stdev, stuser, argp); + case SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY: + rc = ioctl_event_summary(stdev, stuser, argp, +sizeof(struct switchtec_ioctl_event_summary_legacy)); break; case SWITCHTEC_IOCTL_EVENT_CTL: rc = ioctl_event_ctl(stdev, argp); @@ -989,6 +1000,10 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, case SWITCHTEC_IOCTL_PORT_TO_PFF: rc = ioctl_port_to_pff(stdev, argp); break; + case SWITCHTEC_IOCTL_EVENT_SUMMARY: + rc = ioctl_event_summary(stdev, stuser, argp, +sizeof(struct switchtec_ioctl_event_summary)); + break; default: rc = -ENOTTY; break; diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 52a079b..0cfc34a 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -20,7 +20,7 @@ #include #define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024 -#define SWITCHTEC_MAX_PFF_CSR 48 +#define SWITCHTEC_MAX_PFF_CSR 255 #define SWITCHTEC_EVENT_OCCURRED BIT(0) #define SWITCHTEC_EVENT_CLEARBIT(0) diff --git a/include/uapi/linux/switchtec_ioctl.h b/include/uapi/linux/switchtec_ioctl.h index 4f4daf8..c912b5a 100644 --- a/include/uapi/linux/switchtec_ioctl.h +++ b/include/uapi/linux/switchtec_ioctl.h @@ -50,7 +50,7 @@ struct switchtec_ioctl_flash_part_info { __u32 active; }; -struct switchtec_ioctl_event_summary { +struct switchtec_ioctl_event_summary_legacy { __u64 global; __u64 part_bitmap; __u32 local_part; @@ -59,6 +59,15 @@ struct switchtec_ioctl_event_summary { __u32 pff[48]; }; +struct switchtec_ioctl_event_summary { + __u64 global; + __u64 part_bitmap; + __u32 local_part; + __u32 padding; + __u32 part[48]; + __u32 pff[255]; +}; + #define SWITCHTEC_IOCTL_EVENT_STACK_ERROR 0 #
[PATCH v2 0/2] Fix two bugs of switchtec module
Hi, Everyone, This patch series fix two bugs of switchtec module. The first is introduced by device spec definition issue: the maximum supported PCIe function number by hardware should be 255 instead of the false number of 48. Rectify it in driver and for backward compatible, a new ioctl and corresponding data structure are created, while keep the deprecated one. The second is MRPC event unintentionally masked at corner case. Fix this bug by skipping the mask operation for MRPC event in event ISR like what we already do for LINK event. Regard, Wesley -- Changed since v1: - rewrapped the commit message of [PATCH 1/2] into one paragraph -- Wesley Sheng (2): switchtec: Fix false maximum supported PCIe function number issue switchtec: Fix unintended mask of MRPC event drivers/pci/switch/switchtec.c | 42 +--- include/linux/switchtec.h| 2 +- include/uapi/linux/switchtec_ioctl.h | 13 ++- 3 files changed, 42 insertions(+), 15 deletions(-) -- 2.7.4
[PATCH v2 2/2] switchtec: Fix unintended mask of MRPC event
When running application tool switchtec-user's `firmware update` and `event wait` commands concurrently, sometimes the firmware update speed reduced evidently. It is because when the MRPC event happened right after MRPC event occurrence check but before event mask loop reach to its header register in event ISR, the MRPC event would be masked unintentionally. Since there's no chance to enable it again except for a module reload, all the following MRPC execution completion check will be deferred to timeout. Fix this bug by skipping the mask operation for MRPC event in event ISR, same as what we already do for LINK event. Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver") Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 7df9a69..30f6e08 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1177,7 +1177,8 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx) if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ)) return 0; - if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE) + if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE || + eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP) return 0; dev_dbg(>dev, "%s: %d %d %x\n", __func__, eid, idx, hdr); -- 2.7.4
[PATCH 1/3] ntb_hw_switchtec: Remove redundant steps of switchtec_ntb_reinit_peer() function
From: Joey Zhang When a re-initialization is caused by a link event, the driver will re-setup the shared memory window. But at that time, the shared memory is still valid, and it's unnecessary to free, reallocate and then initialize it again. We only need to reconfigure the hardware registers. Remove the redundant steps from switchtec_ntb_reinit_peer() function. Signed-off-by: Joey Zhang Signed-off-by: Wesley Sheng --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index d905d36..947ed0b 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1457,10 +1457,13 @@ static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) { - dev_info(>stdev->dev, "peer reinitialized\n"); - switchtec_ntb_deinit_shared_mw(sndev); - switchtec_ntb_init_mw(sndev); - return switchtec_ntb_init_shared_mw(sndev); + int rc; + + dev_info(>stdev->dev, "reinitialize shared memory window\n"); + rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, +sndev->self_partition, +sndev->self_shared_dma); + return rc; } static int switchtec_ntb_add(struct device *dev, -- 2.7.4
[PATCH 2/3] ntb_hw_switchtec: Skip unnecessary re-setup of shared memory window for crosslink case
In case of NTB crosslink topology, the setting of shared memory window in the virtual partition doesn't reset on peer's reboot. So skip the unnecessary re-setup of shared memory window for that case. Signed-off-by: Wesley Sheng --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 947ed0b..6cf15c18 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1459,6 +1459,9 @@ static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) { int rc; + if (crosslink_is_enabled(sndev)) + return 0; + dev_info(>stdev->dev, "reinitialize shared memory window\n"); rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, sndev->self_partition, -- 2.7.4
[PATCH 3/3] ntb_hw_switchtec: Fix setup MW with failure bug
From: Joey Zhang Switchtec does not support setting multiple MWs simultaneously. The driver takes a hardware lock to ensure that two peers are not doing this simultaneously and it fails if someone else takes the lock. In most cases, this is fine as clients only setup the MWs once on one side of the link. However, there's a race condition when a re-initialization is caused by a link event. The driver will re-setup the shared memory window asynchronously and this races with the client setting up it's memory windows on the link up event. To fix this we ensure do the entire initialization in a work queue and signal the client once it's done. Signed-off-by: Joey Zhang Signed-off-by: Wesley Sheng --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 66 -- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 6cf15c18..f9a 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -95,7 +95,8 @@ struct switchtec_ntb { bool link_is_up; enum ntb_speed link_speed; enum ntb_width link_width; - struct work_struct link_reinit_work; + struct work_struct check_link_status_work; + bool link_force_down; }; static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) @@ -494,33 +495,11 @@ enum switchtec_msg { static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); -static void link_reinit_work(struct work_struct *work) -{ - struct switchtec_ntb *sndev; - - sndev = container_of(work, struct switchtec_ntb, link_reinit_work); - - switchtec_ntb_reinit_peer(sndev); -} - -static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, -enum switchtec_msg msg) +static void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev) { int link_sta; int old = sndev->link_is_up; - if (msg == MSG_LINK_FORCE_DOWN) { - schedule_work(>link_reinit_work); - - if (sndev->link_is_up) { - sndev->link_is_up = 0; - ntb_link_event(>ntb); - dev_info(>stdev->dev, "ntb link forced down\n"); - } - - return; - } - link_sta = sndev->self_shared->link_sta; if (link_sta) { u64 peer = ioread64(>peer_shared->magic); @@ -545,6 +524,38 @@ static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, } } +static void check_link_status_work(struct work_struct *work) +{ + struct switchtec_ntb *sndev; + + sndev = container_of(work, struct switchtec_ntb, +check_link_status_work); + + if (sndev->link_force_down) { + sndev->link_force_down = false; + switchtec_ntb_reinit_peer(sndev); + + if (sndev->link_is_up) { + sndev->link_is_up = 0; + ntb_link_event(>ntb); + dev_info(>stdev->dev, "ntb link forced down\n"); + } + + return; + } + + switchtec_ntb_link_status_update(sndev); +} + +static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, + enum switchtec_msg msg) +{ + if (msg == MSG_LINK_FORCE_DOWN) + sndev->link_force_down = true; + + schedule_work(>check_link_status_work); +} + static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) { struct switchtec_ntb *sndev = stdev->sndev; @@ -577,7 +588,7 @@ static int switchtec_ntb_link_enable(struct ntb_dev *ntb, sndev->self_shared->link_sta = 1; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); - switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); + switchtec_ntb_link_status_update(sndev); return 0; } @@ -591,7 +602,7 @@ static int switchtec_ntb_link_disable(struct ntb_dev *ntb) sndev->self_shared->link_sta = 0; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); - switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); + switchtec_ntb_link_status_update(sndev); return 0; } @@ -844,7 +855,8 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) sndev->ntb.topo = NTB_TOPO_SWITCH; sndev->ntb.ops = _ntb_ops; - INIT_WORK(>link_reinit_work, link_reinit_work); + INIT_WORK(>check_link_status_work, check_link_status_work); + sndev->link_force_down = false; sndev->self_partition = sndev->stdev->partition; -- 2.7.4
[PATCH 0/3] Redundant steps removal and bug fix of ntb_hw_switchtec
Hi, Everyone, This patch series remove redundant steps and fix one bug of the ntb_hw_switchtec module. When a re-initialization is caused by a link event, the driver will re-setup the shared memory windows. But at that time, the shared memory is still valid, and it's unnecessary to free, reallocate and then initialize it again. Remove these redundant steps. In case of NTB crosslink topology, the setting of shared memory window in the virtual partition doesn't reset on peer's reboot. So skip the re-setup of shared memory window for that case. Switchtec does not support setting multiple MWs simultaneously. However, there's a race condition when a re-initialization is caused by a link event, the driver will re-setup the shared memory window asynchronously and this races with the client setting up its memory windows on the link up event. Fix this by ensure do the entire initialization in a work queue and signal the client once it's done. Regard, Wesley Joey Zhang (2): ntb_hw_switchtec: Remove redundant steps of switchtec_ntb_reinit_peer() function ntb_hw_switchtec: Fix setup MW with failure bug Wesley Sheng (1): ntb_hw_switchtec: Skip unnecessary re-setup of shared memory window for crosslink case drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 80 +- 1 file changed, 49 insertions(+), 31 deletions(-) -- 2.7.4
[PATCH 0/2] Fix two bugs of switchtec module
Hi, Everyone, This patch series fix two bugs of switchtec module. The first is introduced by device spec definition issue: the maximum supported PCIe function number by hardware should be 255 instead of the false number of 48. Rectify it in driver and for backward compatible, a new ioctl and corresponding data structure are created, while keep the deprecated one. The second is MRPC event unintentionally masked at corner case. Fix this bug by skipping the mask operation for MRPC event in event ISR like what we already do for LINK event. Regard, Wesley Wesley Sheng (2): switchtec: Fix false maximum supported PCIe function number issue switchtec: Fix unintended mask of MRPC event drivers/pci/switch/switchtec.c | 42 +--- include/linux/switchtec.h| 2 +- include/uapi/linux/switchtec_ioctl.h | 13 ++- 3 files changed, 42 insertions(+), 15 deletions(-) -- 2.7.4
[PATCH 2/2] switchtec: Fix unintended mask of MRPC event
When running application tool switchtec-user's `firmware update` and `event wait` commands concurrently, sometimes the firmware update speed reduced evidently. It is because when the MRPC event happened right after MRPC event occurrence check but before event mask loop reach to its header register in event ISR, the MRPC event would be masked unintentionally. Since there's no chance to enable it again except for a module reload, all the following MRPC execution completion check will be deferred to timeout. Fix this bug by skipping the mask operation for MRPC event in event ISR, same as what we already do for LINK event. Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver") Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 7df9a69..30f6e08 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1177,7 +1177,8 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx) if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ)) return 0; - if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE) + if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE || + eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP) return 0; dev_dbg(>dev, "%s: %d %d %x\n", __func__, eid, idx, hdr); -- 2.7.4
[PATCH 1/2] switchtec: Fix false maximum supported PCIe function number issue
The hardware supports up to 255 PFFs and the driver only supports 48, so this patch updates the driver to support them all. To be backward compatible, a new ioctl and corresponding data structure are created, while keep the deprecated one. Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 39 +--- include/linux/switchtec.h| 2 +- include/uapi/linux/switchtec_ioctl.h | 13 +++- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index e22766c..7df9a69 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -658,19 +658,25 @@ static int ioctl_flash_part_info(struct switchtec_dev *stdev, static int ioctl_event_summary(struct switchtec_dev *stdev, struct switchtec_user *stuser, - struct switchtec_ioctl_event_summary __user *usum) + struct switchtec_ioctl_event_summary __user *usum, + size_t size) { - struct switchtec_ioctl_event_summary s = {0}; + struct switchtec_ioctl_event_summary *s; int i; u32 reg; + int ret = 0; - s.global = ioread32(>mmio_sw_event->global_summary); - s.part_bitmap = ioread32(>mmio_sw_event->part_event_bitmap); - s.local_part = ioread32(>mmio_part_cfg->part_event_summary); + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->global = ioread32(>mmio_sw_event->global_summary); + s->part_bitmap = ioread32(>mmio_sw_event->part_event_bitmap); + s->local_part = ioread32(>mmio_part_cfg->part_event_summary); for (i = 0; i < stdev->partition_count; i++) { reg = ioread32(>mmio_part_cfg_all[i].part_event_summary); - s.part[i] = reg; + s->part[i] = reg; } for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { @@ -679,15 +685,19 @@ static int ioctl_event_summary(struct switchtec_dev *stdev, break; reg = ioread32(>mmio_pff_csr[i].pff_event_summary); - s.pff[i] = reg; + s->pff[i] = reg; } - if (copy_to_user(usum, , sizeof(s))) - return -EFAULT; + if (copy_to_user(usum, s, size)) { + ret = -EFAULT; + goto error_case; + } stuser->event_cnt = atomic_read(>event_cnt); - return 0; +error_case: + kfree(s); + return ret; } static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev, @@ -977,8 +987,9 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, case SWITCHTEC_IOCTL_FLASH_PART_INFO: rc = ioctl_flash_part_info(stdev, argp); break; - case SWITCHTEC_IOCTL_EVENT_SUMMARY: - rc = ioctl_event_summary(stdev, stuser, argp); + case SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY: + rc = ioctl_event_summary(stdev, stuser, argp, +sizeof(struct switchtec_ioctl_event_summary_legacy)); break; case SWITCHTEC_IOCTL_EVENT_CTL: rc = ioctl_event_ctl(stdev, argp); @@ -989,6 +1000,10 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, case SWITCHTEC_IOCTL_PORT_TO_PFF: rc = ioctl_port_to_pff(stdev, argp); break; + case SWITCHTEC_IOCTL_EVENT_SUMMARY: + rc = ioctl_event_summary(stdev, stuser, argp, +sizeof(struct switchtec_ioctl_event_summary)); + break; default: rc = -ENOTTY; break; diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 52a079b..0cfc34a 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -20,7 +20,7 @@ #include #define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024 -#define SWITCHTEC_MAX_PFF_CSR 48 +#define SWITCHTEC_MAX_PFF_CSR 255 #define SWITCHTEC_EVENT_OCCURRED BIT(0) #define SWITCHTEC_EVENT_CLEARBIT(0) diff --git a/include/uapi/linux/switchtec_ioctl.h b/include/uapi/linux/switchtec_ioctl.h index 4f4daf8..c912b5a 100644 --- a/include/uapi/linux/switchtec_ioctl.h +++ b/include/uapi/linux/switchtec_ioctl.h @@ -50,7 +50,7 @@ struct switchtec_ioctl_flash_part_info { __u32 active; }; -struct switchtec_ioctl_event_summary { +struct switchtec_ioctl_event_summary_legacy { __u64 global; __u64 part_bitmap; __u32 local_part; @@ -59,6 +59,15 @@ struct switchtec_ioctl_event_summary { __u32 pff[48]; }; +struct switchtec_ioctl_event_summary { + __u64 global; + __u64 part_bitmap; + __u32 local_part; + __u32 padding; + __u32 part[48]; + __u32 pff[255]; +}; + #define SWITCHTEC_IOCTL_EVENT_STACK_ERROR 0 #
[PATCH 1/5] switchtec: Remove immediate status check after submit a MRPC command
From: Kelvin Cao After submitting a Firmware Download MRPC command, Switchtec firmware will delay Management EP BAR MemRd TLP responses by more than 10ms. This is a firmware limitation. Delayed MemRd completions are problem for systems with a low Completion Timeout (CTO). The current driver checks the MRPC status immediately after submitting an MRPC command, which results in the MemRd TLP that's affected by the above limitation. Remove the immediate status check and rely on the check after receiving an interrupt or timing out. This is only a software workaround to the READ issue and a proper fix of this should be done in firmware. Fixes: 080b47def5e5 ("MicroSemi Switchtec management interface driver") Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 54a8b30..d2bca2d 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -134,10 +134,6 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser->data, stuser->data_len); iowrite32(stuser->cmd, >mmio_mrpc->cmd); - stuser->status = ioread32(>mmio_mrpc->status); - if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS) - mrpc_complete_cmd(stdev); - schedule_delayed_work(>mrpc_timeout, msecs_to_jiffies(500)); } -- 2.7.4
[PATCH 2/5] switchtec: Set DMA coherent mask in Switchtec driver
From: Boris Glimcher Switchtec hardware supports 64-bit DMA, set the correct DMA mask. This allows the CMA to allocate larger buffers for memory windows. Signed-off-by: Boris Glimcher Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index d2bca2d..480107e 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1237,6 +1237,10 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, if (rc) return rc; + rc = dma_set_coherent_mask(>dev, DMA_BIT_MASK(64)); + if (rc) + return rc; + pci_set_master(pdev); stdev->mmio = pcim_iomap_table(pdev)[0]; -- 2.7.4
[PATCH 4/5] switchtec: Improve MRPC efficiency by leveraging write combining
From: Kelvin Cao MRPC Input buffer is mostly memory without any side effects, thus we can improve the access time by enabling write combining on only this region of the BAR. In a few places, we still need to flush the WC buffer. To do this, we simply read from the Outbound Doorbell register seeing reads to this register are processed by low latency hardware. Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 41 +++-- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index a908670..0b8862b 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -113,6 +113,19 @@ static void stuser_set_state(struct switchtec_user *stuser, static void mrpc_complete_cmd(struct switchtec_dev *stdev); +static void flush_wc_buf(struct switchtec_dev *stdev) +{ + struct ntb_dbmsg_regs __iomem *mmio_dbmsg; + + /* +* odb (outbound doorbell) register is processed by low latency +* hardware and w/o side effect +*/ + mmio_dbmsg = (void __iomem *)stdev->mmio_ntb + + SWITCHTEC_NTB_REG_DBMSG_OFFSET; + ioread32(_dbmsg->odb); +} + static void mrpc_cmd_submit(struct switchtec_dev *stdev) { /* requires the mrpc_mutex to already be held when called */ @@ -132,6 +145,7 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stdev->mrpc_busy = 1; memcpy_toio(>mmio_mrpc->input_data, stuser->data, stuser->data_len); + flush_wc_buf(stdev); iowrite32(stuser->cmd, >mmio_mrpc->cmd); schedule_delayed_work(>mrpc_timeout, @@ -1231,23 +1245,38 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, struct pci_dev *pdev) { int rc; + void __iomem *map; + unsigned long res_start, res_len; rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pcim_iomap_regions(pdev, 0x1, KBUILD_MODNAME); - if (rc) - return rc; - rc = dma_set_coherent_mask(>dev, DMA_BIT_MASK(64)); if (rc) return rc; pci_set_master(pdev); - stdev->mmio = pcim_iomap_table(pdev)[0]; - stdev->mmio_mrpc = stdev->mmio + SWITCHTEC_GAS_MRPC_OFFSET; + res_start = pci_resource_start(pdev, 0); + res_len = pci_resource_len(pdev, 0); + + if (!devm_request_mem_region(>dev, res_start, +res_len, KBUILD_MODNAME)) + return -EBUSY; + + stdev->mmio_mrpc = devm_ioremap_wc(>dev, res_start, + SWITCHTEC_GAS_TOP_CFG_OFFSET); + if (!stdev->mmio_mrpc) + return -ENOMEM; + + map = devm_ioremap(>dev, + res_start + SWITCHTEC_GAS_TOP_CFG_OFFSET, + res_len - SWITCHTEC_GAS_TOP_CFG_OFFSET); + if (!map) + return -ENOMEM; + + stdev->mmio = map - SWITCHTEC_GAS_TOP_CFG_OFFSET; stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET; stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; -- 2.7.4
[PATCH 0/5] Switchtec MRPC DMA mode support
Hi, Everyone, This patch series adds support for the Switchtec MRPC DMA mode. Switchtec switches supports 2 MRPC interaction modes: MRPC normal mode and MRPC DMA mode, a new feature in the latest firmware versions. MRPC normal mode requires the host to read the MRPC command status and output data. In MRPC DMA mode the command status and output data are pushed directly to host memory and issues an interrupt upon completion. The advantage of MRPC DMA mode is avoiding potential high latency response from the Memory Read TLP. Additionally, we've made the following changes: * Improve the efficiency of filling MRPC Input buffer by enabling write combining on MRPC region of BAR * Software workaround for delay responded Memory READ TLPs that access the BAR * And several bug fixes Regards, Wesley -- Changed since v1: - It's a resend of v1 -- Boris Glimcher (1): switchtec: Set DMA coherent mask in Switchtec driver Joey Zhang (1): switchtec: A temporary variable should be used for the flags of switchtec_ioctl_event_ctl Kelvin Cao (2): switchtec: Remove immediate status check after submit a MRPC command switchtec: Improve MRPC efficiency by leveraging write combining Wesley Sheng (1): switchtec: MRPC DMA mode implementation drivers/pci/switch/switchtec.c | 154 - include/linux/switchtec.h | 16 + 2 files changed, 153 insertions(+), 17 deletions(-) -- 2.7.4
[PATCH 5/5] switchtec: MRPC DMA mode implementation
MRPC normal mode requires the host to read the MRPC command status and output data from BAR. This results in high latency responses from the Memory Read TLP and potential Completion Timeout (CTO). MRPC DMA mode implementation includes: Macro definitions for registers and data structures corresponding to MRPC DMA mode. Add module parameter use_dma_mrpc to select between MRPC DMA mode and MRPC normal mode. Add MRPC mode functionality to: * Retrieve MRPC DMA mode version * Allocate DMA buffer, ISR registration, and enable DMA function during initialization * Check MRPC execution status and collect execution results from DMA buffer * Release DMA buffer and disable DMA function when unloading module MRPC DMA mode is a new feature of firmware and the driver will fall back to MRPC normal mode if there is no support in the legacy firmware. Include so that readq/writeq is replaced by two readl/writel on systems that do not support it. Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 108 + include/linux/switchtec.h | 16 ++ 2 files changed, 114 insertions(+), 10 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 0b8862b..6b726cb 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -13,7 +13,7 @@ #include #include #include - +#include #include MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); @@ -25,6 +25,11 @@ static int max_devices = 16; module_param(max_devices, int, 0644); MODULE_PARM_DESC(max_devices, "max number of switchtec device instances"); +static bool use_dma_mrpc = 1; +module_param(use_dma_mrpc, bool, 0644); +MODULE_PARM_DESC(use_dma_mrpc, +"Enable the use of the DMA MRPC feature"); + static dev_t switchtec_devt; static DEFINE_IDA(switchtec_minor_ida); @@ -141,6 +146,11 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, list); + if (stdev->dma_mrpc) { + stdev->dma_mrpc->status = SWITCHTEC_MRPC_STATUS_INPROGRESS; + memset(stdev->dma_mrpc->data, 0xFF, SWITCHTEC_MRPC_PAYLOAD_SIZE); + } + stuser_set_state(stuser, MRPC_RUNNING); stdev->mrpc_busy = 1; memcpy_toio(>mmio_mrpc->input_data, @@ -180,7 +190,11 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, list); - stuser->status = ioread32(>mmio_mrpc->status); + if (stdev->dma_mrpc) + stuser->status = stdev->dma_mrpc->status; + else + stuser->status = ioread32(>mmio_mrpc->status); + if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) return; @@ -190,13 +204,19 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) goto out; - stuser->return_code = ioread32(>mmio_mrpc->ret_value); + if (stdev->dma_mrpc) + stuser->return_code = stdev->dma_mrpc->rtn_code; + else + stuser->return_code = ioread32(>mmio_mrpc->ret_value); if (stuser->return_code != 0) goto out; - memcpy_fromio(stuser->data, >mmio_mrpc->output_data, - stuser->read_len); - + if (stdev->dma_mrpc) + memcpy(stuser->data, >dma_mrpc->data, + stuser->read_len); + else + memcpy_fromio(stuser->data, >mmio_mrpc->output_data, + stuser->read_len); out: complete_all(>comp); list_del_init(>list); @@ -231,7 +251,10 @@ static void mrpc_timeout_work(struct work_struct *work) mutex_lock(>mrpc_mutex); - status = ioread32(>mmio_mrpc->status); + if (stdev->dma_mrpc) + status = stdev->dma_mrpc->status; + else + status = ioread32(>mmio_mrpc->status); if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { schedule_delayed_work(>mrpc_timeout, msecs_to_jiffies(500)); @@ -239,7 +262,6 @@ static void mrpc_timeout_work(struct work_struct *work) } mrpc_complete_cmd(stdev); - out: mutex_unlock(>mrpc_mutex); } @@ -1030,10 +1052,24 @@ static void enable_link_state_events(struct switchtec_dev *stdev) } } +static void enable_dma_mrpc(struct switchtec_dev *stdev) +{ + writeq(stdev->dma_mrpc_dma_addr, >mmio_mrpc->dma_addr); + flush_wc_buf(stdev); + iowrite32(SWITCHTEC_D
[PATCH 3/5] switchtec: A temporary variable should be used for the flags of switchtec_ioctl_event_ctl
From: Joey Zhang For nr_idxs is larger than 1 switchtec_ioctl_event_ctl event flags will be used by each event indexes. In current implementation the event flags are overwritten by first call of the function event_ctl(). Preserve the event flag value with a temporary variable. Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver") Signed-off-by: Joey Zhang Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 480107e..a908670 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -796,6 +796,7 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev, { int ret; int nr_idxs; + unsigned int event_flags; struct switchtec_ioctl_event_ctl ctl; if (copy_from_user(, uctl, sizeof(ctl))) @@ -817,7 +818,9 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev, else return -EINVAL; + event_flags = ctl.flags; for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) { + ctl.flags = event_flags; ret = event_ctl(stdev, ); if (ret < 0) return ret; -- 2.7.4
[PATCH v2 3/3] ntb_hw_switchtec: Added support of >=4G memory windows
From: Paul Selles Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Reported-by: Boris Glimcher Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 9 +++-- include/linux/switchtec.h | 6 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 9916bc5..f6f0035 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -264,6 +264,7 @@ static void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx) ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); iowrite32(0, >bar_entry[bar].win_size); + iowrite32(0, >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition, >bar_entry[bar].xlate_addr); } @@ -286,7 +287,9 @@ static void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (lower_32_bits(size) & 0xF000), + >bar_entry[bar].win_size); + iowrite32(upper_32_bits(size), >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition | addr, >bar_entry[bar].xlate_addr); } @@ -1053,7 +1056,9 @@ static int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (lower_32_bits(size) & 0xF000), + >bar_entry[bar].win_size); + iowrite32(upper_32_bits(size), >bar_ext_entry[bar].win_size); iowrite64(sndev->peer_partition | addr, >bar_entry[bar].xlate_addr); } diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 623719c9..64aa25e 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -243,7 +243,11 @@ struct ntb_ctrl_regs { u32 win_size; u64 xlate_addr; } bar_entry[6]; - u32 reserved2[216]; + struct { + u32 win_size; + u32 reserved[3]; + } bar_ext_entry[6]; + u32 reserved2[192]; u32 req_id_table[512]; u32 reserved3[256]; u64 lut_entry[512]; -- 2.7.4
[PATCH v2 2/3] ntb_hw_switchtec: NT req id mapping table register entry number should be 512
The number of available NT req id mapping table entries per NTB control register is 512. The driver mistakenly limits the number to 256. Fix the array size of NT req id mapping table. Fixes: c082b04c9d40 ("NTB: switchtec: Add NTB hardware register definitions") Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- include/linux/switchtec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index ab400af..623719c9 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -244,8 +244,8 @@ struct ntb_ctrl_regs { u64 xlate_addr; } bar_entry[6]; u32 reserved2[216]; - u32 req_id_table[256]; - u32 reserved3[512]; + u32 req_id_table[512]; + u32 reserved3[256]; u64 lut_entry[512]; } __packed; -- 2.7.4
[PATCH v2 0/3] ntb_hw_switchtec: Added support of >=4G memory windows
Hi, Everyone, This patch series adds support of >=4G memory windows. Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Additionally, we've made the following changes: * debug print 64bit aligned crosslink BAR numbers * Fix the array size of NT req id mapping table Tested with ntb_test.sh successfully based on NTB fixes series from Logan Gunthorpe at https://github.com/sbates130272/linux-p2pmem on branch of ntb_multiport_fixes Regards, Wesley -- Changed since v1: - Using upper_32_bits() and lower_32_bits() marcos makes it easier to read and avoids compiler warning on 32-bit arch - Reorder the patches to make the bug fixes first and add a "Fixes" line to the commit messages -- Paul Selles (2): ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers ntb_hw_switchtec: Added support of >=4G memory windows Wesley Sheng (1): ntb_hw_switchtec: NT req id mapping table register entry number should be 512 drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 11 --- include/linux/switchtec.h | 10 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) -- 2.7.4
[PATCH v2 3/3] ntb_hw_switchtec: Added support of >=4G memory windows
From: Paul Selles Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Reported-by: Boris Glimcher Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 9 +++-- include/linux/switchtec.h | 6 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 9916bc5..f6f0035 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -264,6 +264,7 @@ static void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx) ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); iowrite32(0, >bar_entry[bar].win_size); + iowrite32(0, >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition, >bar_entry[bar].xlate_addr); } @@ -286,7 +287,9 @@ static void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (lower_32_bits(size) & 0xF000), + >bar_entry[bar].win_size); + iowrite32(upper_32_bits(size), >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition | addr, >bar_entry[bar].xlate_addr); } @@ -1053,7 +1056,9 @@ static int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (lower_32_bits(size) & 0xF000), + >bar_entry[bar].win_size); + iowrite32(upper_32_bits(size), >bar_ext_entry[bar].win_size); iowrite64(sndev->peer_partition | addr, >bar_entry[bar].xlate_addr); } diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 623719c9..64aa25e 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -243,7 +243,11 @@ struct ntb_ctrl_regs { u32 win_size; u64 xlate_addr; } bar_entry[6]; - u32 reserved2[216]; + struct { + u32 win_size; + u32 reserved[3]; + } bar_ext_entry[6]; + u32 reserved2[192]; u32 req_id_table[512]; u32 reserved3[256]; u64 lut_entry[512]; -- 2.7.4
[PATCH v2 2/3] ntb_hw_switchtec: NT req id mapping table register entry number should be 512
The number of available NT req id mapping table entries per NTB control register is 512. The driver mistakenly limits the number to 256. Fix the array size of NT req id mapping table. Fixes: c082b04c9d40 ("NTB: switchtec: Add NTB hardware register definitions") Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- include/linux/switchtec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index ab400af..623719c9 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -244,8 +244,8 @@ struct ntb_ctrl_regs { u64 xlate_addr; } bar_entry[6]; u32 reserved2[216]; - u32 req_id_table[256]; - u32 reserved3[512]; + u32 req_id_table[512]; + u32 reserved3[256]; u64 lut_entry[512]; } __packed; -- 2.7.4
[PATCH v2 0/3] ntb_hw_switchtec: Added support of >=4G memory windows
Hi, Everyone, This patch series adds support of >=4G memory windows. Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Additionally, we've made the following changes: * debug print 64bit aligned crosslink BAR numbers * Fix the array size of NT req id mapping table Tested with ntb_test.sh successfully based on NTB fixes series from Logan Gunthorpe at https://github.com/sbates130272/linux-p2pmem on branch of ntb_multiport_fixes Regards, Wesley -- Changed since v1: - Using upper_32_bits() and lower_32_bits() marcos makes it easier to read and avoids compiler warning on 32-bit arch - Reorder the patches to make the bug fixes first and add a "Fixes" line to the commit messages -- Paul Selles (2): ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers ntb_hw_switchtec: Added support of >=4G memory windows Wesley Sheng (1): ntb_hw_switchtec: NT req id mapping table register entry number should be 512 drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 11 --- include/linux/switchtec.h | 10 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) -- 2.7.4
[PATCH v2 1/3] ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers
From: Paul Selles Switchtec NTB crosslink BARs are 64bit addressed but they are printed as 32bit addressed BARs. Fix debug log to increment the BAR numbers by 2 to reflect the 64bit address alignment. Fixes: 017525018202 ("ntb_hw_switchtec: Add initialization code for crosslink") Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 5ee5f40..9916bc5 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1120,7 +1120,7 @@ static int crosslink_enum_partition(struct switchtec_ntb *sndev, dev_dbg(>stdev->dev, "Crosslink BAR%d addr: %llx\n", - i, bar_addr); + i*2, bar_addr); if (bar_addr != bar_space * i) continue; -- 2.7.4
[PATCH v2 1/3] ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers
From: Paul Selles Switchtec NTB crosslink BARs are 64bit addressed but they are printed as 32bit addressed BARs. Fix debug log to increment the BAR numbers by 2 to reflect the 64bit address alignment. Fixes: 017525018202 ("ntb_hw_switchtec: Add initialization code for crosslink") Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng Reviewed-by: Logan Gunthorpe --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 5ee5f40..9916bc5 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1120,7 +1120,7 @@ static int crosslink_enum_partition(struct switchtec_ntb *sndev, dev_dbg(>stdev->dev, "Crosslink BAR%d addr: %llx\n", - i, bar_addr); + i*2, bar_addr); if (bar_addr != bar_space * i) continue; -- 2.7.4
[PATCH 2/3] ntb_hw_switchtec: Added support of >=4G memory windows
From: Paul Selles Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Reported-by: Boris Glimcher Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 9 +++-- include/linux/switchtec.h | 6 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 9916bc5..32850fb 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -264,6 +264,7 @@ static void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx) ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); iowrite32(0, >bar_entry[bar].win_size); + iowrite32(0, >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition, >bar_entry[bar].xlate_addr); } @@ -286,7 +287,9 @@ static void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (size & 0xF000), + >bar_entry[bar].win_size); + iowrite32(size >> 32, >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition | addr, >bar_entry[bar].xlate_addr); } @@ -1053,7 +1056,9 @@ static int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (size & 0xF000), + >bar_entry[bar].win_size); + iowrite32(size >> 32, >bar_ext_entry[bar].win_size); iowrite64(sndev->peer_partition | addr, >bar_entry[bar].xlate_addr); } diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index eee0412..1e6e333 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -248,7 +248,11 @@ struct ntb_ctrl_regs { u32 win_size; u64 xlate_addr; } bar_entry[6]; - u32 reserved2[216]; + struct { + u32 win_size; + u32 reserved[3]; + } bar_ext_entry[6]; + u32 reserved2[192]; u32 req_id_table[256]; u32 reserved3[512]; u64 lut_entry[512]; -- 2.7.4
[PATCH 1/3] ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers
From: Paul Selles Switchtec NTB crosslink BARs are 64bit addressed but they are printed as 32bit addressed BARs. Fix debug log to increment the BAR numbers by 2 to reflect the 64bit address alignment. Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 5ee5f40..9916bc5 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1120,7 +1120,7 @@ static int crosslink_enum_partition(struct switchtec_ntb *sndev, dev_dbg(>stdev->dev, "Crosslink BAR%d addr: %llx\n", - i, bar_addr); + i*2, bar_addr); if (bar_addr != bar_space * i) continue; -- 2.7.4
[PATCH 0/3] ntb_hw_switchtec: Added support of >=4G memory windows
Hi, Everyone, This patch series adds support of >=4G memory windows. Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Additionally, we've made the following changes: * debug print 64bit aligned crosslink BAR numbers * Fix the array size of NT req id mapping table Tested with ntb_test.sh successfully based on NTB fixes series from Logan Gunthorpe at https://github.com/sbates130272/linux-p2pmem on branch of ntb_multiport_fixes Regards, Wesley Paul Selles (2): ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers ntb_hw_switchtec: Added support of >=4G memory windows Wesley Sheng (1): ntb_hw_switchtec: NT req id mapping table register entry number should be 512 drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 11 --- include/linux/switchtec.h | 10 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) -- 2.7.4
[PATCH 3/3] ntb_hw_switchtec: NT req id mapping table register entry number should be 512
The number of available NT req id mapping table entries per NTB control register is 512. The driver mistakenly limits the number to 256. Fix the array size of NT req id mapping table. Signed-off-by: Wesley Sheng --- include/linux/switchtec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 1e6e333..52a079b 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -253,8 +253,8 @@ struct ntb_ctrl_regs { u32 reserved[3]; } bar_ext_entry[6]; u32 reserved2[192]; - u32 req_id_table[256]; - u32 reserved3[512]; + u32 req_id_table[512]; + u32 reserved3[256]; u64 lut_entry[512]; } __packed; -- 2.7.4
[PATCH 2/3] ntb_hw_switchtec: Added support of >=4G memory windows
From: Paul Selles Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Reported-by: Boris Glimcher Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 9 +++-- include/linux/switchtec.h | 6 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 9916bc5..32850fb 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -264,6 +264,7 @@ static void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx) ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); iowrite32(0, >bar_entry[bar].win_size); + iowrite32(0, >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition, >bar_entry[bar].xlate_addr); } @@ -286,7 +287,9 @@ static void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (size & 0xF000), + >bar_entry[bar].win_size); + iowrite32(size >> 32, >bar_ext_entry[bar].win_size); iowrite64(sndev->self_partition | addr, >bar_entry[bar].xlate_addr); } @@ -1053,7 +1056,9 @@ static int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx, ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; iowrite32(ctl_val, >bar_entry[bar].ctl); - iowrite32(xlate_pos | size, >bar_entry[bar].win_size); + iowrite32(xlate_pos | (size & 0xF000), + >bar_entry[bar].win_size); + iowrite32(size >> 32, >bar_ext_entry[bar].win_size); iowrite64(sndev->peer_partition | addr, >bar_entry[bar].xlate_addr); } diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index eee0412..1e6e333 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -248,7 +248,11 @@ struct ntb_ctrl_regs { u32 win_size; u64 xlate_addr; } bar_entry[6]; - u32 reserved2[216]; + struct { + u32 win_size; + u32 reserved[3]; + } bar_ext_entry[6]; + u32 reserved2[192]; u32 req_id_table[256]; u32 reserved3[512]; u64 lut_entry[512]; -- 2.7.4
[PATCH 1/3] ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers
From: Paul Selles Switchtec NTB crosslink BARs are 64bit addressed but they are printed as 32bit addressed BARs. Fix debug log to increment the BAR numbers by 2 to reflect the 64bit address alignment. Signed-off-by: Paul Selles Signed-off-by: Wesley Sheng --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 5ee5f40..9916bc5 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1120,7 +1120,7 @@ static int crosslink_enum_partition(struct switchtec_ntb *sndev, dev_dbg(>stdev->dev, "Crosslink BAR%d addr: %llx\n", - i, bar_addr); + i*2, bar_addr); if (bar_addr != bar_space * i) continue; -- 2.7.4
[PATCH 0/3] ntb_hw_switchtec: Added support of >=4G memory windows
Hi, Everyone, This patch series adds support of >=4G memory windows. Current Switchtec's BAR setup registers are limited to 32bits, corresponding to the maximum MW (memory window) size is <4G. Increase the MW sizes with the addition of the BAR Setup Extension Register for the upper 32bits of a 64bits MW size. This increases the MW range to between 4K and 2^63. Additionally, we've made the following changes: * debug print 64bit aligned crosslink BAR numbers * Fix the array size of NT req id mapping table Tested with ntb_test.sh successfully based on NTB fixes series from Logan Gunthorpe at https://github.com/sbates130272/linux-p2pmem on branch of ntb_multiport_fixes Regards, Wesley Paul Selles (2): ntb_hw_switchtec: debug print 64bit aligned crosslink BAR Numbers ntb_hw_switchtec: Added support of >=4G memory windows Wesley Sheng (1): ntb_hw_switchtec: NT req id mapping table register entry number should be 512 drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 11 --- include/linux/switchtec.h | 10 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) -- 2.7.4
[PATCH 3/3] ntb_hw_switchtec: NT req id mapping table register entry number should be 512
The number of available NT req id mapping table entries per NTB control register is 512. The driver mistakenly limits the number to 256. Fix the array size of NT req id mapping table. Signed-off-by: Wesley Sheng --- include/linux/switchtec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 1e6e333..52a079b 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -253,8 +253,8 @@ struct ntb_ctrl_regs { u32 reserved[3]; } bar_ext_entry[6]; u32 reserved2[192]; - u32 req_id_table[256]; - u32 reserved3[512]; + u32 req_id_table[512]; + u32 reserved3[256]; u64 lut_entry[512]; } __packed; -- 2.7.4
[PATCH 4/5] switchtec: Improve MRPC efficiency by leveraging write combining
From: Kelvin Cao MRPC Input buffer is mostly memory without any side effects, thus we can improve the access time by enabling write combining on only this region of the BAR. In a few places, we still need to flush the WC buffer. To do this, we simply read from the Outbound Doorbell register seeing reads to this register are processed by low latency hardware. Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 41 +++-- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index a908670..0b8862b 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -113,6 +113,19 @@ static void stuser_set_state(struct switchtec_user *stuser, static void mrpc_complete_cmd(struct switchtec_dev *stdev); +static void flush_wc_buf(struct switchtec_dev *stdev) +{ + struct ntb_dbmsg_regs __iomem *mmio_dbmsg; + + /* +* odb (outbound doorbell) register is processed by low latency +* hardware and w/o side effect +*/ + mmio_dbmsg = (void __iomem *)stdev->mmio_ntb + + SWITCHTEC_NTB_REG_DBMSG_OFFSET; + ioread32(_dbmsg->odb); +} + static void mrpc_cmd_submit(struct switchtec_dev *stdev) { /* requires the mrpc_mutex to already be held when called */ @@ -132,6 +145,7 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stdev->mrpc_busy = 1; memcpy_toio(>mmio_mrpc->input_data, stuser->data, stuser->data_len); + flush_wc_buf(stdev); iowrite32(stuser->cmd, >mmio_mrpc->cmd); schedule_delayed_work(>mrpc_timeout, @@ -1231,23 +1245,38 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, struct pci_dev *pdev) { int rc; + void __iomem *map; + unsigned long res_start, res_len; rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pcim_iomap_regions(pdev, 0x1, KBUILD_MODNAME); - if (rc) - return rc; - rc = dma_set_coherent_mask(>dev, DMA_BIT_MASK(64)); if (rc) return rc; pci_set_master(pdev); - stdev->mmio = pcim_iomap_table(pdev)[0]; - stdev->mmio_mrpc = stdev->mmio + SWITCHTEC_GAS_MRPC_OFFSET; + res_start = pci_resource_start(pdev, 0); + res_len = pci_resource_len(pdev, 0); + + if (!devm_request_mem_region(>dev, res_start, +res_len, KBUILD_MODNAME)) + return -EBUSY; + + stdev->mmio_mrpc = devm_ioremap_wc(>dev, res_start, + SWITCHTEC_GAS_TOP_CFG_OFFSET); + if (!stdev->mmio_mrpc) + return -ENOMEM; + + map = devm_ioremap(>dev, + res_start + SWITCHTEC_GAS_TOP_CFG_OFFSET, + res_len - SWITCHTEC_GAS_TOP_CFG_OFFSET); + if (!map) + return -ENOMEM; + + stdev->mmio = map - SWITCHTEC_GAS_TOP_CFG_OFFSET; stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET; stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; -- 2.7.4
[PATCH 5/5] switchtec: MRPC DMA mode implementation
MRPC normal mode requires the host to read the MRPC command status and output data from BAR. This results in high latency responses from the Memory Read TLP and potential Completion Timeout (CTO). MRPC DMA mode implementation includes: Macro definitions for registers and data structures corresponding to MRPC DMA mode. Add module parameter use_dma_mrpc to select between MRPC DMA mode and MRPC normal mode. Add MRPC mode functionality to: * Retrieve MRPC DMA mode version * Allocate DMA buffer, ISR registration, and enable DMA function during initialization * Check MRPC execution status and collect execution results from DMA buffer * Release DMA buffer and disable DMA function when unloading module MRPC DMA mode is a new feature of firmware and the driver will fall back to MRPC normal mode if there is no support in the legacy firmware. Include so that readq/writeq is replaced by two readl/writel on systems that do not support it. Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 108 + include/linux/switchtec.h | 16 ++ 2 files changed, 114 insertions(+), 10 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 0b8862b..6b726cb 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -13,7 +13,7 @@ #include #include #include - +#include #include MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); @@ -25,6 +25,11 @@ static int max_devices = 16; module_param(max_devices, int, 0644); MODULE_PARM_DESC(max_devices, "max number of switchtec device instances"); +static bool use_dma_mrpc = 1; +module_param(use_dma_mrpc, bool, 0644); +MODULE_PARM_DESC(use_dma_mrpc, +"Enable the use of the DMA MRPC feature"); + static dev_t switchtec_devt; static DEFINE_IDA(switchtec_minor_ida); @@ -141,6 +146,11 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, list); + if (stdev->dma_mrpc) { + stdev->dma_mrpc->status = SWITCHTEC_MRPC_STATUS_INPROGRESS; + memset(stdev->dma_mrpc->data, 0xFF, SWITCHTEC_MRPC_PAYLOAD_SIZE); + } + stuser_set_state(stuser, MRPC_RUNNING); stdev->mrpc_busy = 1; memcpy_toio(>mmio_mrpc->input_data, @@ -180,7 +190,11 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, list); - stuser->status = ioread32(>mmio_mrpc->status); + if (stdev->dma_mrpc) + stuser->status = stdev->dma_mrpc->status; + else + stuser->status = ioread32(>mmio_mrpc->status); + if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) return; @@ -190,13 +204,19 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) goto out; - stuser->return_code = ioread32(>mmio_mrpc->ret_value); + if (stdev->dma_mrpc) + stuser->return_code = stdev->dma_mrpc->rtn_code; + else + stuser->return_code = ioread32(>mmio_mrpc->ret_value); if (stuser->return_code != 0) goto out; - memcpy_fromio(stuser->data, >mmio_mrpc->output_data, - stuser->read_len); - + if (stdev->dma_mrpc) + memcpy(stuser->data, >dma_mrpc->data, + stuser->read_len); + else + memcpy_fromio(stuser->data, >mmio_mrpc->output_data, + stuser->read_len); out: complete_all(>comp); list_del_init(>list); @@ -231,7 +251,10 @@ static void mrpc_timeout_work(struct work_struct *work) mutex_lock(>mrpc_mutex); - status = ioread32(>mmio_mrpc->status); + if (stdev->dma_mrpc) + status = stdev->dma_mrpc->status; + else + status = ioread32(>mmio_mrpc->status); if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { schedule_delayed_work(>mrpc_timeout, msecs_to_jiffies(500)); @@ -239,7 +262,6 @@ static void mrpc_timeout_work(struct work_struct *work) } mrpc_complete_cmd(stdev); - out: mutex_unlock(>mrpc_mutex); } @@ -1030,10 +1052,24 @@ static void enable_link_state_events(struct switchtec_dev *stdev) } } +static void enable_dma_mrpc(struct switchtec_dev *stdev) +{ + writeq(stdev->dma_mrpc_dma_addr, >mmio_mrpc->dma_addr); + flush_wc_buf(stdev); + iowrite32(SWITCHTEC_DMA_MRPC_
[PATCH 3/5] switchtec: A temporary variable should be used for the flags of switchtec_ioctl_event_ctl
From: Joey Zhang For nr_idxs is larger than 1 switchtec_ioctl_event_ctl event flags will be used by each event indexes. In current implementation the event flags are overwritten by first call of the function event_ctl(). Preserve the event flag value with a temporary variable. Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver") Signed-off-by: Joey Zhang Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 480107e..a908670 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -796,6 +796,7 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev, { int ret; int nr_idxs; + unsigned int event_flags; struct switchtec_ioctl_event_ctl ctl; if (copy_from_user(, uctl, sizeof(ctl))) @@ -817,7 +818,9 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev, else return -EINVAL; + event_flags = ctl.flags; for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) { + ctl.flags = event_flags; ret = event_ctl(stdev, ); if (ret < 0) return ret; -- 2.7.4
[PATCH 5/5] switchtec: MRPC DMA mode implementation
MRPC normal mode requires the host to read the MRPC command status and output data from BAR. This results in high latency responses from the Memory Read TLP and potential Completion Timeout (CTO). MRPC DMA mode implementation includes: Macro definitions for registers and data structures corresponding to MRPC DMA mode. Add module parameter use_dma_mrpc to select between MRPC DMA mode and MRPC normal mode. Add MRPC mode functionality to: * Retrieve MRPC DMA mode version * Allocate DMA buffer, ISR registration, and enable DMA function during initialization * Check MRPC execution status and collect execution results from DMA buffer * Release DMA buffer and disable DMA function when unloading module MRPC DMA mode is a new feature of firmware and the driver will fall back to MRPC normal mode if there is no support in the legacy firmware. Include so that readq/writeq is replaced by two readl/writel on systems that do not support it. Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 108 + include/linux/switchtec.h | 16 ++ 2 files changed, 114 insertions(+), 10 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 0b8862b..6b726cb 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -13,7 +13,7 @@ #include #include #include - +#include #include MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); @@ -25,6 +25,11 @@ static int max_devices = 16; module_param(max_devices, int, 0644); MODULE_PARM_DESC(max_devices, "max number of switchtec device instances"); +static bool use_dma_mrpc = 1; +module_param(use_dma_mrpc, bool, 0644); +MODULE_PARM_DESC(use_dma_mrpc, +"Enable the use of the DMA MRPC feature"); + static dev_t switchtec_devt; static DEFINE_IDA(switchtec_minor_ida); @@ -141,6 +146,11 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, list); + if (stdev->dma_mrpc) { + stdev->dma_mrpc->status = SWITCHTEC_MRPC_STATUS_INPROGRESS; + memset(stdev->dma_mrpc->data, 0xFF, SWITCHTEC_MRPC_PAYLOAD_SIZE); + } + stuser_set_state(stuser, MRPC_RUNNING); stdev->mrpc_busy = 1; memcpy_toio(>mmio_mrpc->input_data, @@ -180,7 +190,11 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, list); - stuser->status = ioread32(>mmio_mrpc->status); + if (stdev->dma_mrpc) + stuser->status = stdev->dma_mrpc->status; + else + stuser->status = ioread32(>mmio_mrpc->status); + if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) return; @@ -190,13 +204,19 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) goto out; - stuser->return_code = ioread32(>mmio_mrpc->ret_value); + if (stdev->dma_mrpc) + stuser->return_code = stdev->dma_mrpc->rtn_code; + else + stuser->return_code = ioread32(>mmio_mrpc->ret_value); if (stuser->return_code != 0) goto out; - memcpy_fromio(stuser->data, >mmio_mrpc->output_data, - stuser->read_len); - + if (stdev->dma_mrpc) + memcpy(stuser->data, >dma_mrpc->data, + stuser->read_len); + else + memcpy_fromio(stuser->data, >mmio_mrpc->output_data, + stuser->read_len); out: complete_all(>comp); list_del_init(>list); @@ -231,7 +251,10 @@ static void mrpc_timeout_work(struct work_struct *work) mutex_lock(>mrpc_mutex); - status = ioread32(>mmio_mrpc->status); + if (stdev->dma_mrpc) + status = stdev->dma_mrpc->status; + else + status = ioread32(>mmio_mrpc->status); if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { schedule_delayed_work(>mrpc_timeout, msecs_to_jiffies(500)); @@ -239,7 +262,6 @@ static void mrpc_timeout_work(struct work_struct *work) } mrpc_complete_cmd(stdev); - out: mutex_unlock(>mrpc_mutex); } @@ -1030,10 +1052,24 @@ static void enable_link_state_events(struct switchtec_dev *stdev) } } +static void enable_dma_mrpc(struct switchtec_dev *stdev) +{ + writeq(stdev->dma_mrpc_dma_addr, >mmio_mrpc->dma_addr); + flush_wc_buf(stdev); + iowrite32(SWITCHTEC_DMA_MRPC_
[PATCH 3/5] switchtec: A temporary variable should be used for the flags of switchtec_ioctl_event_ctl
From: Joey Zhang For nr_idxs is larger than 1 switchtec_ioctl_event_ctl event flags will be used by each event indexes. In current implementation the event flags are overwritten by first call of the function event_ctl(). Preserve the event flag value with a temporary variable. Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver") Signed-off-by: Joey Zhang Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 480107e..a908670 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -796,6 +796,7 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev, { int ret; int nr_idxs; + unsigned int event_flags; struct switchtec_ioctl_event_ctl ctl; if (copy_from_user(, uctl, sizeof(ctl))) @@ -817,7 +818,9 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev, else return -EINVAL; + event_flags = ctl.flags; for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) { + ctl.flags = event_flags; ret = event_ctl(stdev, ); if (ret < 0) return ret; -- 2.7.4
[PATCH 4/5] switchtec: Improve MRPC efficiency by leveraging write combining
From: Kelvin Cao MRPC Input buffer is mostly memory without any side effects, thus we can improve the access time by enabling write combining on only this region of the BAR. In a few places, we still need to flush the WC buffer. To do this, we simply read from the Outbound Doorbell register seeing reads to this register are processed by low latency hardware. Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 41 +++-- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index a908670..0b8862b 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -113,6 +113,19 @@ static void stuser_set_state(struct switchtec_user *stuser, static void mrpc_complete_cmd(struct switchtec_dev *stdev); +static void flush_wc_buf(struct switchtec_dev *stdev) +{ + struct ntb_dbmsg_regs __iomem *mmio_dbmsg; + + /* +* odb (outbound doorbell) register is processed by low latency +* hardware and w/o side effect +*/ + mmio_dbmsg = (void __iomem *)stdev->mmio_ntb + + SWITCHTEC_NTB_REG_DBMSG_OFFSET; + ioread32(_dbmsg->odb); +} + static void mrpc_cmd_submit(struct switchtec_dev *stdev) { /* requires the mrpc_mutex to already be held when called */ @@ -132,6 +145,7 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stdev->mrpc_busy = 1; memcpy_toio(>mmio_mrpc->input_data, stuser->data, stuser->data_len); + flush_wc_buf(stdev); iowrite32(stuser->cmd, >mmio_mrpc->cmd); schedule_delayed_work(>mrpc_timeout, @@ -1231,23 +1245,38 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, struct pci_dev *pdev) { int rc; + void __iomem *map; + unsigned long res_start, res_len; rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pcim_iomap_regions(pdev, 0x1, KBUILD_MODNAME); - if (rc) - return rc; - rc = dma_set_coherent_mask(>dev, DMA_BIT_MASK(64)); if (rc) return rc; pci_set_master(pdev); - stdev->mmio = pcim_iomap_table(pdev)[0]; - stdev->mmio_mrpc = stdev->mmio + SWITCHTEC_GAS_MRPC_OFFSET; + res_start = pci_resource_start(pdev, 0); + res_len = pci_resource_len(pdev, 0); + + if (!devm_request_mem_region(>dev, res_start, +res_len, KBUILD_MODNAME)) + return -EBUSY; + + stdev->mmio_mrpc = devm_ioremap_wc(>dev, res_start, + SWITCHTEC_GAS_TOP_CFG_OFFSET); + if (!stdev->mmio_mrpc) + return -ENOMEM; + + map = devm_ioremap(>dev, + res_start + SWITCHTEC_GAS_TOP_CFG_OFFSET, + res_len - SWITCHTEC_GAS_TOP_CFG_OFFSET); + if (!map) + return -ENOMEM; + + stdev->mmio = map - SWITCHTEC_GAS_TOP_CFG_OFFSET; stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET; stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; -- 2.7.4
[PATCH 0/5] Switchtec MRPC DMA mode support
Hi, Everyone, This patch series adds support for the Switchtec MRPC DMA mode. Switchtec switches supports 2 MRPC interaction modes: MRPC normal mode and MRPC DMA mode, a new feature in the latest firmware versions. MRPC normal mode requires the host to read the MRPC command status and output data. In MRPC DMA mode the command status and output data are pushed directly to host memory and issues an interrupt upon completion. The advantage of MRPC DMA mode is avoiding potential high latency response from the Memory Read TLP. Additionally, we've made the following changes: * Improve the efficiency of filling MRPC Input buffer by enabling write combining on MRPC region of BAR * Software workaround for delay responded Memory READ TLPs that access the BAR * And several bug fixes Regards, Wesley Boris Glimcher (1): switchtec: Set DMA coherent mask in Switchtec driver Joey Zhang (1): switchtec: A temporary variable should be used for the flags of switchtec_ioctl_event_ctl Kelvin Cao (2): switchtec: Remove immediate status check after submit a MRPC command switchtec: Improve MRPC efficiency by leveraging write combining Wesley Sheng (1): switchtec: MRPC DMA mode implementation drivers/pci/switch/switchtec.c | 154 - include/linux/switchtec.h | 16 + 2 files changed, 153 insertions(+), 17 deletions(-) -- 2.7.4
[PATCH 2/5] switchtec: Set DMA coherent mask in Switchtec driver
From: Boris Glimcher Switchtec hardware supports 64-bit DMA, set the correct DMA mask. This allows the CMA to allocate larger buffers for memory windows. Signed-off-by: Boris Glimcher Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index d2bca2d..480107e 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1237,6 +1237,10 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, if (rc) return rc; + rc = dma_set_coherent_mask(>dev, DMA_BIT_MASK(64)); + if (rc) + return rc; + pci_set_master(pdev); stdev->mmio = pcim_iomap_table(pdev)[0]; -- 2.7.4
[PATCH 0/5] Switchtec MRPC DMA mode support
Hi, Everyone, This patch series adds support for the Switchtec MRPC DMA mode. Switchtec switches supports 2 MRPC interaction modes: MRPC normal mode and MRPC DMA mode, a new feature in the latest firmware versions. MRPC normal mode requires the host to read the MRPC command status and output data. In MRPC DMA mode the command status and output data are pushed directly to host memory and issues an interrupt upon completion. The advantage of MRPC DMA mode is avoiding potential high latency response from the Memory Read TLP. Additionally, we've made the following changes: * Improve the efficiency of filling MRPC Input buffer by enabling write combining on MRPC region of BAR * Software workaround for delay responded Memory READ TLPs that access the BAR * And several bug fixes Regards, Wesley Boris Glimcher (1): switchtec: Set DMA coherent mask in Switchtec driver Joey Zhang (1): switchtec: A temporary variable should be used for the flags of switchtec_ioctl_event_ctl Kelvin Cao (2): switchtec: Remove immediate status check after submit a MRPC command switchtec: Improve MRPC efficiency by leveraging write combining Wesley Sheng (1): switchtec: MRPC DMA mode implementation drivers/pci/switch/switchtec.c | 154 - include/linux/switchtec.h | 16 + 2 files changed, 153 insertions(+), 17 deletions(-) -- 2.7.4
[PATCH 2/5] switchtec: Set DMA coherent mask in Switchtec driver
From: Boris Glimcher Switchtec hardware supports 64-bit DMA, set the correct DMA mask. This allows the CMA to allocate larger buffers for memory windows. Signed-off-by: Boris Glimcher Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index d2bca2d..480107e 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1237,6 +1237,10 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, if (rc) return rc; + rc = dma_set_coherent_mask(>dev, DMA_BIT_MASK(64)); + if (rc) + return rc; + pci_set_master(pdev); stdev->mmio = pcim_iomap_table(pdev)[0]; -- 2.7.4
[PATCH 1/5] switchtec: Remove immediate status check after submit a MRPC command
From: Kelvin Cao After submitting a Firmware Download MRPC command, Switchtec firmware will delay Management EP BAR MemRd TLP responses by more than 10ms. This is a firmware limitation. Delayed MemRd completions are problem for systems with a low Completion Timeout (CTO). The current driver checks the MRPC status immediately after submitting an MRPC command, which results in the MemRd TLP that's affected by the above limitation. Remove the immediate status check and rely on the check after receiving an interrupt or timing out. This is only a software workaround to the READ issue and a proper fix of this should be done in firmware. Fixes: 080b47def5e5 ("MicroSemi Switchtec management interface driver") Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 54a8b30..d2bca2d 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -134,10 +134,6 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser->data, stuser->data_len); iowrite32(stuser->cmd, >mmio_mrpc->cmd); - stuser->status = ioread32(>mmio_mrpc->status); - if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS) - mrpc_complete_cmd(stdev); - schedule_delayed_work(>mrpc_timeout, msecs_to_jiffies(500)); } -- 2.7.4
[PATCH 1/5] switchtec: Remove immediate status check after submit a MRPC command
From: Kelvin Cao After submitting a Firmware Download MRPC command, Switchtec firmware will delay Management EP BAR MemRd TLP responses by more than 10ms. This is a firmware limitation. Delayed MemRd completions are problem for systems with a low Completion Timeout (CTO). The current driver checks the MRPC status immediately after submitting an MRPC command, which results in the MemRd TLP that's affected by the above limitation. Remove the immediate status check and rely on the check after receiving an interrupt or timing out. This is only a software workaround to the READ issue and a proper fix of this should be done in firmware. Fixes: 080b47def5e5 ("MicroSemi Switchtec management interface driver") Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng --- drivers/pci/switch/switchtec.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 54a8b30..d2bca2d 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -134,10 +134,6 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser->data, stuser->data_len); iowrite32(stuser->cmd, >mmio_mrpc->cmd); - stuser->status = ioread32(>mmio_mrpc->status); - if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS) - mrpc_complete_cmd(stdev); - schedule_delayed_work(>mrpc_timeout, msecs_to_jiffies(500)); } -- 2.7.4