提交 84e39eeb 编写于 作者: L Linus Torvalds

Merge tag 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma

Pull second round of rdma updates from Doug Ledford:
 "This can be split out into just two categories:

   - fixes to the RDMA R/W API in regards to SG list length limits
     (about 5 patches)

   - fixes/features for the Intel hfi1 driver (everything else)

  The hfi1 driver is still being brought to full feature support by
  Intel, and they have a lot of people working on it, so that amounts to
  almost the entirety of this pull request"

* tag 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma: (84 commits)
  IB/hfi1: Add cache evict LRU list
  IB/hfi1: Fix memory leak during unexpected shutdown
  IB/hfi1: Remove unneeded mm argument in remove function
  IB/hfi1: Consistently call ops->remove outside spinlock
  IB/hfi1: Use evict mmu rb operation
  IB/hfi1: Add evict operation to the mmu rb handler
  IB/hfi1: Fix TID caching actions
  IB/hfi1: Make the cache handler own its rb tree root
  IB/hfi1: Make use of mm consistent
  IB/hfi1: Fix user SDMA racy user request claim
  IB/hfi1: Fix error condition that needs to clean up
  IB/hfi1: Release node on insert failure
  IB/hfi1: Validate SDMA user iovector count
  IB/hfi1: Validate SDMA user request index
  IB/hfi1: Use the same capability state for all shared contexts
  IB/hfi1: Prevent null pointer dereference
  IB/hfi1: Rename TID mmu_rb_* functions
  IB/hfi1: Remove unneeded empty check in hfi1_mmu_rb_unregister()
  IB/hfi1: Restructure hfi1_file_open
  IB/hfi1: Make iovec loop index easy to understand
  ...
...@@ -58,19 +58,13 @@ static inline bool rdma_rw_io_needs_mr(struct ib_device *dev, u8 port_num, ...@@ -58,19 +58,13 @@ static inline bool rdma_rw_io_needs_mr(struct ib_device *dev, u8 port_num,
return false; return false;
} }
static inline u32 rdma_rw_max_sge(struct ib_device *dev,
enum dma_data_direction dir)
{
return dir == DMA_TO_DEVICE ?
dev->attrs.max_sge : dev->attrs.max_sge_rd;
}
static inline u32 rdma_rw_fr_page_list_len(struct ib_device *dev) static inline u32 rdma_rw_fr_page_list_len(struct ib_device *dev)
{ {
/* arbitrary limit to avoid allocating gigantic resources */ /* arbitrary limit to avoid allocating gigantic resources */
return min_t(u32, dev->attrs.max_fast_reg_page_list_len, 256); return min_t(u32, dev->attrs.max_fast_reg_page_list_len, 256);
} }
/* Caller must have zero-initialized *reg. */
static int rdma_rw_init_one_mr(struct ib_qp *qp, u8 port_num, static int rdma_rw_init_one_mr(struct ib_qp *qp, u8 port_num,
struct rdma_rw_reg_ctx *reg, struct scatterlist *sg, struct rdma_rw_reg_ctx *reg, struct scatterlist *sg,
u32 sg_cnt, u32 offset) u32 sg_cnt, u32 offset)
...@@ -114,6 +108,7 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, ...@@ -114,6 +108,7 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u8 port_num, struct scatterlist *sg, u32 sg_cnt, u32 offset, u8 port_num, struct scatterlist *sg, u32 sg_cnt, u32 offset,
u64 remote_addr, u32 rkey, enum dma_data_direction dir) u64 remote_addr, u32 rkey, enum dma_data_direction dir)
{ {
struct rdma_rw_reg_ctx *prev = NULL;
u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device); u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device);
int i, j, ret = 0, count = 0; int i, j, ret = 0, count = 0;
...@@ -125,7 +120,6 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, ...@@ -125,7 +120,6 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
} }
for (i = 0; i < ctx->nr_ops; i++) { for (i = 0; i < ctx->nr_ops; i++) {
struct rdma_rw_reg_ctx *prev = i ? &ctx->reg[i - 1] : NULL;
struct rdma_rw_reg_ctx *reg = &ctx->reg[i]; struct rdma_rw_reg_ctx *reg = &ctx->reg[i];
u32 nents = min(sg_cnt, pages_per_mr); u32 nents = min(sg_cnt, pages_per_mr);
...@@ -162,9 +156,13 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, ...@@ -162,9 +156,13 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
sg_cnt -= nents; sg_cnt -= nents;
for (j = 0; j < nents; j++) for (j = 0; j < nents; j++)
sg = sg_next(sg); sg = sg_next(sg);
prev = reg;
offset = 0; offset = 0;
} }
if (prev)
prev->wr.wr.next = NULL;
ctx->type = RDMA_RW_MR; ctx->type = RDMA_RW_MR;
return count; return count;
...@@ -181,7 +179,8 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, ...@@ -181,7 +179,8 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u64 remote_addr, u32 rkey, enum dma_data_direction dir) u64 remote_addr, u32 rkey, enum dma_data_direction dir)
{ {
struct ib_device *dev = qp->pd->device; struct ib_device *dev = qp->pd->device;
u32 max_sge = rdma_rw_max_sge(dev, dir); u32 max_sge = dir == DMA_TO_DEVICE ? qp->max_write_sge :
qp->max_read_sge;
struct ib_sge *sge; struct ib_sge *sge;
u32 total_len = 0, i, j; u32 total_len = 0, i, j;
...@@ -205,11 +204,10 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, ...@@ -205,11 +204,10 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
rdma_wr->wr.opcode = IB_WR_RDMA_READ; rdma_wr->wr.opcode = IB_WR_RDMA_READ;
rdma_wr->remote_addr = remote_addr + total_len; rdma_wr->remote_addr = remote_addr + total_len;
rdma_wr->rkey = rkey; rdma_wr->rkey = rkey;
rdma_wr->wr.num_sge = nr_sge;
rdma_wr->wr.sg_list = sge; rdma_wr->wr.sg_list = sge;
for (j = 0; j < nr_sge; j++, sg = sg_next(sg)) { for (j = 0; j < nr_sge; j++, sg = sg_next(sg)) {
rdma_wr->wr.num_sge++;
sge->addr = ib_sg_dma_address(dev, sg) + offset; sge->addr = ib_sg_dma_address(dev, sg) + offset;
sge->length = ib_sg_dma_len(dev, sg) - offset; sge->length = ib_sg_dma_len(dev, sg) - offset;
sge->lkey = qp->pd->local_dma_lkey; sge->lkey = qp->pd->local_dma_lkey;
...@@ -220,8 +218,8 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, ...@@ -220,8 +218,8 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
offset = 0; offset = 0;
} }
if (i + 1 < ctx->nr_ops) rdma_wr->wr.next = i + 1 < ctx->nr_ops ?
rdma_wr->wr.next = &ctx->map.wrs[i + 1].wr; &ctx->map.wrs[i + 1].wr : NULL;
} }
ctx->type = RDMA_RW_MULTI_WR; ctx->type = RDMA_RW_MULTI_WR;
......
...@@ -825,6 +825,15 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, ...@@ -825,6 +825,15 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
} }
} }
/*
* Note: all hw drivers guarantee that max_send_sge is lower than
* the device RDMA WRITE SGE limit but not all hw drivers ensure that
* max_send_sge <= max_sge_rd.
*/
qp->max_write_sge = qp_init_attr->cap.max_send_sge;
qp->max_read_sge = min_t(u32, qp_init_attr->cap.max_send_sge,
device->attrs.max_sge_rd);
return qp; return qp;
} }
EXPORT_SYMBOL(ib_create_qp); EXPORT_SYMBOL(ib_create_qp);
......
config INFINIBAND_HFI1 config INFINIBAND_HFI1
tristate "Intel OPA Gen1 support" tristate "Intel OPA Gen1 support"
depends on X86_64 && INFINIBAND_RDMAVT depends on X86_64 && INFINIBAND_RDMAVT && I2C
select MMU_NOTIFIER select MMU_NOTIFIER
select CRC32 select CRC32
select I2C_ALGOBIT
---help--- ---help---
This is a low-level driver for Intel OPA Gen1 adapter. This is a low-level driver for Intel OPA Gen1 adapter.
config HFI1_DEBUG_SDMA_ORDER config HFI1_DEBUG_SDMA_ORDER
......
...@@ -10,7 +10,7 @@ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o ...@@ -10,7 +10,7 @@ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o
hfi1-y := affinity.o chip.o device.o driver.o efivar.o \ hfi1-y := affinity.o chip.o device.o driver.o efivar.o \
eprom.o file_ops.o firmware.o \ eprom.o file_ops.o firmware.o \
init.o intr.o mad.o mmu_rb.o pcie.o pio.o pio_copy.o platform.o \ init.o intr.o mad.o mmu_rb.o pcie.o pio.o pio_copy.o platform.o \
qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o twsi.o \ qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o \
uc.o ud.o user_exp_rcv.o user_pages.o user_sdma.o verbs.o \ uc.o ud.o user_exp_rcv.o user_pages.o user_sdma.o verbs.o \
verbs_txreq.o verbs_txreq.o
hfi1-$(CONFIG_DEBUG_FS) += debugfs.o hfi1-$(CONFIG_DEBUG_FS) += debugfs.o
......
...@@ -73,7 +73,6 @@ struct cpu_mask_set { ...@@ -73,7 +73,6 @@ struct cpu_mask_set {
struct hfi1_affinity { struct hfi1_affinity {
struct cpu_mask_set def_intr; struct cpu_mask_set def_intr;
struct cpu_mask_set rcv_intr; struct cpu_mask_set rcv_intr;
struct cpu_mask_set proc;
struct cpumask real_cpu_mask; struct cpumask real_cpu_mask;
/* spin lock to protect affinity struct */ /* spin lock to protect affinity struct */
spinlock_t lock; spinlock_t lock;
...@@ -82,11 +81,9 @@ struct hfi1_affinity { ...@@ -82,11 +81,9 @@ struct hfi1_affinity {
struct hfi1_msix_entry; struct hfi1_msix_entry;
/* Initialize non-HT cpu cores mask */ /* Initialize non-HT cpu cores mask */
int init_real_cpu_mask(struct hfi1_devdata *); void init_real_cpu_mask(void);
/* Initialize driver affinity data */ /* Initialize driver affinity data */
void hfi1_dev_affinity_init(struct hfi1_devdata *); int hfi1_dev_affinity_init(struct hfi1_devdata *);
/* Free driver affinity data */
void hfi1_dev_affinity_free(struct hfi1_devdata *);
/* /*
* Set IRQ affinity to a CPU. The function will determine the * Set IRQ affinity to a CPU. The function will determine the
* CPU and set the affinity to it. * CPU and set the affinity to it.
...@@ -101,8 +98,35 @@ void hfi1_put_irq_affinity(struct hfi1_devdata *, struct hfi1_msix_entry *); ...@@ -101,8 +98,35 @@ void hfi1_put_irq_affinity(struct hfi1_devdata *, struct hfi1_msix_entry *);
* Determine a CPU affinity for a user process, if the process does not * Determine a CPU affinity for a user process, if the process does not
* have an affinity set yet. * have an affinity set yet.
*/ */
int hfi1_get_proc_affinity(struct hfi1_devdata *, int); int hfi1_get_proc_affinity(int);
/* Release a CPU used by a user process. */ /* Release a CPU used by a user process. */
void hfi1_put_proc_affinity(struct hfi1_devdata *, int); void hfi1_put_proc_affinity(int);
int hfi1_get_sdma_affinity(struct hfi1_devdata *dd, char *buf);
int hfi1_set_sdma_affinity(struct hfi1_devdata *dd, const char *buf,
size_t count);
struct hfi1_affinity_node {
int node;
struct cpu_mask_set def_intr;
struct cpu_mask_set rcv_intr;
struct cpumask general_intr_mask;
struct list_head list;
};
struct hfi1_affinity_node_list {
struct list_head list;
struct cpumask real_cpu_mask;
struct cpu_mask_set proc;
int num_core_siblings;
int num_online_nodes;
int num_online_cpus;
/* protect affinity node list */
spinlock_t lock;
};
int node_affinity_init(void);
void node_affinity_destroy(void);
extern struct hfi1_affinity_node_list node_affinity;
#endif /* _HFI1_AFFINITY_H */ #endif /* _HFI1_AFFINITY_H */
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
#include "efivar.h" #include "efivar.h"
#include "platform.h" #include "platform.h"
#include "aspm.h" #include "aspm.h"
#include "affinity.h"
#define NUM_IB_PORTS 1 #define NUM_IB_PORTS 1
...@@ -121,6 +122,7 @@ struct flag_table { ...@@ -121,6 +122,7 @@ struct flag_table {
#define SEC_SC_HALTED 0x4 /* per-context only */ #define SEC_SC_HALTED 0x4 /* per-context only */
#define SEC_SPC_FREEZE 0x8 /* per-HFI only */ #define SEC_SPC_FREEZE 0x8 /* per-HFI only */
#define DEFAULT_KRCVQS 2
#define MIN_KERNEL_KCTXTS 2 #define MIN_KERNEL_KCTXTS 2
#define FIRST_KERNEL_KCTXT 1 #define FIRST_KERNEL_KCTXT 1
/* sizes for both the QP and RSM map tables */ /* sizes for both the QP and RSM map tables */
...@@ -238,6 +240,9 @@ struct flag_table { ...@@ -238,6 +240,9 @@ struct flag_table {
/* all CceStatus sub-block RXE pause bits */ /* all CceStatus sub-block RXE pause bits */
#define ALL_RXE_PAUSE CCE_STATUS_RXE_PAUSED_SMASK #define ALL_RXE_PAUSE CCE_STATUS_RXE_PAUSED_SMASK
#define CNTR_MAX 0xFFFFFFFFFFFFFFFFULL
#define CNTR_32BIT_MAX 0x00000000FFFFFFFF
/* /*
* CCE Error flags. * CCE Error flags.
*/ */
...@@ -3947,6 +3952,28 @@ static u64 access_sdma_wrong_dw_err_cnt(const struct cntr_entry *entry, ...@@ -3947,6 +3952,28 @@ static u64 access_sdma_wrong_dw_err_cnt(const struct cntr_entry *entry,
return dd->sw_send_dma_eng_err_status_cnt[0]; return dd->sw_send_dma_eng_err_status_cnt[0];
} }
static u64 access_dc_rcv_err_cnt(const struct cntr_entry *entry,
void *context, int vl, int mode,
u64 data)
{
struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
u64 val = 0;
u64 csr = entry->csr;
val = read_write_csr(dd, csr, mode, data);
if (mode == CNTR_MODE_R) {
val = val > CNTR_MAX - dd->sw_rcv_bypass_packet_errors ?
CNTR_MAX : val + dd->sw_rcv_bypass_packet_errors;
} else if (mode == CNTR_MODE_W) {
dd->sw_rcv_bypass_packet_errors = 0;
} else {
dd_dev_err(dd, "Invalid cntr register access mode");
return 0;
}
return val;
}
#define def_access_sw_cpu(cntr) \ #define def_access_sw_cpu(cntr) \
static u64 access_sw_cpu_##cntr(const struct cntr_entry *entry, \ static u64 access_sw_cpu_##cntr(const struct cntr_entry *entry, \
void *context, int vl, int mode, u64 data) \ void *context, int vl, int mode, u64 data) \
...@@ -4020,7 +4047,8 @@ static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = { ...@@ -4020,7 +4047,8 @@ static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = {
CCE_SEND_CREDIT_INT_CNT, CNTR_NORMAL), CCE_SEND_CREDIT_INT_CNT, CNTR_NORMAL),
[C_DC_UNC_ERR] = DC_PERF_CNTR(DcUnctblErr, DCC_ERR_UNCORRECTABLE_CNT, [C_DC_UNC_ERR] = DC_PERF_CNTR(DcUnctblErr, DCC_ERR_UNCORRECTABLE_CNT,
CNTR_SYNTH), CNTR_SYNTH),
[C_DC_RCV_ERR] = DC_PERF_CNTR(DcRecvErr, DCC_ERR_PORTRCV_ERR_CNT, CNTR_SYNTH), [C_DC_RCV_ERR] = CNTR_ELEM("DcRecvErr", DCC_ERR_PORTRCV_ERR_CNT, 0, CNTR_SYNTH,
access_dc_rcv_err_cnt),
[C_DC_FM_CFG_ERR] = DC_PERF_CNTR(DcFmCfgErr, DCC_ERR_FMCONFIG_ERR_CNT, [C_DC_FM_CFG_ERR] = DC_PERF_CNTR(DcFmCfgErr, DCC_ERR_FMCONFIG_ERR_CNT,
CNTR_SYNTH), CNTR_SYNTH),
[C_DC_RMT_PHY_ERR] = DC_PERF_CNTR(DcRmtPhyErr, DCC_ERR_RCVREMOTE_PHY_ERR_CNT, [C_DC_RMT_PHY_ERR] = DC_PERF_CNTR(DcRmtPhyErr, DCC_ERR_RCVREMOTE_PHY_ERR_CNT,
...@@ -8798,30 +8826,6 @@ static int write_tx_settings(struct hfi1_devdata *dd, ...@@ -8798,30 +8826,6 @@ static int write_tx_settings(struct hfi1_devdata *dd,
return load_8051_config(dd, TX_SETTINGS, GENERAL_CONFIG, frame); return load_8051_config(dd, TX_SETTINGS, GENERAL_CONFIG, frame);
} }
static void check_fabric_firmware_versions(struct hfi1_devdata *dd)
{
u32 frame, version, prod_id;
int ret, lane;
/* 4 lanes */
for (lane = 0; lane < 4; lane++) {
ret = read_8051_config(dd, SPICO_FW_VERSION, lane, &frame);
if (ret) {
dd_dev_err(dd,
"Unable to read lane %d firmware details\n",
lane);
continue;
}
version = (frame >> SPICO_ROM_VERSION_SHIFT)
& SPICO_ROM_VERSION_MASK;
prod_id = (frame >> SPICO_ROM_PROD_ID_SHIFT)
& SPICO_ROM_PROD_ID_MASK;
dd_dev_info(dd,
"Lane %d firmware: version 0x%04x, prod_id 0x%04x\n",
lane, version, prod_id);
}
}
/* /*
* Read an idle LCB message. * Read an idle LCB message.
* *
...@@ -9187,17 +9191,24 @@ static void wait_for_qsfp_init(struct hfi1_pportdata *ppd) ...@@ -9187,17 +9191,24 @@ static void wait_for_qsfp_init(struct hfi1_pportdata *ppd)
unsigned long timeout; unsigned long timeout;
/* /*
* Check for QSFP interrupt for t_init (SFF 8679) * Some QSFP cables have a quirk that asserts the IntN line as a side
* effect of power up on plug-in. We ignore this false positive
* interrupt until the module has finished powering up by waiting for
* a minimum timeout of the module inrush initialization time of
* 500 ms (SFF 8679 Table 5-6) to ensure the voltage rails in the
* module have stabilized.
*/
msleep(500);
/*
* Check for QSFP interrupt for t_init (SFF 8679 Table 8-1)
*/ */
timeout = jiffies + msecs_to_jiffies(2000); timeout = jiffies + msecs_to_jiffies(2000);
while (1) { while (1) {
mask = read_csr(dd, dd->hfi1_id ? mask = read_csr(dd, dd->hfi1_id ?
ASIC_QSFP2_IN : ASIC_QSFP1_IN); ASIC_QSFP2_IN : ASIC_QSFP1_IN);
if (!(mask & QSFP_HFI0_INT_N)) { if (!(mask & QSFP_HFI0_INT_N))
write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_CLEAR :
ASIC_QSFP1_CLEAR, QSFP_HFI0_INT_N);
break; break;
}
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
dd_dev_info(dd, "%s: No IntN detected, reset complete\n", dd_dev_info(dd, "%s: No IntN detected, reset complete\n",
__func__); __func__);
...@@ -9213,10 +9224,17 @@ static void set_qsfp_int_n(struct hfi1_pportdata *ppd, u8 enable) ...@@ -9213,10 +9224,17 @@ static void set_qsfp_int_n(struct hfi1_pportdata *ppd, u8 enable)
u64 mask; u64 mask;
mask = read_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK); mask = read_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK);
if (enable) if (enable) {
/*
* Clear the status register to avoid an immediate interrupt
* when we re-enable the IntN pin
*/
write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_CLEAR : ASIC_QSFP1_CLEAR,
QSFP_HFI0_INT_N);
mask |= (u64)QSFP_HFI0_INT_N; mask |= (u64)QSFP_HFI0_INT_N;
else } else {
mask &= ~(u64)QSFP_HFI0_INT_N; mask &= ~(u64)QSFP_HFI0_INT_N;
}
write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK, mask); write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK, mask);
} }
...@@ -9630,14 +9648,6 @@ void hfi1_clear_tids(struct hfi1_ctxtdata *rcd) ...@@ -9630,14 +9648,6 @@ void hfi1_clear_tids(struct hfi1_ctxtdata *rcd)
hfi1_put_tid(dd, i, PT_INVALID, 0, 0); hfi1_put_tid(dd, i, PT_INVALID, 0, 0);
} }
int hfi1_get_base_kinfo(struct hfi1_ctxtdata *rcd,
struct hfi1_ctxt_info *kinfo)
{
kinfo->runtime_flags = (HFI1_MISC_GET() << HFI1_CAP_USER_SHIFT) |
HFI1_CAP_UGET(MASK) | HFI1_CAP_KGET(K2U);
return 0;
}
struct hfi1_message_header *hfi1_get_msgheader( struct hfi1_message_header *hfi1_get_msgheader(
struct hfi1_devdata *dd, __le32 *rhf_addr) struct hfi1_devdata *dd, __le32 *rhf_addr)
{ {
...@@ -9890,6 +9900,131 @@ static int wait_phy_linkstate(struct hfi1_devdata *dd, u32 state, u32 msecs) ...@@ -9890,6 +9900,131 @@ static int wait_phy_linkstate(struct hfi1_devdata *dd, u32 state, u32 msecs)
return 0; return 0;
} }
static const char *state_completed_string(u32 completed)
{
static const char * const state_completed[] = {
"EstablishComm",
"OptimizeEQ",
"VerifyCap"
};
if (completed < ARRAY_SIZE(state_completed))
return state_completed[completed];
return "unknown";
}
static const char all_lanes_dead_timeout_expired[] =
"All lanes were inactive – was the interconnect media removed?";
static const char tx_out_of_policy[] =
"Passing lanes on local port do not meet the local link width policy";
static const char no_state_complete[] =
"State timeout occurred before link partner completed the state";
static const char * const state_complete_reasons[] = {
[0x00] = "Reason unknown",
[0x01] = "Link was halted by driver, refer to LinkDownReason",
[0x02] = "Link partner reported failure",
[0x10] = "Unable to achieve frame sync on any lane",
[0x11] =
"Unable to find a common bit rate with the link partner",
[0x12] =
"Unable to achieve frame sync on sufficient lanes to meet the local link width policy",
[0x13] =
"Unable to identify preset equalization on sufficient lanes to meet the local link width policy",
[0x14] = no_state_complete,
[0x15] =
"State timeout occurred before link partner identified equalization presets",
[0x16] =
"Link partner completed the EstablishComm state, but the passing lanes do not meet the local link width policy",
[0x17] = tx_out_of_policy,
[0x20] = all_lanes_dead_timeout_expired,
[0x21] =
"Unable to achieve acceptable BER on sufficient lanes to meet the local link width policy",
[0x22] = no_state_complete,
[0x23] =
"Link partner completed the OptimizeEq state, but the passing lanes do not meet the local link width policy",
[0x24] = tx_out_of_policy,
[0x30] = all_lanes_dead_timeout_expired,
[0x31] =
"State timeout occurred waiting for host to process received frames",
[0x32] = no_state_complete,
[0x33] =
"Link partner completed the VerifyCap state, but the passing lanes do not meet the local link width policy",
[0x34] = tx_out_of_policy,
};
static const char *state_complete_reason_code_string(struct hfi1_pportdata *ppd,
u32 code)
{
const char *str = NULL;
if (code < ARRAY_SIZE(state_complete_reasons))
str = state_complete_reasons[code];
if (str)
return str;
return "Reserved";
}
/* describe the given last state complete frame */
static void decode_state_complete(struct hfi1_pportdata *ppd, u32 frame,
const char *prefix)
{
struct hfi1_devdata *dd = ppd->dd;
u32 success;
u32 state;
u32 reason;
u32 lanes;
/*
* Decode frame:
* [ 0: 0] - success
* [ 3: 1] - state
* [ 7: 4] - next state timeout
* [15: 8] - reason code
* [31:16] - lanes
*/
success = frame & 0x1;
state = (frame >> 1) & 0x7;
reason = (frame >> 8) & 0xff;
lanes = (frame >> 16) & 0xffff;
dd_dev_err(dd, "Last %s LNI state complete frame 0x%08x:\n",
prefix, frame);
dd_dev_err(dd, " last reported state state: %s (0x%x)\n",
state_completed_string(state), state);
dd_dev_err(dd, " state successfully completed: %s\n",
success ? "yes" : "no");
dd_dev_err(dd, " fail reason 0x%x: %s\n",
reason, state_complete_reason_code_string(ppd, reason));
dd_dev_err(dd, " passing lane mask: 0x%x", lanes);
}
/*
* Read the last state complete frames and explain them. This routine
* expects to be called if the link went down during link negotiation
* and initialization (LNI). That is, anywhere between polling and link up.
*/
static void check_lni_states(struct hfi1_pportdata *ppd)
{
u32 last_local_state;
u32 last_remote_state;
read_last_local_state(ppd->dd, &last_local_state);
read_last_remote_state(ppd->dd, &last_remote_state);
/*
* Don't report anything if there is nothing to report. A value of
* 0 means the link was taken down while polling and there was no
* training in-process.
*/
if (last_local_state == 0 && last_remote_state == 0)
return;
decode_state_complete(ppd, last_local_state, "transmitted");
decode_state_complete(ppd, last_remote_state, "received");
}
/* /*
* Helper for set_link_state(). Do not call except from that routine. * Helper for set_link_state(). Do not call except from that routine.
* Expects ppd->hls_mutex to be held. * Expects ppd->hls_mutex to be held.
...@@ -9902,8 +10037,6 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason) ...@@ -9902,8 +10037,6 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
{ {
struct hfi1_devdata *dd = ppd->dd; struct hfi1_devdata *dd = ppd->dd;
u32 pstate, previous_state; u32 pstate, previous_state;
u32 last_local_state;
u32 last_remote_state;
int ret; int ret;
int do_transition; int do_transition;
int do_wait; int do_wait;
...@@ -10003,12 +10136,7 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason) ...@@ -10003,12 +10136,7 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
} else if (previous_state } else if (previous_state
& (HLS_DN_POLL | HLS_VERIFY_CAP | HLS_GOING_UP)) { & (HLS_DN_POLL | HLS_VERIFY_CAP | HLS_GOING_UP)) {
/* went down while attempting link up */ /* went down while attempting link up */
/* byte 1 of last_*_state is the failure reason */ check_lni_states(ppd);
read_last_local_state(dd, &last_local_state);
read_last_remote_state(dd, &last_remote_state);
dd_dev_err(dd,
"LNI failure last states: local 0x%08x, remote 0x%08x\n",
last_local_state, last_remote_state);
} }
/* the active link width (downgrade) is 0 on link down */ /* the active link width (downgrade) is 0 on link down */
...@@ -11668,9 +11796,6 @@ static void free_cntrs(struct hfi1_devdata *dd) ...@@ -11668,9 +11796,6 @@ static void free_cntrs(struct hfi1_devdata *dd)
dd->cntrnames = NULL; dd->cntrnames = NULL;
} }
#define CNTR_MAX 0xFFFFFFFFFFFFFFFFULL
#define CNTR_32BIT_MAX 0x00000000FFFFFFFF
static u64 read_dev_port_cntr(struct hfi1_devdata *dd, struct cntr_entry *entry, static u64 read_dev_port_cntr(struct hfi1_devdata *dd, struct cntr_entry *entry,
u64 *psval, void *context, int vl) u64 *psval, void *context, int vl)
{ {
...@@ -12325,37 +12450,6 @@ u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd) ...@@ -12325,37 +12450,6 @@ u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd)
return ib_pstate; return ib_pstate;
} }
/*
* Read/modify/write ASIC_QSFP register bits as selected by mask
* data: 0 or 1 in the positions depending on what needs to be written
* dir: 0 for read, 1 for write
* mask: select by setting
* I2CCLK (bit 0)
* I2CDATA (bit 1)
*/
u64 hfi1_gpio_mod(struct hfi1_devdata *dd, u32 target, u32 data, u32 dir,
u32 mask)
{
u64 qsfp_oe, target_oe;
target_oe = target ? ASIC_QSFP2_OE : ASIC_QSFP1_OE;
if (mask) {
/* We are writing register bits, so lock access */
dir &= mask;
data &= mask;
qsfp_oe = read_csr(dd, target_oe);
qsfp_oe = (qsfp_oe & ~(u64)mask) | (u64)dir;
write_csr(dd, target_oe, qsfp_oe);
}
/* We are exclusively reading bits here, but it is unlikely
* we'll get valid data when we set the direction of the pin
* in the same call, so read should call this function again
* to get valid data
*/
return read_csr(dd, target ? ASIC_QSFP2_IN : ASIC_QSFP1_IN);
}
#define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \ #define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \
(r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) (r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK)
...@@ -12780,7 +12874,6 @@ static int set_up_context_variables(struct hfi1_devdata *dd) ...@@ -12780,7 +12874,6 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
/* /*
* Kernel receive contexts: * Kernel receive contexts:
* - min of 2 or 1 context/numa (excluding control context)
* - Context 0 - control context (VL15/multicast/error) * - Context 0 - control context (VL15/multicast/error)
* - Context 1 - first kernel context * - Context 1 - first kernel context
* - Context 2 - second kernel context * - Context 2 - second kernel context
...@@ -12794,9 +12887,7 @@ static int set_up_context_variables(struct hfi1_devdata *dd) ...@@ -12794,9 +12887,7 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
*/ */
num_kernel_contexts = n_krcvqs + 1; num_kernel_contexts = n_krcvqs + 1;
else else
num_kernel_contexts = num_online_nodes() + 1; num_kernel_contexts = DEFAULT_KRCVQS + 1;
num_kernel_contexts =
max_t(int, MIN_KERNEL_KCTXTS, num_kernel_contexts);
/* /*
* Every kernel receive context needs an ACK send context. * Every kernel receive context needs an ACK send context.
* one send context is allocated for each VL{0-7} and VL15 * one send context is allocated for each VL{0-7} and VL15
...@@ -12815,7 +12906,7 @@ static int set_up_context_variables(struct hfi1_devdata *dd) ...@@ -12815,7 +12906,7 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
*/ */
if (num_user_contexts < 0) if (num_user_contexts < 0)
num_user_contexts = num_user_contexts =
cpumask_weight(&dd->affinity->real_cpu_mask); cpumask_weight(&node_affinity.real_cpu_mask);
total_contexts = num_kernel_contexts + num_user_contexts; total_contexts = num_kernel_contexts + num_user_contexts;
...@@ -14141,6 +14232,11 @@ static int init_asic_data(struct hfi1_devdata *dd) ...@@ -14141,6 +14232,11 @@ static int init_asic_data(struct hfi1_devdata *dd)
} }
dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */ dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */
spin_unlock_irqrestore(&hfi1_devs_lock, flags); spin_unlock_irqrestore(&hfi1_devs_lock, flags);
/* first one through - set up i2c devices */
if (!peer)
ret = set_up_i2c(dd, dd->asic_data);
return ret; return ret;
} }
...@@ -14445,19 +14541,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, ...@@ -14445,19 +14541,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
(dd->revision >> CCE_REVISION_SW_SHIFT) (dd->revision >> CCE_REVISION_SW_SHIFT)
& CCE_REVISION_SW_MASK); & CCE_REVISION_SW_MASK);
/*
* The real cpu mask is part of the affinity struct but has to be
* initialized earlier than the rest of the affinity struct because it
* is needed to calculate the number of user contexts in
* set_up_context_variables(). However, hfi1_dev_affinity_init(),
* which initializes the rest of the affinity struct members,
* depends on set_up_context_variables() for the number of kernel
* contexts, so it cannot be called before set_up_context_variables().
*/
ret = init_real_cpu_mask(dd);
if (ret)
goto bail_cleanup;
ret = set_up_context_variables(dd); ret = set_up_context_variables(dd);
if (ret) if (ret)
goto bail_cleanup; goto bail_cleanup;
...@@ -14471,7 +14554,9 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, ...@@ -14471,7 +14554,9 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
/* set up KDETH QP prefix in both RX and TX CSRs */ /* set up KDETH QP prefix in both RX and TX CSRs */
init_kdeth_qp(dd); init_kdeth_qp(dd);
hfi1_dev_affinity_init(dd); ret = hfi1_dev_affinity_init(dd);
if (ret)
goto bail_cleanup;
/* send contexts must be set up before receive contexts */ /* send contexts must be set up before receive contexts */
ret = init_send_contexts(dd); ret = init_send_contexts(dd);
...@@ -14508,8 +14593,14 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, ...@@ -14508,8 +14593,14 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
/* set up LCB access - must be after set_up_interrupts() */ /* set up LCB access - must be after set_up_interrupts() */
init_lcb_access(dd); init_lcb_access(dd);
/*
* Serial number is created from the base guid:
* [27:24] = base guid [38:35]
* [23: 0] = base guid [23: 0]
*/
snprintf(dd->serial, SERIAL_MAX, "0x%08llx\n", snprintf(dd->serial, SERIAL_MAX, "0x%08llx\n",
dd->base_guid & 0xFFFFFF); (dd->base_guid & 0xFFFFFF) |
((dd->base_guid >> 11) & 0xF000000));
dd->oui1 = dd->base_guid >> 56 & 0xFF; dd->oui1 = dd->base_guid >> 56 & 0xFF;
dd->oui2 = dd->base_guid >> 48 & 0xFF; dd->oui2 = dd->base_guid >> 48 & 0xFF;
...@@ -14518,7 +14609,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, ...@@ -14518,7 +14609,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
ret = load_firmware(dd); /* asymmetric with dispose_firmware() */ ret = load_firmware(dd); /* asymmetric with dispose_firmware() */
if (ret) if (ret)
goto bail_clear_intr; goto bail_clear_intr;
check_fabric_firmware_versions(dd);
thermal_init(dd); thermal_init(dd);
......
...@@ -640,6 +640,7 @@ extern uint platform_config_load; ...@@ -640,6 +640,7 @@ extern uint platform_config_load;
/* SBus commands */ /* SBus commands */
#define RESET_SBUS_RECEIVER 0x20 #define RESET_SBUS_RECEIVER 0x20
#define WRITE_SBUS_RECEIVER 0x21 #define WRITE_SBUS_RECEIVER 0x21
#define READ_SBUS_RECEIVER 0x22
void sbus_request(struct hfi1_devdata *dd, void sbus_request(struct hfi1_devdata *dd,
u8 receiver_addr, u8 data_addr, u8 command, u32 data_in); u8 receiver_addr, u8 data_addr, u8 command, u32 data_in);
int sbus_request_slow(struct hfi1_devdata *dd, int sbus_request_slow(struct hfi1_devdata *dd,
...@@ -1336,10 +1337,6 @@ void hfi1_start_cleanup(struct hfi1_devdata *dd); ...@@ -1336,10 +1337,6 @@ void hfi1_start_cleanup(struct hfi1_devdata *dd);
void hfi1_clear_tids(struct hfi1_ctxtdata *rcd); void hfi1_clear_tids(struct hfi1_ctxtdata *rcd);
struct hfi1_message_header *hfi1_get_msgheader( struct hfi1_message_header *hfi1_get_msgheader(
struct hfi1_devdata *dd, __le32 *rhf_addr); struct hfi1_devdata *dd, __le32 *rhf_addr);
int hfi1_get_base_kinfo(struct hfi1_ctxtdata *rcd,
struct hfi1_ctxt_info *kinfo);
u64 hfi1_gpio_mod(struct hfi1_devdata *dd, u32 target, u32 data, u32 dir,
u32 mask);
int hfi1_init_ctxt(struct send_context *sc); int hfi1_init_ctxt(struct send_context *sc);
void hfi1_put_tid(struct hfi1_devdata *dd, u32 index, void hfi1_put_tid(struct hfi1_devdata *dd, u32 index,
u32 type, unsigned long pa, u16 order); u32 type, unsigned long pa, u16 order);
......
...@@ -471,6 +471,10 @@ ...@@ -471,6 +471,10 @@
#define ASIC_STS_SBUS_RESULT (ASIC + 0x000000000010) #define ASIC_STS_SBUS_RESULT (ASIC + 0x000000000010)
#define ASIC_STS_SBUS_RESULT_DONE_SMASK 0x1ull #define ASIC_STS_SBUS_RESULT_DONE_SMASK 0x1ull
#define ASIC_STS_SBUS_RESULT_RCV_DATA_VALID_SMASK 0x2ull #define ASIC_STS_SBUS_RESULT_RCV_DATA_VALID_SMASK 0x2ull
#define ASIC_STS_SBUS_RESULT_RESULT_CODE_SHIFT 2
#define ASIC_STS_SBUS_RESULT_RESULT_CODE_MASK 0x7ull
#define ASIC_STS_SBUS_RESULT_DATA_OUT_SHIFT 32
#define ASIC_STS_SBUS_RESULT_DATA_OUT_MASK 0xFFFFFFFFull
#define ASIC_STS_THERM (ASIC + 0x000000000058) #define ASIC_STS_THERM (ASIC + 0x000000000058)
#define ASIC_STS_THERM_CRIT_TEMP_MASK 0x7FFull #define ASIC_STS_THERM_CRIT_TEMP_MASK 0x7FFull
#define ASIC_STS_THERM_CRIT_TEMP_SHIFT 18 #define ASIC_STS_THERM_CRIT_TEMP_SHIFT 18
......
...@@ -392,9 +392,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, ...@@ -392,9 +392,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
u16 rlid; u16 rlid;
u8 svc_type, sl, sc5; u8 svc_type, sl, sc5;
sc5 = (be16_to_cpu(rhdr->lrh[0]) >> 12) & 0xf; sc5 = hdr2sc(rhdr, packet->rhf);
if (rhf_dc_info(packet->rhf))
sc5 |= 0x10;
sl = ibp->sc_to_sl[sc5]; sl = ibp->sc_to_sl[sc5];
lqpn = be32_to_cpu(bth[1]) & RVT_QPN_MASK; lqpn = be32_to_cpu(bth[1]) & RVT_QPN_MASK;
...@@ -450,14 +448,20 @@ static inline void init_packet(struct hfi1_ctxtdata *rcd, ...@@ -450,14 +448,20 @@ static inline void init_packet(struct hfi1_ctxtdata *rcd,
packet->rcv_flags = 0; packet->rcv_flags = 0;
} }
static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr, void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
struct hfi1_other_headers *ohdr, bool do_cnp)
u64 rhf, u32 bth1, struct ib_grh *grh)
{ {
struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
u32 rqpn = 0; struct hfi1_ib_header *hdr = pkt->hdr;
u16 rlid; struct hfi1_other_headers *ohdr = pkt->ohdr;
u8 sc5, svc_type; struct ib_grh *grh = NULL;
u32 rqpn = 0, bth1;
u16 rlid, dlid = be16_to_cpu(hdr->lrh[1]);
u8 sc, svc_type;
bool is_mcast = false;
if (pkt->rcv_flags & HFI1_HAS_GRH)
grh = &hdr->u.l.grh;
switch (qp->ibqp.qp_type) { switch (qp->ibqp.qp_type) {
case IB_QPT_SMI: case IB_QPT_SMI:
...@@ -466,6 +470,8 @@ static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr, ...@@ -466,6 +470,8 @@ static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr,
rlid = be16_to_cpu(hdr->lrh[3]); rlid = be16_to_cpu(hdr->lrh[3]);
rqpn = be32_to_cpu(ohdr->u.ud.deth[1]) & RVT_QPN_MASK; rqpn = be32_to_cpu(ohdr->u.ud.deth[1]) & RVT_QPN_MASK;
svc_type = IB_CC_SVCTYPE_UD; svc_type = IB_CC_SVCTYPE_UD;
is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
(dlid != be16_to_cpu(IB_LID_PERMISSIVE));
break; break;
case IB_QPT_UC: case IB_QPT_UC:
rlid = qp->remote_ah_attr.dlid; rlid = qp->remote_ah_attr.dlid;
...@@ -481,24 +487,23 @@ static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr, ...@@ -481,24 +487,23 @@ static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr,
return; return;
} }
sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; sc = hdr2sc((struct hfi1_message_header *)hdr, pkt->rhf);
if (rhf_dc_info(rhf))
sc5 |= 0x10;
if (bth1 & HFI1_FECN_SMASK) { bth1 = be32_to_cpu(ohdr->bth[1]);
if (do_cnp && (bth1 & HFI1_FECN_SMASK)) {
u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]); u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]);
u16 dlid = be16_to_cpu(hdr->lrh[1]);
return_cnp(ibp, qp, rqpn, pkey, dlid, rlid, sc5, grh); return_cnp(ibp, qp, rqpn, pkey, dlid, rlid, sc, grh);
} }
if (bth1 & HFI1_BECN_SMASK) { if (!is_mcast && (bth1 & HFI1_BECN_SMASK)) {
struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
u32 lqpn = bth1 & RVT_QPN_MASK; u32 lqpn = bth1 & RVT_QPN_MASK;
u8 sl = ibp->sc_to_sl[sc5]; u8 sl = ibp->sc_to_sl[sc];
process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type); process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type);
} }
} }
struct ps_mdata { struct ps_mdata {
...@@ -596,7 +601,6 @@ static void __prescan_rxq(struct hfi1_packet *packet) ...@@ -596,7 +601,6 @@ static void __prescan_rxq(struct hfi1_packet *packet)
struct rvt_qp *qp; struct rvt_qp *qp;
struct hfi1_ib_header *hdr; struct hfi1_ib_header *hdr;
struct hfi1_other_headers *ohdr; struct hfi1_other_headers *ohdr;
struct ib_grh *grh = NULL;
struct rvt_dev_info *rdi = &dd->verbs_dev.rdi; struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
u64 rhf = rhf_to_cpu(rhf_addr); u64 rhf = rhf_to_cpu(rhf_addr);
u32 etype = rhf_rcv_type(rhf), qpn, bth1; u32 etype = rhf_rcv_type(rhf), qpn, bth1;
...@@ -616,14 +620,13 @@ static void __prescan_rxq(struct hfi1_packet *packet) ...@@ -616,14 +620,13 @@ static void __prescan_rxq(struct hfi1_packet *packet)
hfi1_get_msgheader(dd, rhf_addr); hfi1_get_msgheader(dd, rhf_addr);
lnh = be16_to_cpu(hdr->lrh[0]) & 3; lnh = be16_to_cpu(hdr->lrh[0]) & 3;
if (lnh == HFI1_LRH_BTH) { if (lnh == HFI1_LRH_BTH)
ohdr = &hdr->u.oth; ohdr = &hdr->u.oth;
} else if (lnh == HFI1_LRH_GRH) { else if (lnh == HFI1_LRH_GRH)
ohdr = &hdr->u.l.oth; ohdr = &hdr->u.l.oth;
grh = &hdr->u.l.grh; else
} else {
goto next; /* just in case */ goto next; /* just in case */
}
bth1 = be32_to_cpu(ohdr->bth[1]); bth1 = be32_to_cpu(ohdr->bth[1]);
is_ecn = !!(bth1 & (HFI1_FECN_SMASK | HFI1_BECN_SMASK)); is_ecn = !!(bth1 & (HFI1_FECN_SMASK | HFI1_BECN_SMASK));
...@@ -639,7 +642,7 @@ static void __prescan_rxq(struct hfi1_packet *packet) ...@@ -639,7 +642,7 @@ static void __prescan_rxq(struct hfi1_packet *packet)
goto next; goto next;
} }
process_ecn(qp, hdr, ohdr, rhf, bth1, grh); process_ecn(qp, packet, true);
rcu_read_unlock(); rcu_read_unlock();
/* turn off BECN, FECN */ /* turn off BECN, FECN */
...@@ -1362,6 +1365,7 @@ int process_receive_bypass(struct hfi1_packet *packet) ...@@ -1362,6 +1365,7 @@ int process_receive_bypass(struct hfi1_packet *packet)
dd_dev_err(packet->rcd->dd, dd_dev_err(packet->rcd->dd,
"Bypass packets are not supported in normal operation. Dropping\n"); "Bypass packets are not supported in normal operation. Dropping\n");
incr_cntr64(&packet->rcd->dd->sw_rcv_bypass_packet_errors);
return RHF_RCV_CONTINUE; return RHF_RCV_CONTINUE;
} }
......
...@@ -168,6 +168,7 @@ static inline int is_valid_mmap(u64 token) ...@@ -168,6 +168,7 @@ static inline int is_valid_mmap(u64 token)
static int hfi1_file_open(struct inode *inode, struct file *fp) static int hfi1_file_open(struct inode *inode, struct file *fp)
{ {
struct hfi1_filedata *fd;
struct hfi1_devdata *dd = container_of(inode->i_cdev, struct hfi1_devdata *dd = container_of(inode->i_cdev,
struct hfi1_devdata, struct hfi1_devdata,
user_cdev); user_cdev);
...@@ -176,10 +177,17 @@ static int hfi1_file_open(struct inode *inode, struct file *fp) ...@@ -176,10 +177,17 @@ static int hfi1_file_open(struct inode *inode, struct file *fp)
kobject_get(&dd->kobj); kobject_get(&dd->kobj);
/* The real work is performed later in assign_ctxt() */ /* The real work is performed later in assign_ctxt() */
fp->private_data = kzalloc(sizeof(struct hfi1_filedata), GFP_KERNEL);
if (fp->private_data) /* no cpu affinity by default */ fd = kzalloc(sizeof(*fd), GFP_KERNEL);
((struct hfi1_filedata *)fp->private_data)->rec_cpu_num = -1;
return fp->private_data ? 0 : -ENOMEM; if (fd) {
fd->rec_cpu_num = -1; /* no cpu affinity by default */
fd->mm = current->mm;
}
fp->private_data = fd;
return fd ? 0 : -ENOMEM;
} }
static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
...@@ -392,41 +400,38 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) ...@@ -392,41 +400,38 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from)
struct hfi1_filedata *fd = kiocb->ki_filp->private_data; struct hfi1_filedata *fd = kiocb->ki_filp->private_data;
struct hfi1_user_sdma_pkt_q *pq = fd->pq; struct hfi1_user_sdma_pkt_q *pq = fd->pq;
struct hfi1_user_sdma_comp_q *cq = fd->cq; struct hfi1_user_sdma_comp_q *cq = fd->cq;
int ret = 0, done = 0, reqs = 0; int done = 0, reqs = 0;
unsigned long dim = from->nr_segs; unsigned long dim = from->nr_segs;
if (!cq || !pq) { if (!cq || !pq)
ret = -EIO; return -EIO;
goto done;
}
if (!iter_is_iovec(from) || !dim) { if (!iter_is_iovec(from) || !dim)
ret = -EINVAL; return -EINVAL;
goto done;
}
hfi1_cdbg(SDMA, "SDMA request from %u:%u (%lu)", hfi1_cdbg(SDMA, "SDMA request from %u:%u (%lu)",
fd->uctxt->ctxt, fd->subctxt, dim); fd->uctxt->ctxt, fd->subctxt, dim);
if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) { if (atomic_read(&pq->n_reqs) == pq->n_max_reqs)
ret = -ENOSPC; return -ENOSPC;
goto done;
}
while (dim) { while (dim) {
int ret;
unsigned long count = 0; unsigned long count = 0;
ret = hfi1_user_sdma_process_request( ret = hfi1_user_sdma_process_request(
kiocb->ki_filp, (struct iovec *)(from->iov + done), kiocb->ki_filp, (struct iovec *)(from->iov + done),
dim, &count); dim, &count);
if (ret) if (ret) {
goto done; reqs = ret;
break;
}
dim -= count; dim -= count;
done += count; done += count;
reqs++; reqs++;
} }
done:
return ret ? ret : reqs; return reqs;
} }
static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
...@@ -718,7 +723,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) ...@@ -718,7 +723,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
hfi1_user_sdma_free_queues(fdata); hfi1_user_sdma_free_queues(fdata);
/* release the cpu */ /* release the cpu */
hfi1_put_proc_affinity(dd, fdata->rec_cpu_num); hfi1_put_proc_affinity(fdata->rec_cpu_num);
/* /*
* Clear any left over, unhandled events so the next process that * Clear any left over, unhandled events so the next process that
...@@ -730,7 +735,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) ...@@ -730,7 +735,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
if (--uctxt->cnt) { if (--uctxt->cnt) {
uctxt->active_slaves &= ~(1 << fdata->subctxt); uctxt->active_slaves &= ~(1 << fdata->subctxt);
uctxt->subpid[fdata->subctxt] = 0;
mutex_unlock(&hfi1_mutex); mutex_unlock(&hfi1_mutex);
goto done; goto done;
} }
...@@ -756,7 +760,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) ...@@ -756,7 +760,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
write_kctxt_csr(dd, uctxt->sc->hw_context, SEND_CTXT_CHECK_ENABLE, write_kctxt_csr(dd, uctxt->sc->hw_context, SEND_CTXT_CHECK_ENABLE,
hfi1_pkt_default_send_ctxt_mask(dd, uctxt->sc->type)); hfi1_pkt_default_send_ctxt_mask(dd, uctxt->sc->type));
sc_disable(uctxt->sc); sc_disable(uctxt->sc);
uctxt->pid = 0;
spin_unlock_irqrestore(&dd->uctxt_lock, flags); spin_unlock_irqrestore(&dd->uctxt_lock, flags);
dd->rcd[uctxt->ctxt] = NULL; dd->rcd[uctxt->ctxt] = NULL;
...@@ -818,9 +821,10 @@ static int assign_ctxt(struct file *fp, struct hfi1_user_info *uinfo) ...@@ -818,9 +821,10 @@ static int assign_ctxt(struct file *fp, struct hfi1_user_info *uinfo)
ret = find_shared_ctxt(fp, uinfo); ret = find_shared_ctxt(fp, uinfo);
if (ret < 0) if (ret < 0)
goto done_unlock; goto done_unlock;
if (ret) if (ret) {
fd->rec_cpu_num = hfi1_get_proc_affinity( fd->rec_cpu_num =
fd->uctxt->dd, fd->uctxt->numa_id); hfi1_get_proc_affinity(fd->uctxt->numa_id);
}
} }
/* /*
...@@ -895,7 +899,6 @@ static int find_shared_ctxt(struct file *fp, ...@@ -895,7 +899,6 @@ static int find_shared_ctxt(struct file *fp,
} }
fd->uctxt = uctxt; fd->uctxt = uctxt;
fd->subctxt = uctxt->cnt++; fd->subctxt = uctxt->cnt++;
uctxt->subpid[fd->subctxt] = current->pid;
uctxt->active_slaves |= 1 << fd->subctxt; uctxt->active_slaves |= 1 << fd->subctxt;
ret = 1; ret = 1;
goto done; goto done;
...@@ -932,7 +935,11 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd, ...@@ -932,7 +935,11 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
if (ctxt == dd->num_rcv_contexts) if (ctxt == dd->num_rcv_contexts)
return -EBUSY; return -EBUSY;
fd->rec_cpu_num = hfi1_get_proc_affinity(dd, -1); /*
* If we don't have a NUMA node requested, preference is towards
* device NUMA node.
*/
fd->rec_cpu_num = hfi1_get_proc_affinity(dd->node);
if (fd->rec_cpu_num != -1) if (fd->rec_cpu_num != -1)
numa = cpu_to_node(fd->rec_cpu_num); numa = cpu_to_node(fd->rec_cpu_num);
else else
...@@ -976,8 +983,7 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd, ...@@ -976,8 +983,7 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
return ret; return ret;
} }
uctxt->userversion = uinfo->userversion; uctxt->userversion = uinfo->userversion;
uctxt->pid = current->pid; uctxt->flags = hfi1_cap_mask; /* save current flag state */
uctxt->flags = HFI1_CAP_UGET(MASK);
init_waitqueue_head(&uctxt->wait); init_waitqueue_head(&uctxt->wait);
strlcpy(uctxt->comm, current->comm, sizeof(uctxt->comm)); strlcpy(uctxt->comm, current->comm, sizeof(uctxt->comm));
memcpy(uctxt->uuid, uinfo->uuid, sizeof(uctxt->uuid)); memcpy(uctxt->uuid, uinfo->uuid, sizeof(uctxt->uuid));
...@@ -1080,18 +1086,18 @@ static int user_init(struct file *fp) ...@@ -1080,18 +1086,18 @@ static int user_init(struct file *fp)
hfi1_set_ctxt_jkey(uctxt->dd, uctxt->ctxt, uctxt->jkey); hfi1_set_ctxt_jkey(uctxt->dd, uctxt->ctxt, uctxt->jkey);
rcvctrl_ops = HFI1_RCVCTRL_CTXT_ENB; rcvctrl_ops = HFI1_RCVCTRL_CTXT_ENB;
if (HFI1_CAP_KGET_MASK(uctxt->flags, HDRSUPP)) if (HFI1_CAP_UGET_MASK(uctxt->flags, HDRSUPP))
rcvctrl_ops |= HFI1_RCVCTRL_TIDFLOW_ENB; rcvctrl_ops |= HFI1_RCVCTRL_TIDFLOW_ENB;
/* /*
* Ignore the bit in the flags for now until proper * Ignore the bit in the flags for now until proper
* support for multiple packet per rcv array entry is * support for multiple packet per rcv array entry is
* added. * added.
*/ */
if (!HFI1_CAP_KGET_MASK(uctxt->flags, MULTI_PKT_EGR)) if (!HFI1_CAP_UGET_MASK(uctxt->flags, MULTI_PKT_EGR))
rcvctrl_ops |= HFI1_RCVCTRL_ONE_PKT_EGR_ENB; rcvctrl_ops |= HFI1_RCVCTRL_ONE_PKT_EGR_ENB;
if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_EGR_FULL)) if (HFI1_CAP_UGET_MASK(uctxt->flags, NODROP_EGR_FULL))
rcvctrl_ops |= HFI1_RCVCTRL_NO_EGR_DROP_ENB; rcvctrl_ops |= HFI1_RCVCTRL_NO_EGR_DROP_ENB;
if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_RHQ_FULL)) if (HFI1_CAP_UGET_MASK(uctxt->flags, NODROP_RHQ_FULL))
rcvctrl_ops |= HFI1_RCVCTRL_NO_RHQ_DROP_ENB; rcvctrl_ops |= HFI1_RCVCTRL_NO_RHQ_DROP_ENB;
/* /*
* The RcvCtxtCtrl.TailUpd bit has to be explicitly written. * The RcvCtxtCtrl.TailUpd bit has to be explicitly written.
...@@ -1099,7 +1105,7 @@ static int user_init(struct file *fp) ...@@ -1099,7 +1105,7 @@ static int user_init(struct file *fp)
* uses of the chip or ctxt. Therefore, add the rcvctrl op * uses of the chip or ctxt. Therefore, add the rcvctrl op
* for both cases. * for both cases.
*/ */
if (HFI1_CAP_KGET_MASK(uctxt->flags, DMA_RTAIL)) if (HFI1_CAP_UGET_MASK(uctxt->flags, DMA_RTAIL))
rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_ENB; rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_ENB;
else else
rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_DIS; rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_DIS;
...@@ -1122,9 +1128,14 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len) ...@@ -1122,9 +1128,14 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
int ret = 0; int ret = 0;
memset(&cinfo, 0, sizeof(cinfo)); memset(&cinfo, 0, sizeof(cinfo));
ret = hfi1_get_base_kinfo(uctxt, &cinfo); cinfo.runtime_flags = (((uctxt->flags >> HFI1_CAP_MISC_SHIFT) &
if (ret < 0) HFI1_CAP_MISC_MASK) << HFI1_CAP_USER_SHIFT) |
goto done; HFI1_CAP_UGET_MASK(uctxt->flags, MASK) |
HFI1_CAP_KGET_MASK(uctxt->flags, K2U);
/* adjust flag if this fd is not able to cache */
if (!fd->handler)
cinfo.runtime_flags |= HFI1_CAP_TID_UNMAP; /* no caching */
cinfo.num_active = hfi1_count_active_units(); cinfo.num_active = hfi1_count_active_units();
cinfo.unit = uctxt->dd->unit; cinfo.unit = uctxt->dd->unit;
cinfo.ctxt = uctxt->ctxt; cinfo.ctxt = uctxt->ctxt;
...@@ -1146,7 +1157,7 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len) ...@@ -1146,7 +1157,7 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, fd->subctxt, cinfo); trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, fd->subctxt, cinfo);
if (copy_to_user(ubase, &cinfo, sizeof(cinfo))) if (copy_to_user(ubase, &cinfo, sizeof(cinfo)))
ret = -EFAULT; ret = -EFAULT;
done:
return ret; return ret;
} }
......
...@@ -206,6 +206,9 @@ static const struct firmware *platform_config; ...@@ -206,6 +206,9 @@ static const struct firmware *platform_config;
/* the number of fabric SerDes on the SBus */ /* the number of fabric SerDes on the SBus */
#define NUM_FABRIC_SERDES 4 #define NUM_FABRIC_SERDES 4
/* ASIC_STS_SBUS_RESULT.RESULT_CODE value */
#define SBUS_READ_COMPLETE 0x4
/* SBus fabric SerDes addresses, one set per HFI */ /* SBus fabric SerDes addresses, one set per HFI */
static const u8 fabric_serdes_addrs[2][NUM_FABRIC_SERDES] = { static const u8 fabric_serdes_addrs[2][NUM_FABRIC_SERDES] = {
{ 0x01, 0x02, 0x03, 0x04 }, { 0x01, 0x02, 0x03, 0x04 },
...@@ -240,6 +243,7 @@ static const u8 all_pcie_serdes_broadcast = 0xe0; ...@@ -240,6 +243,7 @@ static const u8 all_pcie_serdes_broadcast = 0xe0;
static void dispose_one_firmware(struct firmware_details *fdet); static void dispose_one_firmware(struct firmware_details *fdet);
static int load_fabric_serdes_firmware(struct hfi1_devdata *dd, static int load_fabric_serdes_firmware(struct hfi1_devdata *dd,
struct firmware_details *fdet); struct firmware_details *fdet);
static void dump_fw_version(struct hfi1_devdata *dd);
/* /*
* Read a single 64-bit value from 8051 data memory. * Read a single 64-bit value from 8051 data memory.
...@@ -1078,6 +1082,44 @@ void sbus_request(struct hfi1_devdata *dd, ...@@ -1078,6 +1082,44 @@ void sbus_request(struct hfi1_devdata *dd,
ASIC_CFG_SBUS_REQUEST_RECEIVER_ADDR_SHIFT)); ASIC_CFG_SBUS_REQUEST_RECEIVER_ADDR_SHIFT));
} }
/*
* Read a value from the SBus.
*
* Requires the caller to be in fast mode
*/
static u32 sbus_read(struct hfi1_devdata *dd, u8 receiver_addr, u8 data_addr,
u32 data_in)
{
u64 reg;
int retries;
int success = 0;
u32 result = 0;
u32 result_code = 0;
sbus_request(dd, receiver_addr, data_addr, READ_SBUS_RECEIVER, data_in);
for (retries = 0; retries < 100; retries++) {
usleep_range(1000, 1200); /* arbitrary */
reg = read_csr(dd, ASIC_STS_SBUS_RESULT);
result_code = (reg >> ASIC_STS_SBUS_RESULT_RESULT_CODE_SHIFT)
& ASIC_STS_SBUS_RESULT_RESULT_CODE_MASK;
if (result_code != SBUS_READ_COMPLETE)
continue;
success = 1;
result = (reg >> ASIC_STS_SBUS_RESULT_DATA_OUT_SHIFT)
& ASIC_STS_SBUS_RESULT_DATA_OUT_MASK;
break;
}
if (!success) {
dd_dev_err(dd, "%s: read failed, result code 0x%x\n", __func__,
result_code);
}
return result;
}
/* /*
* Turn off the SBus and fabric serdes spicos. * Turn off the SBus and fabric serdes spicos.
* *
...@@ -1636,6 +1678,7 @@ int load_firmware(struct hfi1_devdata *dd) ...@@ -1636,6 +1678,7 @@ int load_firmware(struct hfi1_devdata *dd)
return ret; return ret;
} }
dump_fw_version(dd);
return 0; return 0;
} }
...@@ -2054,3 +2097,85 @@ void read_guid(struct hfi1_devdata *dd) ...@@ -2054,3 +2097,85 @@ void read_guid(struct hfi1_devdata *dd)
dd_dev_info(dd, "GUID %llx", dd_dev_info(dd, "GUID %llx",
(unsigned long long)dd->base_guid); (unsigned long long)dd->base_guid);
} }
/* read and display firmware version info */
static void dump_fw_version(struct hfi1_devdata *dd)
{
u32 pcie_vers[NUM_PCIE_SERDES];
u32 fabric_vers[NUM_FABRIC_SERDES];
u32 sbus_vers;
int i;
int all_same;
int ret;
u8 rcv_addr;
ret = acquire_chip_resource(dd, CR_SBUS, SBUS_TIMEOUT);
if (ret) {
dd_dev_err(dd, "Unable to acquire SBus to read firmware versions\n");
return;
}
/* set fast mode */
set_sbus_fast_mode(dd);
/* read version for SBus Master */
sbus_request(dd, SBUS_MASTER_BROADCAST, 0x02, WRITE_SBUS_RECEIVER, 0);
sbus_request(dd, SBUS_MASTER_BROADCAST, 0x07, WRITE_SBUS_RECEIVER, 0x1);
/* wait for interrupt to be processed */
usleep_range(10000, 11000);
sbus_vers = sbus_read(dd, SBUS_MASTER_BROADCAST, 0x08, 0x1);
dd_dev_info(dd, "SBus Master firmware version 0x%08x\n", sbus_vers);
/* read version for PCIe SerDes */
all_same = 1;
pcie_vers[0] = 0;
for (i = 0; i < NUM_PCIE_SERDES; i++) {
rcv_addr = pcie_serdes_addrs[dd->hfi1_id][i];
sbus_request(dd, rcv_addr, 0x03, WRITE_SBUS_RECEIVER, 0);
/* wait for interrupt to be processed */
usleep_range(10000, 11000);
pcie_vers[i] = sbus_read(dd, rcv_addr, 0x04, 0x0);
if (i > 0 && pcie_vers[0] != pcie_vers[i])
all_same = 0;
}
if (all_same) {
dd_dev_info(dd, "PCIe SerDes firmware version 0x%x\n",
pcie_vers[0]);
} else {
dd_dev_warn(dd, "PCIe SerDes do not have the same firmware version\n");
for (i = 0; i < NUM_PCIE_SERDES; i++) {
dd_dev_info(dd,
"PCIe SerDes lane %d firmware version 0x%x\n",
i, pcie_vers[i]);
}
}
/* read version for fabric SerDes */
all_same = 1;
fabric_vers[0] = 0;
for (i = 0; i < NUM_FABRIC_SERDES; i++) {
rcv_addr = fabric_serdes_addrs[dd->hfi1_id][i];
sbus_request(dd, rcv_addr, 0x03, WRITE_SBUS_RECEIVER, 0);
/* wait for interrupt to be processed */
usleep_range(10000, 11000);
fabric_vers[i] = sbus_read(dd, rcv_addr, 0x04, 0x0);
if (i > 0 && fabric_vers[0] != fabric_vers[i])
all_same = 0;
}
if (all_same) {
dd_dev_info(dd, "Fabric SerDes firmware version 0x%x\n",
fabric_vers[0]);
} else {
dd_dev_warn(dd, "Fabric SerDes do not have the same firmware version\n");
for (i = 0; i < NUM_FABRIC_SERDES; i++) {
dd_dev_info(dd,
"Fabric SerDes lane %d firmware version 0x%x\n",
i, fabric_vers[i]);
}
}
clear_sbus_fast_mode(dd);
release_chip_resource(dd, CR_SBUS);
}
...@@ -62,6 +62,8 @@ ...@@ -62,6 +62,8 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <rdma/rdma_vt.h> #include <rdma/rdma_vt.h>
#include "chip_registers.h" #include "chip_registers.h"
...@@ -253,7 +255,7 @@ struct hfi1_ctxtdata { ...@@ -253,7 +255,7 @@ struct hfi1_ctxtdata {
/* chip offset of PIO buffers for this ctxt */ /* chip offset of PIO buffers for this ctxt */
u32 piobufs; u32 piobufs;
/* per-context configuration flags */ /* per-context configuration flags */
u32 flags; unsigned long flags;
/* per-context event flags for fileops/intr communication */ /* per-context event flags for fileops/intr communication */
unsigned long event_flags; unsigned long event_flags;
/* WAIT_RCV that timed out, no interrupt */ /* WAIT_RCV that timed out, no interrupt */
...@@ -268,9 +270,6 @@ struct hfi1_ctxtdata { ...@@ -268,9 +270,6 @@ struct hfi1_ctxtdata {
u32 urgent; u32 urgent;
/* saved total number of polled urgent packets for poll edge trigger */ /* saved total number of polled urgent packets for poll edge trigger */
u32 urgent_poll; u32 urgent_poll;
/* pid of process using this ctxt */
pid_t pid;
pid_t subpid[HFI1_MAX_SHARED_CTXTS];
/* same size as task_struct .comm[], command that opened context */ /* same size as task_struct .comm[], command that opened context */
char comm[TASK_COMM_LEN]; char comm[TASK_COMM_LEN];
/* so file ops can get at unit */ /* so file ops can get at unit */
...@@ -366,11 +365,6 @@ struct hfi1_packet { ...@@ -366,11 +365,6 @@ struct hfi1_packet {
u8 etype; u8 etype;
}; };
static inline bool has_sc4_bit(struct hfi1_packet *p)
{
return !!rhf_dc_info(p->rhf);
}
/* /*
* Private data for snoop/capture support. * Private data for snoop/capture support.
*/ */
...@@ -805,10 +799,19 @@ struct hfi1_temp { ...@@ -805,10 +799,19 @@ struct hfi1_temp {
u8 triggers; /* temperature triggers */ u8 triggers; /* temperature triggers */
}; };
struct hfi1_i2c_bus {
struct hfi1_devdata *controlling_dd; /* current controlling device */
struct i2c_adapter adapter; /* bus details */
struct i2c_algo_bit_data algo; /* bus algorithm details */
int num; /* bus number, 0 or 1 */
};
/* common data between shared ASIC HFIs */ /* common data between shared ASIC HFIs */
struct hfi1_asic_data { struct hfi1_asic_data {
struct hfi1_devdata *dds[2]; /* back pointers */ struct hfi1_devdata *dds[2]; /* back pointers */
struct mutex asic_resource_mutex; struct mutex asic_resource_mutex;
struct hfi1_i2c_bus *i2c_bus0;
struct hfi1_i2c_bus *i2c_bus1;
}; };
/* device data struct now contains only "general per-device" info. /* device data struct now contains only "general per-device" info.
...@@ -1128,7 +1131,8 @@ struct hfi1_devdata { ...@@ -1128,7 +1131,8 @@ struct hfi1_devdata {
NUM_SEND_DMA_ENG_ERR_STATUS_COUNTERS]; NUM_SEND_DMA_ENG_ERR_STATUS_COUNTERS];
/* Software counter that aggregates all cce_err_status errors */ /* Software counter that aggregates all cce_err_status errors */
u64 sw_cce_err_status_aggregate; u64 sw_cce_err_status_aggregate;
/* Software counter that aggregates all bypass packet rcv errors */
u64 sw_rcv_bypass_packet_errors;
/* receive interrupt functions */ /* receive interrupt functions */
rhf_rcv_function_ptr *rhf_rcv_function_map; rhf_rcv_function_ptr *rhf_rcv_function_map;
rhf_rcv_function_ptr normal_rhf_rcv_functions[8]; rhf_rcv_function_ptr normal_rhf_rcv_functions[8];
...@@ -1184,6 +1188,7 @@ struct hfi1_devdata { ...@@ -1184,6 +1188,7 @@ struct hfi1_devdata {
struct tid_rb_node; struct tid_rb_node;
struct mmu_rb_node; struct mmu_rb_node;
struct mmu_rb_handler;
/* Private data for file operations */ /* Private data for file operations */
struct hfi1_filedata { struct hfi1_filedata {
...@@ -1194,7 +1199,7 @@ struct hfi1_filedata { ...@@ -1194,7 +1199,7 @@ struct hfi1_filedata {
/* for cpu affinity; -1 if none */ /* for cpu affinity; -1 if none */
int rec_cpu_num; int rec_cpu_num;
u32 tid_n_pinned; u32 tid_n_pinned;
struct rb_root tid_rb_root; struct mmu_rb_handler *handler;
struct tid_rb_node **entry_to_rb; struct tid_rb_node **entry_to_rb;
spinlock_t tid_lock; /* protect tid_[limit,used] counters */ spinlock_t tid_lock; /* protect tid_[limit,used] counters */
u32 tid_limit; u32 tid_limit;
...@@ -1203,6 +1208,7 @@ struct hfi1_filedata { ...@@ -1203,6 +1208,7 @@ struct hfi1_filedata {
u32 invalid_tid_idx; u32 invalid_tid_idx;
/* protect invalid_tids array and invalid_tid_idx */ /* protect invalid_tids array and invalid_tid_idx */
spinlock_t invalid_lock; spinlock_t invalid_lock;
struct mm_struct *mm;
}; };
extern struct list_head hfi1_dev_list; extern struct list_head hfi1_dev_list;
...@@ -1236,6 +1242,8 @@ int handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *, int); ...@@ -1236,6 +1242,8 @@ int handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *, int);
int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *, int); int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *, int);
void set_all_slowpath(struct hfi1_devdata *dd); void set_all_slowpath(struct hfi1_devdata *dd);
extern const struct pci_device_id hfi1_pci_tbl[];
/* receive packet handler dispositions */ /* receive packet handler dispositions */
#define RCV_PKT_OK 0x0 /* keep going */ #define RCV_PKT_OK 0x0 /* keep going */
#define RCV_PKT_LIMIT 0x1 /* stop, hit limit, start thread */ #define RCV_PKT_LIMIT 0x1 /* stop, hit limit, start thread */
...@@ -1261,7 +1269,7 @@ void receive_interrupt_work(struct work_struct *work); ...@@ -1261,7 +1269,7 @@ void receive_interrupt_work(struct work_struct *work);
static inline int hdr2sc(struct hfi1_message_header *hdr, u64 rhf) static inline int hdr2sc(struct hfi1_message_header *hdr, u64 rhf)
{ {
return ((be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf) | return ((be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf) |
((!!(rhf & RHF_DC_INFO_SMASK)) << 4); ((!!(rhf_dc_info(rhf))) << 4);
} }
static inline u16 generate_jkey(kuid_t uid) static inline u16 generate_jkey(kuid_t uid)
...@@ -1571,6 +1579,22 @@ static inline struct hfi1_ibport *to_iport(struct ib_device *ibdev, u8 port) ...@@ -1571,6 +1579,22 @@ static inline struct hfi1_ibport *to_iport(struct ib_device *ibdev, u8 port)
return &dd->pport[pidx].ibport_data; return &dd->pport[pidx].ibport_data;
} }
void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
bool do_cnp);
static inline bool process_ecn(struct rvt_qp *qp, struct hfi1_packet *pkt,
bool do_cnp)
{
struct hfi1_other_headers *ohdr = pkt->ohdr;
u32 bth1;
bth1 = be32_to_cpu(ohdr->bth[1]);
if (unlikely(bth1 & (HFI1_BECN_SMASK | HFI1_FECN_SMASK))) {
hfi1_process_ecn_slowpath(qp, pkt, do_cnp);
return bth1 & HFI1_FECN_SMASK;
}
return false;
}
/* /*
* Return the indexed PKEY from the port PKEY table. * Return the indexed PKEY from the port PKEY table.
*/ */
...@@ -1588,14 +1612,23 @@ static inline u16 hfi1_get_pkey(struct hfi1_ibport *ibp, unsigned index) ...@@ -1588,14 +1612,23 @@ static inline u16 hfi1_get_pkey(struct hfi1_ibport *ibp, unsigned index)
} }
/* /*
* Readers of cc_state must call get_cc_state() under rcu_read_lock(). * Called by readers of cc_state only, must call under rcu_read_lock().
* Writers of cc_state must call get_cc_state() under cc_state_lock.
*/ */
static inline struct cc_state *get_cc_state(struct hfi1_pportdata *ppd) static inline struct cc_state *get_cc_state(struct hfi1_pportdata *ppd)
{ {
return rcu_dereference(ppd->cc_state); return rcu_dereference(ppd->cc_state);
} }
/*
* Called by writers of cc_state only, must call under cc_state_lock.
*/
static inline
struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd)
{
return rcu_dereference_protected(ppd->cc_state,
lockdep_is_held(&ppd->cc_state_lock));
}
/* /*
* values for dd->flags (_device_ related flags) * values for dd->flags (_device_ related flags)
*/ */
...@@ -1671,9 +1704,12 @@ void shutdown_led_override(struct hfi1_pportdata *ppd); ...@@ -1671,9 +1704,12 @@ void shutdown_led_override(struct hfi1_pportdata *ppd);
*/ */
#define DEFAULT_RCVHDR_ENTSIZE 32 #define DEFAULT_RCVHDR_ENTSIZE 32
bool hfi1_can_pin_pages(struct hfi1_devdata *, u32, u32); bool hfi1_can_pin_pages(struct hfi1_devdata *dd, struct mm_struct *mm,
int hfi1_acquire_user_pages(unsigned long, size_t, bool, struct page **); u32 nlocked, u32 npages);
void hfi1_release_user_pages(struct mm_struct *, struct page **, size_t, bool); int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr,
size_t npages, bool writable, struct page **pages);
void hfi1_release_user_pages(struct mm_struct *mm, struct page **p,
size_t npages, bool dirty);
static inline void clear_rcvhdrtail(const struct hfi1_ctxtdata *rcd) static inline void clear_rcvhdrtail(const struct hfi1_ctxtdata *rcd)
{ {
...@@ -1949,4 +1985,55 @@ static inline u32 qsfp_resource(struct hfi1_devdata *dd) ...@@ -1949,4 +1985,55 @@ static inline u32 qsfp_resource(struct hfi1_devdata *dd)
int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp); int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp);
#define DD_DEV_ENTRY(dd) __string(dev, dev_name(&(dd)->pcidev->dev))
#define DD_DEV_ASSIGN(dd) __assign_str(dev, dev_name(&(dd)->pcidev->dev))
#define packettype_name(etype) { RHF_RCV_TYPE_##etype, #etype }
#define show_packettype(etype) \
__print_symbolic(etype, \
packettype_name(EXPECTED), \
packettype_name(EAGER), \
packettype_name(IB), \
packettype_name(ERROR), \
packettype_name(BYPASS))
#define ib_opcode_name(opcode) { IB_OPCODE_##opcode, #opcode }
#define show_ib_opcode(opcode) \
__print_symbolic(opcode, \
ib_opcode_name(RC_SEND_FIRST), \
ib_opcode_name(RC_SEND_MIDDLE), \
ib_opcode_name(RC_SEND_LAST), \
ib_opcode_name(RC_SEND_LAST_WITH_IMMEDIATE), \
ib_opcode_name(RC_SEND_ONLY), \
ib_opcode_name(RC_SEND_ONLY_WITH_IMMEDIATE), \
ib_opcode_name(RC_RDMA_WRITE_FIRST), \
ib_opcode_name(RC_RDMA_WRITE_MIDDLE), \
ib_opcode_name(RC_RDMA_WRITE_LAST), \
ib_opcode_name(RC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \
ib_opcode_name(RC_RDMA_WRITE_ONLY), \
ib_opcode_name(RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \
ib_opcode_name(RC_RDMA_READ_REQUEST), \
ib_opcode_name(RC_RDMA_READ_RESPONSE_FIRST), \
ib_opcode_name(RC_RDMA_READ_RESPONSE_MIDDLE), \
ib_opcode_name(RC_RDMA_READ_RESPONSE_LAST), \
ib_opcode_name(RC_RDMA_READ_RESPONSE_ONLY), \
ib_opcode_name(RC_ACKNOWLEDGE), \
ib_opcode_name(RC_ATOMIC_ACKNOWLEDGE), \
ib_opcode_name(RC_COMPARE_SWAP), \
ib_opcode_name(RC_FETCH_ADD), \
ib_opcode_name(UC_SEND_FIRST), \
ib_opcode_name(UC_SEND_MIDDLE), \
ib_opcode_name(UC_SEND_LAST), \
ib_opcode_name(UC_SEND_LAST_WITH_IMMEDIATE), \
ib_opcode_name(UC_SEND_ONLY), \
ib_opcode_name(UC_SEND_ONLY_WITH_IMMEDIATE), \
ib_opcode_name(UC_RDMA_WRITE_FIRST), \
ib_opcode_name(UC_RDMA_WRITE_MIDDLE), \
ib_opcode_name(UC_RDMA_WRITE_LAST), \
ib_opcode_name(UC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \
ib_opcode_name(UC_RDMA_WRITE_ONLY), \
ib_opcode_name(UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \
ib_opcode_name(UD_SEND_ONLY), \
ib_opcode_name(UD_SEND_ONLY_WITH_IMMEDIATE), \
ib_opcode_name(CNP))
#endif /* _HFI1_KERNEL_H */ #endif /* _HFI1_KERNEL_H */
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#include "debugfs.h" #include "debugfs.h"
#include "verbs.h" #include "verbs.h"
#include "aspm.h" #include "aspm.h"
#include "affinity.h"
#undef pr_fmt #undef pr_fmt
#define pr_fmt(fmt) DRIVER_NAME ": " fmt #define pr_fmt(fmt) DRIVER_NAME ": " fmt
...@@ -474,8 +475,9 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t) ...@@ -474,8 +475,9 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t)
void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd, void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
struct hfi1_devdata *dd, u8 hw_pidx, u8 port) struct hfi1_devdata *dd, u8 hw_pidx, u8 port)
{ {
int i, size; int i;
uint default_pkey_idx; uint default_pkey_idx;
struct cc_state *cc_state;
ppd->dd = dd; ppd->dd = dd;
ppd->hw_pidx = hw_pidx; ppd->hw_pidx = hw_pidx;
...@@ -526,9 +528,9 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd, ...@@ -526,9 +528,9 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
spin_lock_init(&ppd->cc_state_lock); spin_lock_init(&ppd->cc_state_lock);
spin_lock_init(&ppd->cc_log_lock); spin_lock_init(&ppd->cc_log_lock);
size = sizeof(struct cc_state); cc_state = kzalloc(sizeof(*cc_state), GFP_KERNEL);
RCU_INIT_POINTER(ppd->cc_state, kzalloc(size, GFP_KERNEL)); RCU_INIT_POINTER(ppd->cc_state, cc_state);
if (!rcu_dereference(ppd->cc_state)) if (!cc_state)
goto bail; goto bail;
return; return;
...@@ -972,39 +974,49 @@ void hfi1_free_ctxtdata(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) ...@@ -972,39 +974,49 @@ void hfi1_free_ctxtdata(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
/* /*
* Release our hold on the shared asic data. If we are the last one, * Release our hold on the shared asic data. If we are the last one,
* free the structure. Must be holding hfi1_devs_lock. * return the structure to be finalized outside the lock. Must be
* holding hfi1_devs_lock.
*/ */
static void release_asic_data(struct hfi1_devdata *dd) static struct hfi1_asic_data *release_asic_data(struct hfi1_devdata *dd)
{ {
struct hfi1_asic_data *ad;
int other; int other;
if (!dd->asic_data) if (!dd->asic_data)
return; return NULL;
dd->asic_data->dds[dd->hfi1_id] = NULL; dd->asic_data->dds[dd->hfi1_id] = NULL;
other = dd->hfi1_id ? 0 : 1; other = dd->hfi1_id ? 0 : 1;
if (!dd->asic_data->dds[other]) { ad = dd->asic_data;
/* we are the last holder, free it */
kfree(dd->asic_data);
}
dd->asic_data = NULL; dd->asic_data = NULL;
/* return NULL if the other dd still has a link */
return ad->dds[other] ? NULL : ad;
}
static void finalize_asic_data(struct hfi1_devdata *dd,
struct hfi1_asic_data *ad)
{
clean_up_i2c(dd, ad);
kfree(ad);
} }
static void __hfi1_free_devdata(struct kobject *kobj) static void __hfi1_free_devdata(struct kobject *kobj)
{ {
struct hfi1_devdata *dd = struct hfi1_devdata *dd =
container_of(kobj, struct hfi1_devdata, kobj); container_of(kobj, struct hfi1_devdata, kobj);
struct hfi1_asic_data *ad;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&hfi1_devs_lock, flags); spin_lock_irqsave(&hfi1_devs_lock, flags);
idr_remove(&hfi1_unit_table, dd->unit); idr_remove(&hfi1_unit_table, dd->unit);
list_del(&dd->list); list_del(&dd->list);
release_asic_data(dd); ad = release_asic_data(dd);
spin_unlock_irqrestore(&hfi1_devs_lock, flags); spin_unlock_irqrestore(&hfi1_devs_lock, flags);
if (ad)
finalize_asic_data(dd, ad);
free_platform_config(dd); free_platform_config(dd);
rcu_barrier(); /* wait for rcu callbacks to complete */ rcu_barrier(); /* wait for rcu callbacks to complete */
free_percpu(dd->int_counter); free_percpu(dd->int_counter);
free_percpu(dd->rcv_limit); free_percpu(dd->rcv_limit);
hfi1_dev_affinity_free(dd);
free_percpu(dd->send_schedule); free_percpu(dd->send_schedule);
rvt_dealloc_device(&dd->verbs_dev.rdi); rvt_dealloc_device(&dd->verbs_dev.rdi);
} }
...@@ -1162,7 +1174,7 @@ static int init_one(struct pci_dev *, const struct pci_device_id *); ...@@ -1162,7 +1174,7 @@ static int init_one(struct pci_dev *, const struct pci_device_id *);
#define DRIVER_LOAD_MSG "Intel " DRIVER_NAME " loaded: " #define DRIVER_LOAD_MSG "Intel " DRIVER_NAME " loaded: "
#define PFX DRIVER_NAME ": " #define PFX DRIVER_NAME ": "
static const struct pci_device_id hfi1_pci_tbl[] = { const struct pci_device_id hfi1_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL0) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL1) },
{ 0, } { 0, }
...@@ -1198,6 +1210,10 @@ static int __init hfi1_mod_init(void) ...@@ -1198,6 +1210,10 @@ static int __init hfi1_mod_init(void)
if (ret) if (ret)
goto bail; goto bail;
ret = node_affinity_init();
if (ret)
goto bail;
/* validate max MTU before any devices start */ /* validate max MTU before any devices start */
if (!valid_opa_max_mtu(hfi1_max_mtu)) { if (!valid_opa_max_mtu(hfi1_max_mtu)) {
pr_err("Invalid max_mtu 0x%x, using 0x%x instead\n", pr_err("Invalid max_mtu 0x%x, using 0x%x instead\n",
...@@ -1278,6 +1294,7 @@ module_init(hfi1_mod_init); ...@@ -1278,6 +1294,7 @@ module_init(hfi1_mod_init);
static void __exit hfi1_mod_cleanup(void) static void __exit hfi1_mod_cleanup(void)
{ {
pci_unregister_driver(&hfi1_pci_driver); pci_unregister_driver(&hfi1_pci_driver);
node_affinity_destroy();
hfi1_wss_exit(); hfi1_wss_exit();
hfi1_dbg_exit(); hfi1_dbg_exit();
hfi1_cpulist_count = 0; hfi1_cpulist_count = 0;
...@@ -1311,7 +1328,7 @@ static void cleanup_device_data(struct hfi1_devdata *dd) ...@@ -1311,7 +1328,7 @@ static void cleanup_device_data(struct hfi1_devdata *dd)
hrtimer_cancel(&ppd->cca_timer[i].hrtimer); hrtimer_cancel(&ppd->cca_timer[i].hrtimer);
spin_lock(&ppd->cc_state_lock); spin_lock(&ppd->cc_state_lock);
cc_state = get_cc_state(ppd); cc_state = get_cc_state_protected(ppd);
RCU_INIT_POINTER(ppd->cc_state, NULL); RCU_INIT_POINTER(ppd->cc_state, NULL);
spin_unlock(&ppd->cc_state_lock); spin_unlock(&ppd->cc_state_lock);
...@@ -1760,8 +1777,8 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd) ...@@ -1760,8 +1777,8 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd)
hfi1_cdbg(PROC, hfi1_cdbg(PROC,
"ctxt%u: Alloced %u rcv tid entries @ %uKB, total %zuKB\n", "ctxt%u: Alloced %u rcv tid entries @ %uKB, total %zuKB\n",
rcd->ctxt, rcd->egrbufs.alloced, rcd->egrbufs.rcvtid_size, rcd->ctxt, rcd->egrbufs.alloced,
rcd->egrbufs.size); rcd->egrbufs.rcvtid_size / 1024, rcd->egrbufs.size / 1024);
/* /*
* Set the contexts rcv array head update threshold to the closest * Set the contexts rcv array head update threshold to the closest
......
...@@ -588,7 +588,6 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, ...@@ -588,7 +588,6 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
pi->port_phys_conf = (ppd->port_type & 0xf); pi->port_phys_conf = (ppd->port_type & 0xf);
#if PI_LED_ENABLE_SUP
pi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; pi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4;
pi->port_states.ledenable_offlinereason |= pi->port_states.ledenable_offlinereason |=
ppd->is_sm_config_started << 5; ppd->is_sm_config_started << 5;
...@@ -602,11 +601,6 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, ...@@ -602,11 +601,6 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
pi->port_states.ledenable_offlinereason |= is_beaconing_active << 6; pi->port_states.ledenable_offlinereason |= is_beaconing_active << 6;
pi->port_states.ledenable_offlinereason |= pi->port_states.ledenable_offlinereason |=
ppd->offline_disabled_reason; ppd->offline_disabled_reason;
#else
pi->port_states.offline_reason = ppd->neighbor_normal << 4;
pi->port_states.offline_reason |= ppd->is_sm_config_started << 5;
pi->port_states.offline_reason |= ppd->offline_disabled_reason;
#endif /* PI_LED_ENABLE_SUP */
pi->port_states.portphysstate_portstate = pi->port_states.portphysstate_portstate =
(hfi1_ibphys_portstate(ppd) << 4) | state; (hfi1_ibphys_portstate(ppd) << 4) | state;
...@@ -1752,17 +1746,11 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data, ...@@ -1752,17 +1746,11 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
if (start_of_sm_config && (lstate == IB_PORT_INIT)) if (start_of_sm_config && (lstate == IB_PORT_INIT))
ppd->is_sm_config_started = 1; ppd->is_sm_config_started = 1;
#if PI_LED_ENABLE_SUP
psi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; psi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4;
psi->port_states.ledenable_offlinereason |= psi->port_states.ledenable_offlinereason |=
ppd->is_sm_config_started << 5; ppd->is_sm_config_started << 5;
psi->port_states.ledenable_offlinereason |= psi->port_states.ledenable_offlinereason |=
ppd->offline_disabled_reason; ppd->offline_disabled_reason;
#else
psi->port_states.offline_reason = ppd->neighbor_normal << 4;
psi->port_states.offline_reason |= ppd->is_sm_config_started << 5;
psi->port_states.offline_reason |= ppd->offline_disabled_reason;
#endif /* PI_LED_ENABLE_SUP */
psi->port_states.portphysstate_portstate = psi->port_states.portphysstate_portstate =
(hfi1_ibphys_portstate(ppd) << 4) | (lstate & 0xf); (hfi1_ibphys_portstate(ppd) << 4) | (lstate & 0xf);
...@@ -2430,14 +2418,9 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp, ...@@ -2430,14 +2418,9 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
rsp->port_rcv_remote_physical_errors = rsp->port_rcv_remote_physical_errors =
cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR,
CNTR_INVALID_VL)); CNTR_INVALID_VL));
tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL); rsp->local_link_integrity_errors =
tmp2 = tmp + read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL); cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY,
if (tmp2 < tmp) { CNTR_INVALID_VL));
/* overflow/wrapped */
rsp->local_link_integrity_errors = cpu_to_be64(~0);
} else {
rsp->local_link_integrity_errors = cpu_to_be64(tmp2);
}
tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL);
tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT,
CNTR_INVALID_VL); CNTR_INVALID_VL);
...@@ -2499,6 +2482,9 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp, ...@@ -2499,6 +2482,9 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL, cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL,
idx_from_vl(vl))); idx_from_vl(vl)));
rsp->vls[vfi].port_vl_xmit_discards =
cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL,
idx_from_vl(vl)));
vlinfo++; vlinfo++;
vfi++; vfi++;
} }
...@@ -2529,9 +2515,8 @@ static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port, ...@@ -2529,9 +2515,8 @@ static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port,
error_counter_summary += read_dev_cntr(dd, C_DC_RMT_PHY_ERR, error_counter_summary += read_dev_cntr(dd, C_DC_RMT_PHY_ERR,
CNTR_INVALID_VL); CNTR_INVALID_VL);
/* local link integrity must be right-shifted by the lli resolution */ /* local link integrity must be right-shifted by the lli resolution */
tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL); error_counter_summary += (read_dev_cntr(dd, C_DC_RX_REPLAY,
tmp += read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL); CNTR_INVALID_VL) >> res_lli);
error_counter_summary += (tmp >> res_lli);
/* link error recovery must b right-shifted by the ler resolution */ /* link error recovery must b right-shifted by the ler resolution */
tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL);
tmp += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL); tmp += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL);
...@@ -2800,14 +2785,9 @@ static void pma_get_opa_port_ectrs(struct ib_device *ibdev, ...@@ -2800,14 +2785,9 @@ static void pma_get_opa_port_ectrs(struct ib_device *ibdev,
rsp->port_rcv_constraint_errors = rsp->port_rcv_constraint_errors =
cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR,
CNTR_INVALID_VL)); CNTR_INVALID_VL));
tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL); rsp->local_link_integrity_errors =
tmp2 = tmp + read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL); cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY,
if (tmp2 < tmp) { CNTR_INVALID_VL));
/* overflow/wrapped */
rsp->local_link_integrity_errors = cpu_to_be64(~0);
} else {
rsp->local_link_integrity_errors = cpu_to_be64(tmp2);
}
rsp->excessive_buffer_overruns = rsp->excessive_buffer_overruns =
cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL)); cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL));
} }
...@@ -2883,14 +2863,17 @@ static int pma_get_opa_porterrors(struct opa_pma_mad *pmp, ...@@ -2883,14 +2863,17 @@ static int pma_get_opa_porterrors(struct opa_pma_mad *pmp,
tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL);
rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff; rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff;
rsp->port_rcv_errors =
cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL));
vlinfo = &rsp->vls[0]; vlinfo = &rsp->vls[0];
vfi = 0; vfi = 0;
vl_select_mask = be32_to_cpu(req->vl_select_mask); vl_select_mask = be32_to_cpu(req->vl_select_mask);
for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), for_each_set_bit(vl, (unsigned long *)&(vl_select_mask),
8 * sizeof(req->vl_select_mask)) { 8 * sizeof(req->vl_select_mask)) {
memset(vlinfo, 0, sizeof(*vlinfo)); memset(vlinfo, 0, sizeof(*vlinfo));
/* vlinfo->vls[vfi].port_vl_xmit_discards ??? */ rsp->vls[vfi].port_vl_xmit_discards =
cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL,
idx_from_vl(vl)));
vlinfo += 1; vlinfo += 1;
vfi++; vfi++;
} }
...@@ -3162,10 +3145,8 @@ static int pma_set_opa_portstatus(struct opa_pma_mad *pmp, ...@@ -3162,10 +3145,8 @@ static int pma_set_opa_portstatus(struct opa_pma_mad *pmp,
if (counter_select & CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS) if (counter_select & CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS)
write_dev_cntr(dd, C_DC_RMT_PHY_ERR, CNTR_INVALID_VL, 0); write_dev_cntr(dd, C_DC_RMT_PHY_ERR, CNTR_INVALID_VL, 0);
if (counter_select & CS_LOCAL_LINK_INTEGRITY_ERRORS) { if (counter_select & CS_LOCAL_LINK_INTEGRITY_ERRORS)
write_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL, 0);
write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0);
}
if (counter_select & CS_LINK_ERROR_RECOVERY) { if (counter_select & CS_LINK_ERROR_RECOVERY) {
write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0);
...@@ -3223,7 +3204,9 @@ static int pma_set_opa_portstatus(struct opa_pma_mad *pmp, ...@@ -3223,7 +3204,9 @@ static int pma_set_opa_portstatus(struct opa_pma_mad *pmp,
/* if (counter_select & CS_PORT_MARK_FECN) /* if (counter_select & CS_PORT_MARK_FECN)
* write_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT + offset, 0); * write_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT + offset, 0);
*/ */
/* port_vl_xmit_discards ??? */ if (counter_select & C_SW_XMIT_DSCD_VL)
write_port_cntr(ppd, C_SW_XMIT_DSCD_VL,
idx_from_vl(vl), 0);
} }
if (resp_len) if (resp_len)
...@@ -3392,7 +3375,7 @@ static void apply_cc_state(struct hfi1_pportdata *ppd) ...@@ -3392,7 +3375,7 @@ static void apply_cc_state(struct hfi1_pportdata *ppd)
*/ */
spin_lock(&ppd->cc_state_lock); spin_lock(&ppd->cc_state_lock);
old_cc_state = get_cc_state(ppd); old_cc_state = get_cc_state_protected(ppd);
if (!old_cc_state) { if (!old_cc_state) {
/* never active, or shutting down */ /* never active, or shutting down */
spin_unlock(&ppd->cc_state_lock); spin_unlock(&ppd->cc_state_lock);
...@@ -3960,7 +3943,6 @@ void clear_linkup_counters(struct hfi1_devdata *dd) ...@@ -3960,7 +3943,6 @@ void clear_linkup_counters(struct hfi1_devdata *dd)
write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0);
write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL, 0); write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL, 0);
/* LocalLinkIntegrityErrors */ /* LocalLinkIntegrityErrors */
write_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL, 0);
write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0);
/* ExcessiveBufferOverruns */ /* ExcessiveBufferOverruns */
write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0); write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0);
......
...@@ -48,15 +48,8 @@ ...@@ -48,15 +48,8 @@
#define _HFI1_MAD_H #define _HFI1_MAD_H
#include <rdma/ib_pma.h> #include <rdma/ib_pma.h>
#define USE_PI_LED_ENABLE 1 /*
* use led enabled bit in struct
* opa_port_states, if available
*/
#include <rdma/opa_smi.h> #include <rdma/opa_smi.h>
#include <rdma/opa_port_info.h> #include <rdma/opa_port_info.h>
#ifndef PI_LED_ENABLE_SUP
#define PI_LED_ENABLE_SUP 0
#endif
#include "opa_compat.h" #include "opa_compat.h"
/* /*
......
...@@ -53,19 +53,20 @@ ...@@ -53,19 +53,20 @@
#include "trace.h" #include "trace.h"
struct mmu_rb_handler { struct mmu_rb_handler {
struct list_head list;
struct mmu_notifier mn; struct mmu_notifier mn;
struct rb_root *root; struct rb_root root;
void *ops_arg;
spinlock_t lock; /* protect the RB tree */ spinlock_t lock; /* protect the RB tree */
struct mmu_rb_ops *ops; struct mmu_rb_ops *ops;
struct mm_struct *mm;
struct list_head lru_list;
struct work_struct del_work;
struct list_head del_list;
struct workqueue_struct *wq;
}; };
static LIST_HEAD(mmu_rb_handlers);
static DEFINE_SPINLOCK(mmu_rb_lock); /* protect mmu_rb_handlers list */
static unsigned long mmu_node_start(struct mmu_rb_node *); static unsigned long mmu_node_start(struct mmu_rb_node *);
static unsigned long mmu_node_last(struct mmu_rb_node *); static unsigned long mmu_node_last(struct mmu_rb_node *);
static struct mmu_rb_handler *find_mmu_handler(struct rb_root *);
static inline void mmu_notifier_page(struct mmu_notifier *, struct mm_struct *, static inline void mmu_notifier_page(struct mmu_notifier *, struct mm_struct *,
unsigned long); unsigned long);
static inline void mmu_notifier_range_start(struct mmu_notifier *, static inline void mmu_notifier_range_start(struct mmu_notifier *,
...@@ -76,6 +77,9 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *, ...@@ -76,6 +77,9 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *,
unsigned long, unsigned long); unsigned long, unsigned long);
static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *, static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *,
unsigned long, unsigned long); unsigned long, unsigned long);
static void do_remove(struct mmu_rb_handler *handler,
struct list_head *del_list);
static void handle_remove(struct work_struct *work);
static struct mmu_notifier_ops mn_opts = { static struct mmu_notifier_ops mn_opts = {
.invalidate_page = mmu_notifier_page, .invalidate_page = mmu_notifier_page,
...@@ -95,73 +99,79 @@ static unsigned long mmu_node_last(struct mmu_rb_node *node) ...@@ -95,73 +99,79 @@ static unsigned long mmu_node_last(struct mmu_rb_node *node)
return PAGE_ALIGN(node->addr + node->len) - 1; return PAGE_ALIGN(node->addr + node->len) - 1;
} }
int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops) int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm,
struct mmu_rb_ops *ops,
struct workqueue_struct *wq,
struct mmu_rb_handler **handler)
{ {
struct mmu_rb_handler *handlr; struct mmu_rb_handler *handlr;
int ret;
if (!ops->invalidate)
return -EINVAL;
handlr = kmalloc(sizeof(*handlr), GFP_KERNEL); handlr = kmalloc(sizeof(*handlr), GFP_KERNEL);
if (!handlr) if (!handlr)
return -ENOMEM; return -ENOMEM;
handlr->root = root; handlr->root = RB_ROOT;
handlr->ops = ops; handlr->ops = ops;
handlr->ops_arg = ops_arg;
INIT_HLIST_NODE(&handlr->mn.hlist); INIT_HLIST_NODE(&handlr->mn.hlist);
spin_lock_init(&handlr->lock); spin_lock_init(&handlr->lock);
handlr->mn.ops = &mn_opts; handlr->mn.ops = &mn_opts;
spin_lock(&mmu_rb_lock); handlr->mm = mm;
list_add_tail_rcu(&handlr->list, &mmu_rb_handlers); INIT_WORK(&handlr->del_work, handle_remove);
spin_unlock(&mmu_rb_lock); INIT_LIST_HEAD(&handlr->del_list);
INIT_LIST_HEAD(&handlr->lru_list);
handlr->wq = wq;
ret = mmu_notifier_register(&handlr->mn, handlr->mm);
if (ret) {
kfree(handlr);
return ret;
}
return mmu_notifier_register(&handlr->mn, current->mm); *handler = handlr;
return 0;
} }
void hfi1_mmu_rb_unregister(struct rb_root *root) void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler)
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root); struct mmu_rb_node *rbnode;
struct rb_node *node;
unsigned long flags; unsigned long flags;
struct list_head del_list;
if (!handler)
return;
/* Unregister first so we don't get any more notifications. */ /* Unregister first so we don't get any more notifications. */
if (current->mm) mmu_notifier_unregister(&handler->mn, handler->mm);
mmu_notifier_unregister(&handler->mn, current->mm);
spin_lock(&mmu_rb_lock); /*
list_del_rcu(&handler->list); * Make sure the wq delete handler is finished running. It will not
spin_unlock(&mmu_rb_lock); * be triggered once the mmu notifiers are unregistered above.
synchronize_rcu(); */
flush_work(&handler->del_work);
INIT_LIST_HEAD(&del_list);
spin_lock_irqsave(&handler->lock, flags); spin_lock_irqsave(&handler->lock, flags);
if (!RB_EMPTY_ROOT(root)) { while ((node = rb_first(&handler->root))) {
struct rb_node *node; rbnode = rb_entry(node, struct mmu_rb_node, node);
struct mmu_rb_node *rbnode; rb_erase(node, &handler->root);
/* move from LRU list to delete list */
while ((node = rb_first(root))) { list_move(&rbnode->list, &del_list);
rbnode = rb_entry(node, struct mmu_rb_node, node);
rb_erase(node, root);
if (handler->ops->remove)
handler->ops->remove(root, rbnode, NULL);
}
} }
spin_unlock_irqrestore(&handler->lock, flags); spin_unlock_irqrestore(&handler->lock, flags);
do_remove(handler, &del_list);
kfree(handler); kfree(handler);
} }
int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode) int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler,
struct mmu_rb_node *mnode)
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root);
struct mmu_rb_node *node; struct mmu_rb_node *node;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
if (!handler)
return -EINVAL;
spin_lock_irqsave(&handler->lock, flags); spin_lock_irqsave(&handler->lock, flags);
hfi1_cdbg(MMU, "Inserting node addr 0x%llx, len %u", mnode->addr, hfi1_cdbg(MMU, "Inserting node addr 0x%llx, len %u", mnode->addr,
mnode->len); mnode->len);
...@@ -170,12 +180,13 @@ int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode) ...@@ -170,12 +180,13 @@ int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode)
ret = -EINVAL; ret = -EINVAL;
goto unlock; goto unlock;
} }
__mmu_int_rb_insert(mnode, root); __mmu_int_rb_insert(mnode, &handler->root);
list_add(&mnode->list, &handler->lru_list);
if (handler->ops->insert) { ret = handler->ops->insert(handler->ops_arg, mnode);
ret = handler->ops->insert(root, mnode); if (ret) {
if (ret) __mmu_int_rb_remove(mnode, &handler->root);
__mmu_int_rb_remove(mnode, root); list_del(&mnode->list); /* remove from LRU list */
} }
unlock: unlock:
spin_unlock_irqrestore(&handler->lock, flags); spin_unlock_irqrestore(&handler->lock, flags);
...@@ -191,10 +202,10 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, ...@@ -191,10 +202,10 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler,
hfi1_cdbg(MMU, "Searching for addr 0x%llx, len %u", addr, len); hfi1_cdbg(MMU, "Searching for addr 0x%llx, len %u", addr, len);
if (!handler->ops->filter) { if (!handler->ops->filter) {
node = __mmu_int_rb_iter_first(handler->root, addr, node = __mmu_int_rb_iter_first(&handler->root, addr,
(addr + len) - 1); (addr + len) - 1);
} else { } else {
for (node = __mmu_int_rb_iter_first(handler->root, addr, for (node = __mmu_int_rb_iter_first(&handler->root, addr,
(addr + len) - 1); (addr + len) - 1);
node; node;
node = __mmu_int_rb_iter_next(node, addr, node = __mmu_int_rb_iter_next(node, addr,
...@@ -206,82 +217,72 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, ...@@ -206,82 +217,72 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler,
return node; return node;
} }
/* Caller must *not* hold handler lock. */ struct mmu_rb_node *hfi1_mmu_rb_extract(struct mmu_rb_handler *handler,
static void __mmu_rb_remove(struct mmu_rb_handler *handler, unsigned long addr, unsigned long len)
struct mmu_rb_node *node, struct mm_struct *mm)
{
unsigned long flags;
/* Validity of handler and node pointers has been checked by caller. */
hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr,
node->len);
spin_lock_irqsave(&handler->lock, flags);
__mmu_int_rb_remove(node, handler->root);
spin_unlock_irqrestore(&handler->lock, flags);
if (handler->ops->remove)
handler->ops->remove(handler->root, node, mm);
}
struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr,
unsigned long len)
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root);
struct mmu_rb_node *node; struct mmu_rb_node *node;
unsigned long flags; unsigned long flags;
if (!handler)
return ERR_PTR(-EINVAL);
spin_lock_irqsave(&handler->lock, flags); spin_lock_irqsave(&handler->lock, flags);
node = __mmu_rb_search(handler, addr, len); node = __mmu_rb_search(handler, addr, len);
if (node) {
__mmu_int_rb_remove(node, &handler->root);
list_del(&node->list); /* remove from LRU list */
}
spin_unlock_irqrestore(&handler->lock, flags); spin_unlock_irqrestore(&handler->lock, flags);
return node; return node;
} }
struct mmu_rb_node *hfi1_mmu_rb_extract(struct rb_root *root, void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg)
unsigned long addr, unsigned long len)
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root); struct mmu_rb_node *rbnode, *ptr;
struct mmu_rb_node *node; struct list_head del_list;
unsigned long flags; unsigned long flags;
bool stop = false;
if (!handler) INIT_LIST_HEAD(&del_list);
return ERR_PTR(-EINVAL);
spin_lock_irqsave(&handler->lock, flags); spin_lock_irqsave(&handler->lock, flags);
node = __mmu_rb_search(handler, addr, len); list_for_each_entry_safe_reverse(rbnode, ptr, &handler->lru_list,
if (node) list) {
__mmu_int_rb_remove(node, handler->root); if (handler->ops->evict(handler->ops_arg, rbnode, evict_arg,
&stop)) {
__mmu_int_rb_remove(rbnode, &handler->root);
/* move from LRU list to delete list */
list_move(&rbnode->list, &del_list);
}
if (stop)
break;
}
spin_unlock_irqrestore(&handler->lock, flags); spin_unlock_irqrestore(&handler->lock, flags);
return node; while (!list_empty(&del_list)) {
rbnode = list_first_entry(&del_list, struct mmu_rb_node, list);
list_del(&rbnode->list);
handler->ops->remove(handler->ops_arg, rbnode);
}
} }
void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node) /*
* It is up to the caller to ensure that this function does not race with the
* mmu invalidate notifier which may be calling the users remove callback on
* 'node'.
*/
void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler,
struct mmu_rb_node *node)
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root); unsigned long flags;
if (!handler || !node)
return;
__mmu_rb_remove(handler, node, NULL);
}
static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root) /* Validity of handler and node pointers has been checked by caller. */
{ hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr,
struct mmu_rb_handler *handler; node->len);
spin_lock_irqsave(&handler->lock, flags);
__mmu_int_rb_remove(node, &handler->root);
list_del(&node->list); /* remove from LRU list */
spin_unlock_irqrestore(&handler->lock, flags);
rcu_read_lock(); handler->ops->remove(handler->ops_arg, node);
list_for_each_entry_rcu(handler, &mmu_rb_handlers, list) {
if (handler->root == root)
goto unlock;
}
handler = NULL;
unlock:
rcu_read_unlock();
return handler;
} }
static inline void mmu_notifier_page(struct mmu_notifier *mn, static inline void mmu_notifier_page(struct mmu_notifier *mn,
...@@ -304,9 +305,10 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, ...@@ -304,9 +305,10 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn,
{ {
struct mmu_rb_handler *handler = struct mmu_rb_handler *handler =
container_of(mn, struct mmu_rb_handler, mn); container_of(mn, struct mmu_rb_handler, mn);
struct rb_root *root = handler->root; struct rb_root *root = &handler->root;
struct mmu_rb_node *node, *ptr = NULL; struct mmu_rb_node *node, *ptr = NULL;
unsigned long flags; unsigned long flags;
bool added = false;
spin_lock_irqsave(&handler->lock, flags); spin_lock_irqsave(&handler->lock, flags);
for (node = __mmu_int_rb_iter_first(root, start, end - 1); for (node = __mmu_int_rb_iter_first(root, start, end - 1);
...@@ -315,11 +317,53 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, ...@@ -315,11 +317,53 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn,
ptr = __mmu_int_rb_iter_next(node, start, end - 1); ptr = __mmu_int_rb_iter_next(node, start, end - 1);
hfi1_cdbg(MMU, "Invalidating node addr 0x%llx, len %u", hfi1_cdbg(MMU, "Invalidating node addr 0x%llx, len %u",
node->addr, node->len); node->addr, node->len);
if (handler->ops->invalidate(root, node)) { if (handler->ops->invalidate(handler->ops_arg, node)) {
__mmu_int_rb_remove(node, root); __mmu_int_rb_remove(node, root);
if (handler->ops->remove) /* move from LRU list to delete list */
handler->ops->remove(root, node, mm); list_move(&node->list, &handler->del_list);
added = true;
} }
} }
spin_unlock_irqrestore(&handler->lock, flags); spin_unlock_irqrestore(&handler->lock, flags);
if (added)
queue_work(handler->wq, &handler->del_work);
}
/*
* Call the remove function for the given handler and the list. This
* is expected to be called with a delete list extracted from handler.
* The caller should not be holding the handler lock.
*/
static void do_remove(struct mmu_rb_handler *handler,
struct list_head *del_list)
{
struct mmu_rb_node *node;
while (!list_empty(del_list)) {
node = list_first_entry(del_list, struct mmu_rb_node, list);
list_del(&node->list);
handler->ops->remove(handler->ops_arg, node);
}
}
/*
* Work queue function to remove all nodes that have been queued up to
* be removed. The key feature is that mm->mmap_sem is not being held
* and the remove callback can sleep while taking it, if needed.
*/
static void handle_remove(struct work_struct *work)
{
struct mmu_rb_handler *handler = container_of(work,
struct mmu_rb_handler,
del_work);
struct list_head del_list;
unsigned long flags;
/* remove anything that is queued to get removed */
spin_lock_irqsave(&handler->lock, flags);
list_replace_init(&handler->del_list, &del_list);
spin_unlock_irqrestore(&handler->lock, flags);
do_remove(handler, &del_list);
} }
...@@ -54,23 +54,34 @@ struct mmu_rb_node { ...@@ -54,23 +54,34 @@ struct mmu_rb_node {
unsigned long len; unsigned long len;
unsigned long __last; unsigned long __last;
struct rb_node node; struct rb_node node;
struct list_head list;
}; };
/*
* NOTE: filter, insert, invalidate, and evict must not sleep. Only remove is
* allowed to sleep.
*/
struct mmu_rb_ops { struct mmu_rb_ops {
bool (*filter)(struct mmu_rb_node *, unsigned long, unsigned long); bool (*filter)(struct mmu_rb_node *node, unsigned long addr,
int (*insert)(struct rb_root *, struct mmu_rb_node *); unsigned long len);
void (*remove)(struct rb_root *, struct mmu_rb_node *, int (*insert)(void *ops_arg, struct mmu_rb_node *mnode);
struct mm_struct *); void (*remove)(void *ops_arg, struct mmu_rb_node *mnode);
int (*invalidate)(struct rb_root *, struct mmu_rb_node *); int (*invalidate)(void *ops_arg, struct mmu_rb_node *node);
int (*evict)(void *ops_arg, struct mmu_rb_node *mnode,
void *evict_arg, bool *stop);
}; };
int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops); int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm,
void hfi1_mmu_rb_unregister(struct rb_root *); struct mmu_rb_ops *ops,
int hfi1_mmu_rb_insert(struct rb_root *, struct mmu_rb_node *); struct workqueue_struct *wq,
void hfi1_mmu_rb_remove(struct rb_root *, struct mmu_rb_node *); struct mmu_rb_handler **handler);
struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *, unsigned long, void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler);
unsigned long); int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler,
struct mmu_rb_node *hfi1_mmu_rb_extract(struct rb_root *, unsigned long, struct mmu_rb_node *mnode);
unsigned long); void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg);
void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler,
struct mmu_rb_node *mnode);
struct mmu_rb_node *hfi1_mmu_rb_extract(struct mmu_rb_handler *handler,
unsigned long addr, unsigned long len);
#endif /* _HFI1_MMU_RB_H */ #endif /* _HFI1_MMU_RB_H */
...@@ -679,6 +679,10 @@ static uint pcie_pset = UNSET_PSET; ...@@ -679,6 +679,10 @@ static uint pcie_pset = UNSET_PSET;
module_param(pcie_pset, uint, S_IRUGO); module_param(pcie_pset, uint, S_IRUGO);
MODULE_PARM_DESC(pcie_pset, "PCIe Eq Pset value to use, range is 0-10"); MODULE_PARM_DESC(pcie_pset, "PCIe Eq Pset value to use, range is 0-10");
static uint pcie_ctle = 1; /* discrete on, integrated off */
module_param(pcie_ctle, uint, S_IRUGO);
MODULE_PARM_DESC(pcie_ctle, "PCIe static CTLE mode, bit 0 - discrete on/off, bit 1 - integrated on/off");
/* equalization columns */ /* equalization columns */
#define PREC 0 #define PREC 0
#define ATTN 1 #define ATTN 1
...@@ -716,6 +720,36 @@ static const u8 integrated_preliminary_eq[11][3] = { ...@@ -716,6 +720,36 @@ static const u8 integrated_preliminary_eq[11][3] = {
{ 0x00, 0x1e, 0x0a }, /* p10 */ { 0x00, 0x1e, 0x0a }, /* p10 */
}; };
static const u8 discrete_ctle_tunings[11][4] = {
/* DC LF HF BW */
{ 0x48, 0x0b, 0x04, 0x04 }, /* p0 */
{ 0x60, 0x05, 0x0f, 0x0a }, /* p1 */
{ 0x50, 0x09, 0x06, 0x06 }, /* p2 */
{ 0x68, 0x05, 0x0f, 0x0a }, /* p3 */
{ 0x80, 0x05, 0x0f, 0x0a }, /* p4 */
{ 0x70, 0x05, 0x0f, 0x0a }, /* p5 */
{ 0x68, 0x05, 0x0f, 0x0a }, /* p6 */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p7 */
{ 0x48, 0x09, 0x06, 0x06 }, /* p8 */
{ 0x60, 0x05, 0x0f, 0x0a }, /* p9 */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p10 */
};
static const u8 integrated_ctle_tunings[11][4] = {
/* DC LF HF BW */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p0 */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p1 */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p2 */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p3 */
{ 0x58, 0x0a, 0x05, 0x05 }, /* p4 */
{ 0x48, 0x0a, 0x05, 0x05 }, /* p5 */
{ 0x40, 0x0a, 0x05, 0x05 }, /* p6 */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p7 */
{ 0x38, 0x0f, 0x00, 0x00 }, /* p8 */
{ 0x38, 0x09, 0x06, 0x06 }, /* p9 */
{ 0x38, 0x0e, 0x01, 0x01 }, /* p10 */
};
/* helper to format the value to write to hardware */ /* helper to format the value to write to hardware */
#define eq_value(pre, curr, post) \ #define eq_value(pre, curr, post) \
((((u32)(pre)) << \ ((((u32)(pre)) << \
...@@ -951,11 +985,14 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd) ...@@ -951,11 +985,14 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
u32 status, err; u32 status, err;
int ret; int ret;
int do_retry, retry_count = 0; int do_retry, retry_count = 0;
int intnum = 0;
uint default_pset; uint default_pset;
u16 target_vector, target_speed; u16 target_vector, target_speed;
u16 lnkctl2, vendor; u16 lnkctl2, vendor;
u8 div; u8 div;
const u8 (*eq)[3]; const u8 (*eq)[3];
const u8 (*ctle_tunings)[4];
uint static_ctle_mode;
int return_error = 0; int return_error = 0;
/* PCIe Gen3 is for the ASIC only */ /* PCIe Gen3 is for the ASIC only */
...@@ -1089,6 +1126,9 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd) ...@@ -1089,6 +1126,9 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
div = 3; div = 3;
eq = discrete_preliminary_eq; eq = discrete_preliminary_eq;
default_pset = DEFAULT_DISCRETE_PSET; default_pset = DEFAULT_DISCRETE_PSET;
ctle_tunings = discrete_ctle_tunings;
/* bit 0 - discrete on/off */
static_ctle_mode = pcie_ctle & 0x1;
} else { } else {
/* 400mV, FS=29, LF = 9 */ /* 400mV, FS=29, LF = 9 */
fs = 29; fs = 29;
...@@ -1096,6 +1136,9 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd) ...@@ -1096,6 +1136,9 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
div = 1; div = 1;
eq = integrated_preliminary_eq; eq = integrated_preliminary_eq;
default_pset = DEFAULT_MCP_PSET; default_pset = DEFAULT_MCP_PSET;
ctle_tunings = integrated_ctle_tunings;
/* bit 1 - integrated on/off */
static_ctle_mode = (pcie_ctle >> 1) & 0x1;
} }
pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL101, pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL101,
(fs << (fs <<
...@@ -1135,16 +1178,33 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd) ...@@ -1135,16 +1178,33 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
* step 5c: Program gasket interrupts * step 5c: Program gasket interrupts
*/ */
/* set the Rx Bit Rate to REFCLK ratio */ /* set the Rx Bit Rate to REFCLK ratio */
write_gasket_interrupt(dd, 0, 0x0006, 0x0050); write_gasket_interrupt(dd, intnum++, 0x0006, 0x0050);
/* disable pCal for PCIe Gen3 RX equalization */ /* disable pCal for PCIe Gen3 RX equalization */
write_gasket_interrupt(dd, 1, 0x0026, 0x5b01); /* select adaptive or static CTLE */
write_gasket_interrupt(dd, intnum++, 0x0026,
0x5b01 | (static_ctle_mode << 3));
/* /*
* Enable iCal for PCIe Gen3 RX equalization, and set which * Enable iCal for PCIe Gen3 RX equalization, and set which
* evaluation of RX_EQ_EVAL will launch the iCal procedure. * evaluation of RX_EQ_EVAL will launch the iCal procedure.
*/ */
write_gasket_interrupt(dd, 2, 0x0026, 0x5202); write_gasket_interrupt(dd, intnum++, 0x0026, 0x5202);
if (static_ctle_mode) {
/* apply static CTLE tunings */
u8 pcie_dc, pcie_lf, pcie_hf, pcie_bw;
pcie_dc = ctle_tunings[pcie_pset][0];
pcie_lf = ctle_tunings[pcie_pset][1];
pcie_hf = ctle_tunings[pcie_pset][2];
pcie_bw = ctle_tunings[pcie_pset][3];
write_gasket_interrupt(dd, intnum++, 0x0026, 0x0200 | pcie_dc);
write_gasket_interrupt(dd, intnum++, 0x0026, 0x0100 | pcie_lf);
write_gasket_interrupt(dd, intnum++, 0x0026, 0x0000 | pcie_hf);
write_gasket_interrupt(dd, intnum++, 0x0026, 0x5500 | pcie_bw);
}
/* terminate list */ /* terminate list */
write_gasket_interrupt(dd, 3, 0x0000, 0x0000); write_gasket_interrupt(dd, intnum++, 0x0000, 0x0000);
/* /*
* step 5d: program XMT margin * step 5d: program XMT margin
......
...@@ -1952,13 +1952,17 @@ int init_pervl_scs(struct hfi1_devdata *dd) ...@@ -1952,13 +1952,17 @@ int init_pervl_scs(struct hfi1_devdata *dd)
dd->vld[15].sc = sc_alloc(dd, SC_VL15, dd->vld[15].sc = sc_alloc(dd, SC_VL15,
dd->rcd[0]->rcvhdrqentsize, dd->node); dd->rcd[0]->rcvhdrqentsize, dd->node);
if (!dd->vld[15].sc) if (!dd->vld[15].sc)
goto nomem; return -ENOMEM;
hfi1_init_ctxt(dd->vld[15].sc); hfi1_init_ctxt(dd->vld[15].sc);
dd->vld[15].mtu = enum_to_mtu(OPA_MTU_2048); dd->vld[15].mtu = enum_to_mtu(OPA_MTU_2048);
dd->kernel_send_context = kmalloc_node(dd->num_send_contexts * dd->kernel_send_context = kzalloc_node(dd->num_send_contexts *
sizeof(struct send_context *), sizeof(struct send_context *),
GFP_KERNEL, dd->node); GFP_KERNEL, dd->node);
if (!dd->kernel_send_context)
goto freesc15;
dd->kernel_send_context[0] = dd->vld[15].sc; dd->kernel_send_context[0] = dd->vld[15].sc;
for (i = 0; i < num_vls; i++) { for (i = 0; i < num_vls; i++) {
...@@ -2010,12 +2014,21 @@ int init_pervl_scs(struct hfi1_devdata *dd) ...@@ -2010,12 +2014,21 @@ int init_pervl_scs(struct hfi1_devdata *dd)
if (pio_map_init(dd, ppd->port - 1, num_vls, NULL)) if (pio_map_init(dd, ppd->port - 1, num_vls, NULL))
goto nomem; goto nomem;
return 0; return 0;
nomem: nomem:
sc_free(dd->vld[15].sc); for (i = 0; i < num_vls; i++) {
for (i = 0; i < num_vls; i++)
sc_free(dd->vld[i].sc); sc_free(dd->vld[i].sc);
dd->vld[i].sc = NULL;
}
for (i = num_vls; i < INIT_SC_PER_VL * num_vls; i++) for (i = num_vls; i < INIT_SC_PER_VL * num_vls; i++)
sc_free(dd->kernel_send_context[i + 1]); sc_free(dd->kernel_send_context[i + 1]);
kfree(dd->kernel_send_context);
dd->kernel_send_context = NULL;
freesc15:
sc_free(dd->vld[15].sc);
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -537,20 +537,6 @@ static void apply_tunings( ...@@ -537,20 +537,6 @@ static void apply_tunings(
u8 precur = 0, attn = 0, postcur = 0, external_device_config = 0; u8 precur = 0, attn = 0, postcur = 0, external_device_config = 0;
u8 *cache = ppd->qsfp_info.cache; u8 *cache = ppd->qsfp_info.cache;
/* Enable external device config if channel is limiting active */
read_8051_config(ppd->dd, LINK_OPTIMIZATION_SETTINGS,
GENERAL_CONFIG, &config_data);
config_data &= ~(0xff << ENABLE_EXT_DEV_CONFIG_SHIFT);
config_data |= ((u32)limiting_active << ENABLE_EXT_DEV_CONFIG_SHIFT);
ret = load_8051_config(ppd->dd, LINK_OPTIMIZATION_SETTINGS,
GENERAL_CONFIG, config_data);
if (ret != HCMD_SUCCESS)
dd_dev_err(
ppd->dd,
"%s: Failed to set enable external device config\n",
__func__);
config_data = 0; /* re-init */
/* Pass tuning method to 8051 */ /* Pass tuning method to 8051 */
read_8051_config(ppd->dd, LINK_TUNING_PARAMETERS, GENERAL_CONFIG, read_8051_config(ppd->dd, LINK_TUNING_PARAMETERS, GENERAL_CONFIG,
&config_data); &config_data);
...@@ -638,9 +624,13 @@ static int tune_active_qsfp(struct hfi1_pportdata *ppd, u32 *ptr_tx_preset, ...@@ -638,9 +624,13 @@ static int tune_active_qsfp(struct hfi1_pportdata *ppd, u32 *ptr_tx_preset,
if (ret) if (ret)
return ret; return ret;
/*
* We'll change the QSFP memory contents from here on out, thus we set a
* flag here to remind ourselves to reset the QSFP module. This prevents
* reuse of stale settings established in our previous pass through.
*/
if (ppd->qsfp_info.reset_needed) { if (ppd->qsfp_info.reset_needed) {
reset_qsfp(ppd); reset_qsfp(ppd);
ppd->qsfp_info.reset_needed = 0;
refresh_qsfp_cache(ppd, &ppd->qsfp_info); refresh_qsfp_cache(ppd, &ppd->qsfp_info);
} else { } else {
ppd->qsfp_info.reset_needed = 1; ppd->qsfp_info.reset_needed = 1;
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <rdma/rdma_vt.h> #include <rdma/rdma_vt.h>
#include <rdma/rdmavt_qp.h> #include <rdma/rdmavt_qp.h>
#include <rdma/ib_verbs.h>
#include "hfi.h" #include "hfi.h"
#include "qp.h" #include "qp.h"
...@@ -115,6 +116,66 @@ static const u16 credit_table[31] = { ...@@ -115,6 +116,66 @@ static const u16 credit_table[31] = {
32768 /* 1E */ 32768 /* 1E */
}; };
const struct rvt_operation_params hfi1_post_parms[RVT_OPERATION_MAX] = {
[IB_WR_RDMA_WRITE] = {
.length = sizeof(struct ib_rdma_wr),
.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
},
[IB_WR_RDMA_READ] = {
.length = sizeof(struct ib_rdma_wr),
.qpt_support = BIT(IB_QPT_RC),
.flags = RVT_OPERATION_ATOMIC,
},
[IB_WR_ATOMIC_CMP_AND_SWP] = {
.length = sizeof(struct ib_atomic_wr),
.qpt_support = BIT(IB_QPT_RC),
.flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
},
[IB_WR_ATOMIC_FETCH_AND_ADD] = {
.length = sizeof(struct ib_atomic_wr),
.qpt_support = BIT(IB_QPT_RC),
.flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
},
[IB_WR_RDMA_WRITE_WITH_IMM] = {
.length = sizeof(struct ib_rdma_wr),
.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
},
[IB_WR_SEND] = {
.length = sizeof(struct ib_send_wr),
.qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
},
[IB_WR_SEND_WITH_IMM] = {
.length = sizeof(struct ib_send_wr),
.qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
},
[IB_WR_REG_MR] = {
.length = sizeof(struct ib_reg_wr),
.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
.flags = RVT_OPERATION_LOCAL,
},
[IB_WR_LOCAL_INV] = {
.length = sizeof(struct ib_send_wr),
.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
.flags = RVT_OPERATION_LOCAL,
},
[IB_WR_SEND_WITH_INV] = {
.length = sizeof(struct ib_send_wr),
.qpt_support = BIT(IB_QPT_RC),
},
};
static void flush_tx_list(struct rvt_qp *qp) static void flush_tx_list(struct rvt_qp *qp)
{ {
struct hfi1_qp_priv *priv = qp->priv; struct hfi1_qp_priv *priv = qp->priv;
...@@ -745,8 +806,9 @@ void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp, ...@@ -745,8 +806,9 @@ void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp,
priv->owner = qp; priv->owner = qp;
priv->s_hdr = kzalloc_node(sizeof(*priv->s_hdr), gfp, rdi->dparms.node); priv->s_ahg = kzalloc_node(sizeof(*priv->s_ahg), gfp,
if (!priv->s_hdr) { rdi->dparms.node);
if (!priv->s_ahg) {
kfree(priv); kfree(priv);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
...@@ -759,7 +821,7 @@ void qp_priv_free(struct rvt_dev_info *rdi, struct rvt_qp *qp) ...@@ -759,7 +821,7 @@ void qp_priv_free(struct rvt_dev_info *rdi, struct rvt_qp *qp)
{ {
struct hfi1_qp_priv *priv = qp->priv; struct hfi1_qp_priv *priv = qp->priv;
kfree(priv->s_hdr); kfree(priv->s_ahg);
kfree(priv); kfree(priv);
} }
......
...@@ -54,6 +54,8 @@ ...@@ -54,6 +54,8 @@
extern unsigned int hfi1_qp_table_size; extern unsigned int hfi1_qp_table_size;
extern const struct rvt_operation_params hfi1_post_parms[];
/* /*
* free_ahg - clear ahg from QP * free_ahg - clear ahg from QP
*/ */
...@@ -61,7 +63,7 @@ static inline void clear_ahg(struct rvt_qp *qp) ...@@ -61,7 +63,7 @@ static inline void clear_ahg(struct rvt_qp *qp)
{ {
struct hfi1_qp_priv *priv = qp->priv; struct hfi1_qp_priv *priv = qp->priv;
priv->s_hdr->ahgcount = 0; priv->s_ahg->ahgcount = 0;
qp->s_flags &= ~(RVT_S_AHG_VALID | RVT_S_AHG_CLEAR); qp->s_flags &= ~(RVT_S_AHG_VALID | RVT_S_AHG_CLEAR);
if (priv->s_sde && qp->s_ahgidx >= 0) if (priv->s_sde && qp->s_ahgidx >= 0)
sdma_ahg_free(priv->s_sde, qp->s_ahgidx); sdma_ahg_free(priv->s_sde, qp->s_ahgidx);
......
...@@ -50,46 +50,285 @@ ...@@ -50,46 +50,285 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include "hfi.h" #include "hfi.h"
#include "twsi.h"
/* for the given bus number, return the CSR for reading an i2c line */
static inline u32 i2c_in_csr(u32 bus_num)
{
return bus_num ? ASIC_QSFP2_IN : ASIC_QSFP1_IN;
}
/* for the given bus number, return the CSR for writing an i2c line */
static inline u32 i2c_oe_csr(u32 bus_num)
{
return bus_num ? ASIC_QSFP2_OE : ASIC_QSFP1_OE;
}
static void hfi1_setsda(void *data, int state)
{
struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
struct hfi1_devdata *dd = bus->controlling_dd;
u64 reg;
u32 target_oe;
target_oe = i2c_oe_csr(bus->num);
reg = read_csr(dd, target_oe);
/*
* The OE bit value is inverted and connected to the pin. When
* OE is 0 the pin is left to be pulled up, when the OE is 1
* the pin is driven low. This matches the "open drain" or "open
* collector" convention.
*/
if (state)
reg &= ~QSFP_HFI0_I2CDAT;
else
reg |= QSFP_HFI0_I2CDAT;
write_csr(dd, target_oe, reg);
/* do a read to force the write into the chip */
(void)read_csr(dd, target_oe);
}
static void hfi1_setscl(void *data, int state)
{
struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
struct hfi1_devdata *dd = bus->controlling_dd;
u64 reg;
u32 target_oe;
target_oe = i2c_oe_csr(bus->num);
reg = read_csr(dd, target_oe);
/*
* The OE bit value is inverted and connected to the pin. When
* OE is 0 the pin is left to be pulled up, when the OE is 1
* the pin is driven low. This matches the "open drain" or "open
* collector" convention.
*/
if (state)
reg &= ~QSFP_HFI0_I2CCLK;
else
reg |= QSFP_HFI0_I2CCLK;
write_csr(dd, target_oe, reg);
/* do a read to force the write into the chip */
(void)read_csr(dd, target_oe);
}
static int hfi1_getsda(void *data)
{
struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
u64 reg;
u32 target_in;
hfi1_setsda(data, 1); /* clear OE so we do not pull line down */
udelay(2); /* 1us pull up + 250ns hold */
target_in = i2c_in_csr(bus->num);
reg = read_csr(bus->controlling_dd, target_in);
return !!(reg & QSFP_HFI0_I2CDAT);
}
static int hfi1_getscl(void *data)
{
struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
u64 reg;
u32 target_in;
hfi1_setscl(data, 1); /* clear OE so we do not pull line down */
udelay(2); /* 1us pull up + 250ns hold */
target_in = i2c_in_csr(bus->num);
reg = read_csr(bus->controlling_dd, target_in);
return !!(reg & QSFP_HFI0_I2CCLK);
}
/* /*
* QSFP support for hfi driver, using "Two Wire Serial Interface" driver * Allocate and initialize the given i2c bus number.
* in twsi.c * Returns NULL on failure.
*/ */
#define I2C_MAX_RETRY 4 static struct hfi1_i2c_bus *init_i2c_bus(struct hfi1_devdata *dd,
struct hfi1_asic_data *ad, int num)
{
struct hfi1_i2c_bus *bus;
int ret;
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (!bus)
return NULL;
bus->controlling_dd = dd;
bus->num = num; /* our bus number */
bus->algo.setsda = hfi1_setsda;
bus->algo.setscl = hfi1_setscl;
bus->algo.getsda = hfi1_getsda;
bus->algo.getscl = hfi1_getscl;
bus->algo.udelay = 5;
bus->algo.timeout = usecs_to_jiffies(50);
bus->algo.data = bus;
bus->adapter.owner = THIS_MODULE;
bus->adapter.algo_data = &bus->algo;
bus->adapter.dev.parent = &dd->pcidev->dev;
snprintf(bus->adapter.name, sizeof(bus->adapter.name),
"hfi1_i2c%d", num);
ret = i2c_bit_add_bus(&bus->adapter);
if (ret) {
dd_dev_info(dd, "%s: unable to add i2c bus %d, err %d\n",
__func__, num, ret);
kfree(bus);
return NULL;
}
return bus;
}
/* /*
* Raw i2c write. No set-up or lock checking. * Initialize i2c buses.
* Return 0 on success, -errno on error.
*/ */
static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int set_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad)
int offset, void *bp, int len)
{ {
struct hfi1_devdata *dd = ppd->dd; ad->i2c_bus0 = init_i2c_bus(dd, ad, 0);
int ret, cnt; ad->i2c_bus1 = init_i2c_bus(dd, ad, 1);
u8 *buff = bp; if (!ad->i2c_bus0 || !ad->i2c_bus1)
return -ENOMEM;
return 0;
};
cnt = 0; static void clean_i2c_bus(struct hfi1_i2c_bus *bus)
while (cnt < len) { {
int wlen = len - cnt; if (bus) {
i2c_del_adapter(&bus->adapter);
kfree(bus);
}
}
ret = hfi1_twsi_blk_wr(dd, target, i2c_addr, offset, void clean_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad)
buff + cnt, wlen); {
if (ret) { clean_i2c_bus(ad->i2c_bus0);
/* hfi1_twsi_blk_wr() 1 for error, else 0 */ ad->i2c_bus0 = NULL;
return -EIO; clean_i2c_bus(ad->i2c_bus1);
} ad->i2c_bus1 = NULL;
offset += wlen; }
cnt += wlen;
static int i2c_bus_write(struct hfi1_devdata *dd, struct hfi1_i2c_bus *i2c,
u8 slave_addr, int offset, int offset_size,
u8 *data, u16 len)
{
int ret;
int num_msgs;
u8 offset_bytes[2];
struct i2c_msg msgs[2];
switch (offset_size) {
case 0:
num_msgs = 1;
msgs[0].addr = slave_addr;
msgs[0].flags = 0;
msgs[0].len = len;
msgs[0].buf = data;
break;
case 2:
offset_bytes[1] = (offset >> 8) & 0xff;
/* fall through */
case 1:
num_msgs = 2;
offset_bytes[0] = offset & 0xff;
msgs[0].addr = slave_addr;
msgs[0].flags = 0;
msgs[0].len = offset_size;
msgs[0].buf = offset_bytes;
msgs[1].addr = slave_addr;
msgs[1].flags = I2C_M_NOSTART,
msgs[1].len = len;
msgs[1].buf = data;
break;
default:
return -EINVAL;
} }
/* Must wait min 20us between qsfp i2c transactions */ i2c->controlling_dd = dd;
udelay(20); ret = i2c_transfer(&i2c->adapter, msgs, num_msgs);
if (ret != num_msgs) {
dd_dev_err(dd, "%s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; write failed, ret %d\n",
__func__, i2c->num, slave_addr, offset, len, ret);
return ret < 0 ? ret : -EIO;
}
return 0;
}
static int i2c_bus_read(struct hfi1_devdata *dd, struct hfi1_i2c_bus *bus,
u8 slave_addr, int offset, int offset_size,
u8 *data, u16 len)
{
int ret;
int num_msgs;
u8 offset_bytes[2];
struct i2c_msg msgs[2];
switch (offset_size) {
case 0:
num_msgs = 1;
msgs[0].addr = slave_addr;
msgs[0].flags = I2C_M_RD;
msgs[0].len = len;
msgs[0].buf = data;
break;
case 2:
offset_bytes[1] = (offset >> 8) & 0xff;
/* fall through */
case 1:
num_msgs = 2;
offset_bytes[0] = offset & 0xff;
msgs[0].addr = slave_addr;
msgs[0].flags = 0;
msgs[0].len = offset_size;
msgs[0].buf = offset_bytes;
msgs[1].addr = slave_addr;
msgs[1].flags = I2C_M_RD,
msgs[1].len = len;
msgs[1].buf = data;
break;
default:
return -EINVAL;
}
return cnt; bus->controlling_dd = dd;
ret = i2c_transfer(&bus->adapter, msgs, num_msgs);
if (ret != num_msgs) {
dd_dev_err(dd, "%s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; read failed, ret %d\n",
__func__, bus->num, slave_addr, offset, len, ret);
return ret < 0 ? ret : -EIO;
}
return 0;
}
/*
* Raw i2c write. No set-up or lock checking.
*
* Return 0 on success, -errno on error.
*/
static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
int offset, void *bp, int len)
{
struct hfi1_devdata *dd = ppd->dd;
struct hfi1_i2c_bus *bus;
u8 slave_addr;
int offset_size;
bus = target ? dd->asic_data->i2c_bus1 : dd->asic_data->i2c_bus0;
slave_addr = (i2c_addr & 0xff) >> 1; /* convert to 7-bit addr */
offset_size = (i2c_addr >> 8) & 0x3;
return i2c_bus_write(dd, bus, slave_addr, offset, offset_size, bp, len);
} }
/* /*
* Caller must hold the i2c chain resource. * Caller must hold the i2c chain resource.
*
* Return number of bytes written, or -errno.
*/ */
int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
void *bp, int len) void *bp, int len)
...@@ -99,63 +338,36 @@ int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, ...@@ -99,63 +338,36 @@ int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
return -EACCES; return -EACCES;
/* make sure the TWSI bus is in a sane state */ ret = __i2c_write(ppd, target, i2c_addr, offset, bp, len);
ret = hfi1_twsi_reset(ppd->dd, target); if (ret)
if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port,
"I2C chain %d write interface reset failed\n",
target);
return ret; return ret;
}
return __i2c_write(ppd, target, i2c_addr, offset, bp, len); return len;
} }
/* /*
* Raw i2c read. No set-up or lock checking. * Raw i2c read. No set-up or lock checking.
*
* Return 0 on success, -errno on error.
*/ */
static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
int offset, void *bp, int len) int offset, void *bp, int len)
{ {
struct hfi1_devdata *dd = ppd->dd; struct hfi1_devdata *dd = ppd->dd;
int ret, cnt, pass = 0; struct hfi1_i2c_bus *bus;
int orig_offset = offset; u8 slave_addr;
int offset_size;
cnt = 0;
while (cnt < len) { bus = target ? dd->asic_data->i2c_bus1 : dd->asic_data->i2c_bus0;
int rlen = len - cnt; slave_addr = (i2c_addr & 0xff) >> 1; /* convert to 7-bit addr */
offset_size = (i2c_addr >> 8) & 0x3;
ret = hfi1_twsi_blk_rd(dd, target, i2c_addr, offset, return i2c_bus_read(dd, bus, slave_addr, offset, offset_size, bp, len);
bp + cnt, rlen);
/* Some QSFP's fail first try. Retry as experiment */
if (ret && cnt == 0 && ++pass < I2C_MAX_RETRY)
continue;
if (ret) {
/* hfi1_twsi_blk_rd() 1 for error, else 0 */
ret = -EIO;
goto exit;
}
offset += rlen;
cnt += rlen;
}
ret = cnt;
exit:
if (ret < 0) {
hfi1_dev_porterr(dd, ppd->port,
"I2C chain %d read failed, addr 0x%x, offset 0x%x, len %d\n",
target, i2c_addr, orig_offset, len);
}
/* Must wait min 20us between qsfp i2c transactions */
udelay(20);
return ret;
} }
/* /*
* Caller must hold the i2c chain resource. * Caller must hold the i2c chain resource.
*
* Return number of bytes read, or -errno.
*/ */
int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
void *bp, int len) void *bp, int len)
...@@ -165,16 +377,11 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, ...@@ -165,16 +377,11 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
return -EACCES; return -EACCES;
/* make sure the TWSI bus is in a sane state */ ret = __i2c_read(ppd, target, i2c_addr, offset, bp, len);
ret = hfi1_twsi_reset(ppd->dd, target); if (ret)
if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port,
"I2C chain %d read interface reset failed\n",
target);
return ret; return ret;
}
return __i2c_read(ppd, target, i2c_addr, offset, bp, len); return len;
} }
/* /*
...@@ -182,6 +389,8 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, ...@@ -182,6 +389,8 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
* by writing @addr = ((256 * n) + m) * by writing @addr = ((256 * n) + m)
* *
* Caller must hold the i2c chain resource. * Caller must hold the i2c chain resource.
*
* Return number of bytes written or -errno.
*/ */
int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int len) int len)
...@@ -189,21 +398,12 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -189,21 +398,12 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int count = 0; int count = 0;
int offset; int offset;
int nwrite; int nwrite;
int ret; int ret = 0;
u8 page; u8 page;
if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
return -EACCES; return -EACCES;
/* make sure the TWSI bus is in a sane state */
ret = hfi1_twsi_reset(ppd->dd, target);
if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port,
"QSFP chain %d write interface reset failed\n",
target);
return ret;
}
while (count < len) { while (count < len) {
/* /*
* Set the qsfp page based on a zero-based address * Set the qsfp page based on a zero-based address
...@@ -213,11 +413,12 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -213,11 +413,12 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1); QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
if (ret != 1) { /* QSFPs require a 5-10msec delay after write operations */
mdelay(5);
if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port, hfi1_dev_porterr(ppd->dd, ppd->port,
"QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n", "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
target, ret); target, ret);
ret = -EIO;
break; break;
} }
...@@ -229,11 +430,13 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -229,11 +430,13 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
offset, bp + count, nwrite); offset, bp + count, nwrite);
if (ret <= 0) /* stop on error or nothing written */ /* QSFPs require a 5-10msec delay after write operations */
mdelay(5);
if (ret) /* stop on error */
break; break;
count += ret; count += nwrite;
addr += ret; addr += nwrite;
} }
if (ret < 0) if (ret < 0)
...@@ -243,7 +446,7 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -243,7 +446,7 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
/* /*
* Perform a stand-alone single QSFP write. Acquire the resource, do the * Perform a stand-alone single QSFP write. Acquire the resource, do the
* read, then release the resource. * write, then release the resource.
*/ */
int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int len) int len)
...@@ -266,6 +469,8 @@ int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -266,6 +469,8 @@ int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
* by reading @addr = ((256 * n) + m) * by reading @addr = ((256 * n) + m)
* *
* Caller must hold the i2c chain resource. * Caller must hold the i2c chain resource.
*
* Return the number of bytes read or -errno.
*/ */
int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int len) int len)
...@@ -273,21 +478,12 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -273,21 +478,12 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int count = 0; int count = 0;
int offset; int offset;
int nread; int nread;
int ret; int ret = 0;
u8 page; u8 page;
if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
return -EACCES; return -EACCES;
/* make sure the TWSI bus is in a sane state */
ret = hfi1_twsi_reset(ppd->dd, target);
if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port,
"QSFP chain %d read interface reset failed\n",
target);
return ret;
}
while (count < len) { while (count < len) {
/* /*
* Set the qsfp page based on a zero-based address * Set the qsfp page based on a zero-based address
...@@ -296,11 +492,12 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -296,11 +492,12 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
page = (u8)(addr / QSFP_PAGESIZE); page = (u8)(addr / QSFP_PAGESIZE);
ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1); QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
if (ret != 1) { /* QSFPs require a 5-10msec delay after write operations */
mdelay(5);
if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port, hfi1_dev_porterr(ppd->dd, ppd->port,
"QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n", "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
target, ret); target, ret);
ret = -EIO;
break; break;
} }
...@@ -310,15 +507,13 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -310,15 +507,13 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
if (((addr % QSFP_RW_BOUNDARY) + nread) > QSFP_RW_BOUNDARY) if (((addr % QSFP_RW_BOUNDARY) + nread) > QSFP_RW_BOUNDARY)
nread = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY); nread = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
/* QSFPs require a 5-10msec delay after write operations */
mdelay(5);
ret = __i2c_read(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, ret = __i2c_read(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
offset, bp + count, nread); offset, bp + count, nread);
if (ret <= 0) /* stop on error or nothing read */ if (ret) /* stop on error */
break; break;
count += ret; count += nread;
addr += ret; addr += nread;
} }
if (ret < 0) if (ret < 0)
......
...@@ -238,3 +238,6 @@ int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -238,3 +238,6 @@ int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int len); int len);
int one_qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, int one_qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int len); int len);
struct hfi1_asic_data;
int set_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad);
void clean_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad);
...@@ -477,6 +477,37 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) ...@@ -477,6 +477,37 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
qp->s_flags |= RVT_S_WAIT_FENCE; qp->s_flags |= RVT_S_WAIT_FENCE;
goto bail; goto bail;
} }
/*
* Local operations are processed immediately
* after all prior requests have completed
*/
if (wqe->wr.opcode == IB_WR_REG_MR ||
wqe->wr.opcode == IB_WR_LOCAL_INV) {
int local_ops = 0;
int err = 0;
if (qp->s_last != qp->s_cur)
goto bail;
if (++qp->s_cur == qp->s_size)
qp->s_cur = 0;
if (++qp->s_tail == qp->s_size)
qp->s_tail = 0;
if (!(wqe->wr.send_flags &
RVT_SEND_COMPLETION_ONLY)) {
err = rvt_invalidate_rkey(
qp,
wqe->wr.ex.invalidate_rkey);
local_ops = 1;
}
hfi1_send_complete(qp, wqe,
err ? IB_WC_LOC_PROT_ERR
: IB_WC_SUCCESS);
if (local_ops)
atomic_dec(&qp->local_ops_pending);
qp->s_hdrwords = 0;
goto done_free_tx;
}
newreq = 1; newreq = 1;
qp->s_psn = wqe->psn; qp->s_psn = wqe->psn;
} }
...@@ -491,6 +522,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) ...@@ -491,6 +522,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
switch (wqe->wr.opcode) { switch (wqe->wr.opcode) {
case IB_WR_SEND: case IB_WR_SEND:
case IB_WR_SEND_WITH_IMM: case IB_WR_SEND_WITH_IMM:
case IB_WR_SEND_WITH_INV:
/* If no credit, return. */ /* If no credit, return. */
if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT) && if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT) &&
cmp_msn(wqe->ssn, qp->s_lsn + 1) > 0) { cmp_msn(wqe->ssn, qp->s_lsn + 1) > 0) {
...@@ -504,11 +536,17 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) ...@@ -504,11 +536,17 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
} }
if (wqe->wr.opcode == IB_WR_SEND) { if (wqe->wr.opcode == IB_WR_SEND) {
qp->s_state = OP(SEND_ONLY); qp->s_state = OP(SEND_ONLY);
} else { } else if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
qp->s_state = OP(SEND_ONLY_WITH_IMMEDIATE); qp->s_state = OP(SEND_ONLY_WITH_IMMEDIATE);
/* Immediate data comes after the BTH */ /* Immediate data comes after the BTH */
ohdr->u.imm_data = wqe->wr.ex.imm_data; ohdr->u.imm_data = wqe->wr.ex.imm_data;
hwords += 1; hwords += 1;
} else {
qp->s_state = OP(SEND_ONLY_WITH_INVALIDATE);
/* Invalidate rkey comes after the BTH */
ohdr->u.ieth = cpu_to_be32(
wqe->wr.ex.invalidate_rkey);
hwords += 1;
} }
if (wqe->wr.send_flags & IB_SEND_SOLICITED) if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= IB_BTH_SOLICITED; bth0 |= IB_BTH_SOLICITED;
...@@ -671,11 +709,16 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) ...@@ -671,11 +709,16 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
} }
if (wqe->wr.opcode == IB_WR_SEND) { if (wqe->wr.opcode == IB_WR_SEND) {
qp->s_state = OP(SEND_LAST); qp->s_state = OP(SEND_LAST);
} else { } else if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);
/* Immediate data comes after the BTH */ /* Immediate data comes after the BTH */
ohdr->u.imm_data = wqe->wr.ex.imm_data; ohdr->u.imm_data = wqe->wr.ex.imm_data;
hwords += 1; hwords += 1;
} else {
qp->s_state = OP(SEND_LAST_WITH_INVALIDATE);
/* invalidate data comes after the BTH */
ohdr->u.ieth = cpu_to_be32(wqe->wr.ex.invalidate_rkey);
hwords += 1;
} }
if (wqe->wr.send_flags & IB_SEND_SOLICITED) if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= IB_BTH_SOLICITED; bth0 |= IB_BTH_SOLICITED;
...@@ -1047,7 +1090,7 @@ void hfi1_rc_timeout(unsigned long arg) ...@@ -1047,7 +1090,7 @@ void hfi1_rc_timeout(unsigned long arg)
ibp->rvp.n_rc_timeouts++; ibp->rvp.n_rc_timeouts++;
qp->s_flags &= ~RVT_S_TIMER; qp->s_flags &= ~RVT_S_TIMER;
del_timer(&qp->s_timer); del_timer(&qp->s_timer);
trace_hfi1_rc_timeout(qp, qp->s_last_psn + 1); trace_hfi1_timeout(qp, qp->s_last_psn + 1);
restart_rc(qp, qp->s_last_psn + 1, 1); restart_rc(qp, qp->s_last_psn + 1, 1);
hfi1_schedule_send(qp); hfi1_schedule_send(qp);
} }
...@@ -1171,7 +1214,7 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_ib_header *hdr) ...@@ -1171,7 +1214,7 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_ib_header *hdr)
* If we were waiting for sends to complete before re-sending, * If we were waiting for sends to complete before re-sending,
* and they are now complete, restart sending. * and they are now complete, restart sending.
*/ */
trace_hfi1_rc_sendcomplete(qp, psn); trace_hfi1_sendcomplete(qp, psn);
if (qp->s_flags & RVT_S_WAIT_PSN && if (qp->s_flags & RVT_S_WAIT_PSN &&
cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) > 0) { cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) > 0) {
qp->s_flags &= ~RVT_S_WAIT_PSN; qp->s_flags &= ~RVT_S_WAIT_PSN;
...@@ -1567,7 +1610,7 @@ static void rc_rcv_resp(struct hfi1_ibport *ibp, ...@@ -1567,7 +1610,7 @@ static void rc_rcv_resp(struct hfi1_ibport *ibp,
spin_lock_irqsave(&qp->s_lock, flags); spin_lock_irqsave(&qp->s_lock, flags);
trace_hfi1_rc_ack(qp, psn); trace_hfi1_ack(qp, psn);
/* Ignore invalid responses. */ /* Ignore invalid responses. */
smp_read_barrier_depends(); /* see post_one_send */ smp_read_barrier_depends(); /* see post_one_send */
...@@ -1782,7 +1825,7 @@ static noinline int rc_rcv_error(struct hfi1_other_headers *ohdr, void *data, ...@@ -1782,7 +1825,7 @@ static noinline int rc_rcv_error(struct hfi1_other_headers *ohdr, void *data,
u8 i, prev; u8 i, prev;
int old_req; int old_req;
trace_hfi1_rc_rcv_error(qp, psn); trace_hfi1_rcv_error(qp, psn);
if (diff > 0) { if (diff > 0) {
/* /*
* Packet sequence error. * Packet sequence error.
...@@ -2086,7 +2129,6 @@ void hfi1_rc_rcv(struct hfi1_packet *packet) ...@@ -2086,7 +2129,6 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
u32 tlen = packet->tlen; u32 tlen = packet->tlen;
struct rvt_qp *qp = packet->qp; struct rvt_qp *qp = packet->qp;
struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
struct hfi1_other_headers *ohdr = packet->ohdr; struct hfi1_other_headers *ohdr = packet->ohdr;
u32 bth0, opcode; u32 bth0, opcode;
u32 hdrsize = packet->hlen; u32 hdrsize = packet->hlen;
...@@ -2097,30 +2139,15 @@ void hfi1_rc_rcv(struct hfi1_packet *packet) ...@@ -2097,30 +2139,15 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
int diff; int diff;
struct ib_reth *reth; struct ib_reth *reth;
unsigned long flags; unsigned long flags;
u32 bth1;
int ret, is_fecn = 0; int ret, is_fecn = 0;
int copy_last = 0; int copy_last = 0;
u32 rkey;
bth0 = be32_to_cpu(ohdr->bth[0]); bth0 = be32_to_cpu(ohdr->bth[0]);
if (hfi1_ruc_check_hdr(ibp, hdr, rcv_flags & HFI1_HAS_GRH, qp, bth0)) if (hfi1_ruc_check_hdr(ibp, hdr, rcv_flags & HFI1_HAS_GRH, qp, bth0))
return; return;
bth1 = be32_to_cpu(ohdr->bth[1]); is_fecn = process_ecn(qp, packet, false);
if (unlikely(bth1 & (HFI1_BECN_SMASK | HFI1_FECN_SMASK))) {
if (bth1 & HFI1_BECN_SMASK) {
u16 rlid = qp->remote_ah_attr.dlid;
u32 lqpn, rqpn;
lqpn = qp->ibqp.qp_num;
rqpn = qp->remote_qpn;
process_becn(
ppd,
qp->remote_ah_attr.sl,
rlid, lqpn, rqpn,
IB_CC_SVCTYPE_RC);
}
is_fecn = bth1 & HFI1_FECN_SMASK;
}
psn = be32_to_cpu(ohdr->bth[2]); psn = be32_to_cpu(ohdr->bth[2]);
opcode = (bth0 >> 24) & 0xff; opcode = (bth0 >> 24) & 0xff;
...@@ -2154,7 +2181,8 @@ void hfi1_rc_rcv(struct hfi1_packet *packet) ...@@ -2154,7 +2181,8 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
case OP(SEND_MIDDLE): case OP(SEND_MIDDLE):
if (opcode == OP(SEND_MIDDLE) || if (opcode == OP(SEND_MIDDLE) ||
opcode == OP(SEND_LAST) || opcode == OP(SEND_LAST) ||
opcode == OP(SEND_LAST_WITH_IMMEDIATE)) opcode == OP(SEND_LAST_WITH_IMMEDIATE) ||
opcode == OP(SEND_LAST_WITH_INVALIDATE))
break; break;
goto nack_inv; goto nack_inv;
...@@ -2170,6 +2198,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet) ...@@ -2170,6 +2198,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
if (opcode == OP(SEND_MIDDLE) || if (opcode == OP(SEND_MIDDLE) ||
opcode == OP(SEND_LAST) || opcode == OP(SEND_LAST) ||
opcode == OP(SEND_LAST_WITH_IMMEDIATE) || opcode == OP(SEND_LAST_WITH_IMMEDIATE) ||
opcode == OP(SEND_LAST_WITH_INVALIDATE) ||
opcode == OP(RDMA_WRITE_MIDDLE) || opcode == OP(RDMA_WRITE_MIDDLE) ||
opcode == OP(RDMA_WRITE_LAST) || opcode == OP(RDMA_WRITE_LAST) ||
opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
...@@ -2218,6 +2247,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet) ...@@ -2218,6 +2247,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
case OP(SEND_ONLY): case OP(SEND_ONLY):
case OP(SEND_ONLY_WITH_IMMEDIATE): case OP(SEND_ONLY_WITH_IMMEDIATE):
case OP(SEND_ONLY_WITH_INVALIDATE):
ret = hfi1_rvt_get_rwqe(qp, 0); ret = hfi1_rvt_get_rwqe(qp, 0);
if (ret < 0) if (ret < 0)
goto nack_op_err; goto nack_op_err;
...@@ -2226,12 +2256,22 @@ void hfi1_rc_rcv(struct hfi1_packet *packet) ...@@ -2226,12 +2256,22 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
qp->r_rcv_len = 0; qp->r_rcv_len = 0;
if (opcode == OP(SEND_ONLY)) if (opcode == OP(SEND_ONLY))
goto no_immediate_data; goto no_immediate_data;
if (opcode == OP(SEND_ONLY_WITH_INVALIDATE))
goto send_last_inv;
/* FALLTHROUGH for SEND_ONLY_WITH_IMMEDIATE */ /* FALLTHROUGH for SEND_ONLY_WITH_IMMEDIATE */
case OP(SEND_LAST_WITH_IMMEDIATE): case OP(SEND_LAST_WITH_IMMEDIATE):
send_last_imm: send_last_imm:
wc.ex.imm_data = ohdr->u.imm_data; wc.ex.imm_data = ohdr->u.imm_data;
wc.wc_flags = IB_WC_WITH_IMM; wc.wc_flags = IB_WC_WITH_IMM;
goto send_last; goto send_last;
case OP(SEND_LAST_WITH_INVALIDATE):
send_last_inv:
rkey = be32_to_cpu(ohdr->u.ieth);
if (rvt_invalidate_rkey(qp, rkey))
goto no_immediate_data;
wc.ex.invalidate_rkey = rkey;
wc.wc_flags = IB_WC_WITH_INVALIDATE;
goto send_last;
case OP(RDMA_WRITE_LAST): case OP(RDMA_WRITE_LAST):
copy_last = ibpd_to_rvtpd(qp->ibqp.pd)->user; copy_last = ibpd_to_rvtpd(qp->ibqp.pd)->user;
/* fall through */ /* fall through */
......
...@@ -372,6 +372,7 @@ static void ruc_loopback(struct rvt_qp *sqp) ...@@ -372,6 +372,7 @@ static void ruc_loopback(struct rvt_qp *sqp)
int ret; int ret;
int copy_last = 0; int copy_last = 0;
u32 to; u32 to;
int local_ops = 0;
rcu_read_lock(); rcu_read_lock();
...@@ -440,11 +441,31 @@ static void ruc_loopback(struct rvt_qp *sqp) ...@@ -440,11 +441,31 @@ static void ruc_loopback(struct rvt_qp *sqp)
sqp->s_sge.num_sge = wqe->wr.num_sge; sqp->s_sge.num_sge = wqe->wr.num_sge;
sqp->s_len = wqe->length; sqp->s_len = wqe->length;
switch (wqe->wr.opcode) { switch (wqe->wr.opcode) {
case IB_WR_REG_MR:
goto send_comp;
case IB_WR_LOCAL_INV:
if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) {
if (rvt_invalidate_rkey(sqp,
wqe->wr.ex.invalidate_rkey))
send_status = IB_WC_LOC_PROT_ERR;
local_ops = 1;
}
goto send_comp;
case IB_WR_SEND_WITH_INV:
if (!rvt_invalidate_rkey(qp, wqe->wr.ex.invalidate_rkey)) {
wc.wc_flags = IB_WC_WITH_INVALIDATE;
wc.ex.invalidate_rkey = wqe->wr.ex.invalidate_rkey;
}
goto send;
case IB_WR_SEND_WITH_IMM: case IB_WR_SEND_WITH_IMM:
wc.wc_flags = IB_WC_WITH_IMM; wc.wc_flags = IB_WC_WITH_IMM;
wc.ex.imm_data = wqe->wr.ex.imm_data; wc.ex.imm_data = wqe->wr.ex.imm_data;
/* FALLTHROUGH */ /* FALLTHROUGH */
case IB_WR_SEND: case IB_WR_SEND:
send:
ret = hfi1_rvt_get_rwqe(qp, 0); ret = hfi1_rvt_get_rwqe(qp, 0);
if (ret < 0) if (ret < 0)
goto op_err; goto op_err;
...@@ -583,6 +604,10 @@ static void ruc_loopback(struct rvt_qp *sqp) ...@@ -583,6 +604,10 @@ static void ruc_loopback(struct rvt_qp *sqp)
flush_send: flush_send:
sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
hfi1_send_complete(sqp, wqe, send_status); hfi1_send_complete(sqp, wqe, send_status);
if (local_ops) {
atomic_dec(&sqp->local_ops_pending);
local_ops = 0;
}
goto again; goto again;
rnr_nak: rnr_nak:
...@@ -683,10 +708,10 @@ u32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr, ...@@ -683,10 +708,10 @@ u32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr,
return sizeof(struct ib_grh) / sizeof(u32); return sizeof(struct ib_grh) / sizeof(u32);
} }
#define BTH2_OFFSET (offsetof(struct hfi1_pio_header, hdr.u.oth.bth[2]) / 4) #define BTH2_OFFSET (offsetof(struct hfi1_sdma_header, hdr.u.oth.bth[2]) / 4)
/** /**
* build_ahg - create ahg in s_hdr * build_ahg - create ahg in s_ahg
* @qp: a pointer to QP * @qp: a pointer to QP
* @npsn: the next PSN for the request/response * @npsn: the next PSN for the request/response
* *
...@@ -708,19 +733,18 @@ static inline void build_ahg(struct rvt_qp *qp, u32 npsn) ...@@ -708,19 +733,18 @@ static inline void build_ahg(struct rvt_qp *qp, u32 npsn)
qp->s_ahgidx = sdma_ahg_alloc(priv->s_sde); qp->s_ahgidx = sdma_ahg_alloc(priv->s_sde);
if (qp->s_ahgidx >= 0) { if (qp->s_ahgidx >= 0) {
qp->s_ahgpsn = npsn; qp->s_ahgpsn = npsn;
priv->s_hdr->tx_flags |= SDMA_TXREQ_F_AHG_COPY; priv->s_ahg->tx_flags |= SDMA_TXREQ_F_AHG_COPY;
/* save to protect a change in another thread */ /* save to protect a change in another thread */
priv->s_hdr->sde = priv->s_sde; priv->s_ahg->ahgidx = qp->s_ahgidx;
priv->s_hdr->ahgidx = qp->s_ahgidx;
qp->s_flags |= RVT_S_AHG_VALID; qp->s_flags |= RVT_S_AHG_VALID;
} }
} else { } else {
/* subsequent middle after valid */ /* subsequent middle after valid */
if (qp->s_ahgidx >= 0) { if (qp->s_ahgidx >= 0) {
priv->s_hdr->tx_flags |= SDMA_TXREQ_F_USE_AHG; priv->s_ahg->tx_flags |= SDMA_TXREQ_F_USE_AHG;
priv->s_hdr->ahgidx = qp->s_ahgidx; priv->s_ahg->ahgidx = qp->s_ahgidx;
priv->s_hdr->ahgcount++; priv->s_ahg->ahgcount++;
priv->s_hdr->ahgdesc[0] = priv->s_ahg->ahgdesc[0] =
sdma_build_ahg_descriptor( sdma_build_ahg_descriptor(
(__force u16)cpu_to_be16((u16)npsn), (__force u16)cpu_to_be16((u16)npsn),
BTH2_OFFSET, BTH2_OFFSET,
...@@ -728,8 +752,8 @@ static inline void build_ahg(struct rvt_qp *qp, u32 npsn) ...@@ -728,8 +752,8 @@ static inline void build_ahg(struct rvt_qp *qp, u32 npsn)
16); 16);
if ((npsn & 0xffff0000) != if ((npsn & 0xffff0000) !=
(qp->s_ahgpsn & 0xffff0000)) { (qp->s_ahgpsn & 0xffff0000)) {
priv->s_hdr->ahgcount++; priv->s_ahg->ahgcount++;
priv->s_hdr->ahgdesc[1] = priv->s_ahg->ahgdesc[1] =
sdma_build_ahg_descriptor( sdma_build_ahg_descriptor(
(__force u16)cpu_to_be16( (__force u16)cpu_to_be16(
(u16)(npsn >> 16)), (u16)(npsn >> 16)),
...@@ -766,7 +790,7 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct hfi1_other_headers *ohdr, ...@@ -766,7 +790,7 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct hfi1_other_headers *ohdr,
} }
lrh0 |= (priv->s_sc & 0xf) << 12 | (qp->remote_ah_attr.sl & 0xf) << 4; lrh0 |= (priv->s_sc & 0xf) << 12 | (qp->remote_ah_attr.sl & 0xf) << 4;
/* /*
* reset s_hdr/AHG fields * reset s_ahg/AHG fields
* *
* This insures that the ahgentry/ahgcount * This insures that the ahgentry/ahgcount
* are at a non-AHG default to protect * are at a non-AHG default to protect
...@@ -776,10 +800,9 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct hfi1_other_headers *ohdr, ...@@ -776,10 +800,9 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct hfi1_other_headers *ohdr,
* build_ahg() will modify as appropriate * build_ahg() will modify as appropriate
* to use the AHG feature. * to use the AHG feature.
*/ */
priv->s_hdr->tx_flags = 0; priv->s_ahg->tx_flags = 0;
priv->s_hdr->ahgcount = 0; priv->s_ahg->ahgcount = 0;
priv->s_hdr->ahgidx = 0; priv->s_ahg->ahgidx = 0;
priv->s_hdr->sde = NULL;
if (qp->s_mig_state == IB_MIG_MIGRATED) if (qp->s_mig_state == IB_MIG_MIGRATED)
bth0 |= IB_BTH_MIG_REQ; bth0 |= IB_BTH_MIG_REQ;
else else
...@@ -890,7 +913,7 @@ void hfi1_do_send(struct rvt_qp *qp) ...@@ -890,7 +913,7 @@ void hfi1_do_send(struct rvt_qp *qp)
*/ */
if (hfi1_verbs_send(qp, &ps)) if (hfi1_verbs_send(qp, &ps))
return; return;
/* Record that s_hdr is empty. */ /* Record that s_ahg is empty. */
qp->s_hdrwords = 0; qp->s_hdrwords = 0;
/* allow other tasks to run */ /* allow other tasks to run */
if (unlikely(time_after(jiffies, timeout))) { if (unlikely(time_after(jiffies, timeout))) {
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "hfi.h" #include "hfi.h"
#include "mad.h" #include "mad.h"
#include "trace.h" #include "trace.h"
#include "affinity.h"
/* /*
* Start of per-port congestion control structures and support code * Start of per-port congestion control structures and support code
...@@ -622,6 +623,27 @@ static ssize_t show_tempsense(struct device *device, ...@@ -622,6 +623,27 @@ static ssize_t show_tempsense(struct device *device,
return ret; return ret;
} }
static ssize_t show_sdma_affinity(struct device *device,
struct device_attribute *attr, char *buf)
{
struct hfi1_ibdev *dev =
container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
struct hfi1_devdata *dd = dd_from_dev(dev);
return hfi1_get_sdma_affinity(dd, buf);
}
static ssize_t store_sdma_affinity(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct hfi1_ibdev *dev =
container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
struct hfi1_devdata *dd = dd_from_dev(dev);
return hfi1_set_sdma_affinity(dd, buf, count);
}
/* /*
* end of per-unit (or driver, in some cases, but replicated * end of per-unit (or driver, in some cases, but replicated
* per unit) functions * per unit) functions
...@@ -636,6 +658,8 @@ static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); ...@@ -636,6 +658,8 @@ static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL); static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset); static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
static DEVICE_ATTR(sdma_affinity, S_IWUSR | S_IRUGO, show_sdma_affinity,
store_sdma_affinity);
static struct device_attribute *hfi1_attributes[] = { static struct device_attribute *hfi1_attributes[] = {
&dev_attr_hw_rev, &dev_attr_hw_rev,
...@@ -646,6 +670,7 @@ static struct device_attribute *hfi1_attributes[] = { ...@@ -646,6 +670,7 @@ static struct device_attribute *hfi1_attributes[] = {
&dev_attr_boardversion, &dev_attr_boardversion,
&dev_attr_tempsense, &dev_attr_tempsense,
&dev_attr_chip_reset, &dev_attr_chip_reset,
&dev_attr_sdma_affinity,
}; };
int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
......
此差异已折叠。
/*
* Copyright(c) 2015, 2016 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#if !defined(__HFI1_TRACE_CTXTS_H) || defined(TRACE_HEADER_MULTI_READ)
#define __HFI1_TRACE_CTXTS_H
#include <linux/tracepoint.h>
#include <linux/trace_seq.h>
#include "hfi.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hfi1_ctxts
#define UCTXT_FMT \
"cred:%u, credaddr:0x%llx, piobase:0x%p, rcvhdr_cnt:%u, " \
"rcvbase:0x%llx, rcvegrc:%u, rcvegrb:0x%llx"
TRACE_EVENT(hfi1_uctxtdata,
TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ctxtdata *uctxt),
TP_ARGS(dd, uctxt),
TP_STRUCT__entry(DD_DEV_ENTRY(dd)
__field(unsigned int, ctxt)
__field(u32, credits)
__field(u64, hw_free)
__field(void __iomem *, piobase)
__field(u16, rcvhdrq_cnt)
__field(u64, rcvhdrq_phys)
__field(u32, eager_cnt)
__field(u64, rcvegr_phys)
),
TP_fast_assign(DD_DEV_ASSIGN(dd);
__entry->ctxt = uctxt->ctxt;
__entry->credits = uctxt->sc->credits;
__entry->hw_free = le64_to_cpu(*uctxt->sc->hw_free);
__entry->piobase = uctxt->sc->base_addr;
__entry->rcvhdrq_cnt = uctxt->rcvhdrq_cnt;
__entry->rcvhdrq_phys = uctxt->rcvhdrq_phys;
__entry->eager_cnt = uctxt->egrbufs.alloced;
__entry->rcvegr_phys =
uctxt->egrbufs.rcvtids[0].phys;
),
TP_printk("[%s] ctxt %u " UCTXT_FMT,
__get_str(dev),
__entry->ctxt,
__entry->credits,
__entry->hw_free,
__entry->piobase,
__entry->rcvhdrq_cnt,
__entry->rcvhdrq_phys,
__entry->eager_cnt,
__entry->rcvegr_phys
)
);
#define CINFO_FMT \
"egrtids:%u, egr_size:%u, hdrq_cnt:%u, hdrq_size:%u, sdma_ring_size:%u"
TRACE_EVENT(hfi1_ctxt_info,
TP_PROTO(struct hfi1_devdata *dd, unsigned int ctxt,
unsigned int subctxt,
struct hfi1_ctxt_info cinfo),
TP_ARGS(dd, ctxt, subctxt, cinfo),
TP_STRUCT__entry(DD_DEV_ENTRY(dd)
__field(unsigned int, ctxt)
__field(unsigned int, subctxt)
__field(u16, egrtids)
__field(u16, rcvhdrq_cnt)
__field(u16, rcvhdrq_size)
__field(u16, sdma_ring_size)
__field(u32, rcvegr_size)
),
TP_fast_assign(DD_DEV_ASSIGN(dd);
__entry->ctxt = ctxt;
__entry->subctxt = subctxt;
__entry->egrtids = cinfo.egrtids;
__entry->rcvhdrq_cnt = cinfo.rcvhdrq_cnt;
__entry->rcvhdrq_size = cinfo.rcvhdrq_entsize;
__entry->sdma_ring_size = cinfo.sdma_ring_size;
__entry->rcvegr_size = cinfo.rcvegr_size;
),
TP_printk("[%s] ctxt %u:%u " CINFO_FMT,
__get_str(dev),
__entry->ctxt,
__entry->subctxt,
__entry->egrtids,
__entry->rcvegr_size,
__entry->rcvhdrq_cnt,
__entry->rcvhdrq_size,
__entry->sdma_ring_size
)
);
#endif /* __HFI1_TRACE_CTXTS_H */
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_ctxts
#include <trace/define_trace.h>
/*
* Copyright(c) 2015, 2016 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#if !defined(__HFI1_TRACE_EXTRA_H) || defined(TRACE_HEADER_MULTI_READ)
#define __HFI1_TRACE_EXTRA_H
#include <linux/tracepoint.h>
#include <linux/trace_seq.h>
#include "hfi.h"
/*
* Note:
* This produces a REALLY ugly trace in the console output when the string is
* too long.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hfi1_dbg
#define MAX_MSG_LEN 512
DECLARE_EVENT_CLASS(hfi1_trace_template,
TP_PROTO(const char *function, struct va_format *vaf),
TP_ARGS(function, vaf),
TP_STRUCT__entry(__string(function, function)
__dynamic_array(char, msg, MAX_MSG_LEN)
),
TP_fast_assign(__assign_str(function, function);
WARN_ON_ONCE(vsnprintf
(__get_dynamic_array(msg),
MAX_MSG_LEN, vaf->fmt,
*vaf->va) >=
MAX_MSG_LEN);
),
TP_printk("(%s) %s",
__get_str(function),
__get_str(msg))
);
/*
* It may be nice to macroize the __hfi1_trace but the va_* stuff requires an
* actual function to work and can not be in a macro.
*/
#define __hfi1_trace_def(lvl) \
void __hfi1_trace_##lvl(const char *funct, char *fmt, ...); \
\
DEFINE_EVENT(hfi1_trace_template, hfi1_ ##lvl, \
TP_PROTO(const char *function, struct va_format *vaf), \
TP_ARGS(function, vaf))
#define __hfi1_trace_fn(lvl) \
void __hfi1_trace_##lvl(const char *func, char *fmt, ...) \
{ \
struct va_format vaf = { \
.fmt = fmt, \
}; \
va_list args; \
\
va_start(args, fmt); \
vaf.va = &args; \
trace_hfi1_ ##lvl(func, &vaf); \
va_end(args); \
return; \
}
/*
* To create a new trace level simply define it below and as a __hfi1_trace_fn
* in trace.c. This will create all the hooks for calling
* hfi1_cdbg(LVL, fmt, ...); as well as take care of all
* the debugfs stuff.
*/
__hfi1_trace_def(PKT);
__hfi1_trace_def(PROC);
__hfi1_trace_def(SDMA);
__hfi1_trace_def(LINKVERB);
__hfi1_trace_def(DEBUG);
__hfi1_trace_def(SNOOP);
__hfi1_trace_def(CNTR);
__hfi1_trace_def(PIO);
__hfi1_trace_def(DC8051);
__hfi1_trace_def(FIRMWARE);
__hfi1_trace_def(RCVCTRL);
__hfi1_trace_def(TID);
__hfi1_trace_def(MMU);
__hfi1_trace_def(IOCTL);
#define hfi1_cdbg(which, fmt, ...) \
__hfi1_trace_##which(__func__, fmt, ##__VA_ARGS__)
#define hfi1_dbg(fmt, ...) \
hfi1_cdbg(DEBUG, fmt, ##__VA_ARGS__)
/*
* Define HFI1_EARLY_DBG at compile time or here to enable early trace
* messages. Do not check in an enablement for this.
*/
#ifdef HFI1_EARLY_DBG
#define hfi1_dbg_early(fmt, ...) \
trace_printk(fmt, ##__VA_ARGS__)
#else
#define hfi1_dbg_early(fmt, ...)
#endif
#endif /* __HFI1_TRACE_EXTRA_H */
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_dbg
#include <trace/define_trace.h>
#ifndef _TWSI_H
#define _TWSI_H
/* /*
* Copyright(c) 2015, 2016 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
...@@ -46,20 +44,166 @@ ...@@ -46,20 +44,166 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
#if !defined(__HFI1_TRACE_IBHDRS_H) || defined(TRACE_HEADER_MULTI_READ)
#define __HFI1_TRACE_IBHDRS_H
#define HFI1_TWSI_NO_DEV 0xFF #include <linux/tracepoint.h>
#include <linux/trace_seq.h>
struct hfi1_devdata; #include "hfi.h"
/* Bit position of SDA/SCL pins in ASIC_QSFP* registers */ #undef TRACE_SYSTEM
#define GPIO_SDA_NUM 1 #define TRACE_SYSTEM hfi1_ibhdrs
#define GPIO_SCL_NUM 0
/* these functions must be called with qsfp_lock held */ u8 ibhdr_exhdr_len(struct hfi1_ib_header *hdr);
int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target); const char *parse_everbs_hdrs(struct trace_seq *p, u8 opcode, void *ehdrs);
int hfi1_twsi_blk_rd(struct hfi1_devdata *dd, u32 target, int dev, int addr,
void *buffer, int len);
int hfi1_twsi_blk_wr(struct hfi1_devdata *dd, u32 target, int dev, int addr,
const void *buffer, int len);
#endif /* _TWSI_H */ #define __parse_ib_ehdrs(op, ehdrs) parse_everbs_hdrs(p, op, ehdrs)
#define lrh_name(lrh) { HFI1_##lrh, #lrh }
#define show_lnh(lrh) \
__print_symbolic(lrh, \
lrh_name(LRH_BTH), \
lrh_name(LRH_GRH))
#define LRH_PRN "vl %d lver %d sl %d lnh %d,%s dlid %.4x len %d slid %.4x"
#define BTH_PRN \
"op 0x%.2x,%s se %d m %d pad %d tver %d pkey 0x%.4x " \
"f %d b %d qpn 0x%.6x a %d psn 0x%.8x"
#define EHDR_PRN "%s"
DECLARE_EVENT_CLASS(hfi1_ibhdr_template,
TP_PROTO(struct hfi1_devdata *dd,
struct hfi1_ib_header *hdr),
TP_ARGS(dd, hdr),
TP_STRUCT__entry(
DD_DEV_ENTRY(dd)
/* LRH */
__field(u8, vl)
__field(u8, lver)
__field(u8, sl)
__field(u8, lnh)
__field(u16, dlid)
__field(u16, len)
__field(u16, slid)
/* BTH */
__field(u8, opcode)
__field(u8, se)
__field(u8, m)
__field(u8, pad)
__field(u8, tver)
__field(u16, pkey)
__field(u8, f)
__field(u8, b)
__field(u32, qpn)
__field(u8, a)
__field(u32, psn)
/* extended headers */
__dynamic_array(u8, ehdrs, ibhdr_exhdr_len(hdr))
),
TP_fast_assign(
struct hfi1_other_headers *ohdr;
DD_DEV_ASSIGN(dd);
/* LRH */
__entry->vl =
(u8)(be16_to_cpu(hdr->lrh[0]) >> 12);
__entry->lver =
(u8)(be16_to_cpu(hdr->lrh[0]) >> 8) & 0xf;
__entry->sl =
(u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
__entry->lnh =
(u8)(be16_to_cpu(hdr->lrh[0]) & 3);
__entry->dlid =
be16_to_cpu(hdr->lrh[1]);
/* allow for larger len */
__entry->len =
be16_to_cpu(hdr->lrh[2]);
__entry->slid =
be16_to_cpu(hdr->lrh[3]);
/* BTH */
if (__entry->lnh == HFI1_LRH_BTH)
ohdr = &hdr->u.oth;
else
ohdr = &hdr->u.l.oth;
__entry->opcode =
(be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff;
__entry->se =
(be32_to_cpu(ohdr->bth[0]) >> 23) & 1;
__entry->m =
(be32_to_cpu(ohdr->bth[0]) >> 22) & 1;
__entry->pad =
(be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
__entry->tver =
(be32_to_cpu(ohdr->bth[0]) >> 16) & 0xf;
__entry->pkey =
be32_to_cpu(ohdr->bth[0]) & 0xffff;
__entry->f =
(be32_to_cpu(ohdr->bth[1]) >> HFI1_FECN_SHIFT) &
HFI1_FECN_MASK;
__entry->b =
(be32_to_cpu(ohdr->bth[1]) >> HFI1_BECN_SHIFT) &
HFI1_BECN_MASK;
__entry->qpn =
be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
__entry->a =
(be32_to_cpu(ohdr->bth[2]) >> 31) & 1;
/* allow for larger PSN */
__entry->psn =
be32_to_cpu(ohdr->bth[2]) & 0x7fffffff;
/* extended headers */
memcpy(__get_dynamic_array(ehdrs), &ohdr->u,
ibhdr_exhdr_len(hdr));
),
TP_printk("[%s] " LRH_PRN " " BTH_PRN " " EHDR_PRN,
__get_str(dev),
/* LRH */
__entry->vl,
__entry->lver,
__entry->sl,
__entry->lnh, show_lnh(__entry->lnh),
__entry->dlid,
__entry->len,
__entry->slid,
/* BTH */
__entry->opcode, show_ib_opcode(__entry->opcode),
__entry->se,
__entry->m,
__entry->pad,
__entry->tver,
__entry->pkey,
__entry->f,
__entry->b,
__entry->qpn,
__entry->a,
__entry->psn,
/* extended headers */
__parse_ib_ehdrs(
__entry->opcode,
(void *)__get_dynamic_array(ehdrs))
)
);
DEFINE_EVENT(hfi1_ibhdr_template, input_ibhdr,
TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
TP_ARGS(dd, hdr));
DEFINE_EVENT(hfi1_ibhdr_template, pio_output_ibhdr,
TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
TP_ARGS(dd, hdr));
DEFINE_EVENT(hfi1_ibhdr_template, ack_output_ibhdr,
TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
TP_ARGS(dd, hdr));
DEFINE_EVENT(hfi1_ibhdr_template, sdma_output_ibhdr,
TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
TP_ARGS(dd, hdr));
#endif /* __HFI1_TRACE_IBHDRS_H */
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_ibhdrs
#include <trace/define_trace.h>
/*
* Copyright(c) 2015, 2016 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#if !defined(__HFI1_TRACE_MISC_H) || defined(TRACE_HEADER_MULTI_READ)
#define __HFI1_TRACE_MISC_H
#include <linux/tracepoint.h>
#include <linux/trace_seq.h>
#include "hfi.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hfi1_misc
TRACE_EVENT(hfi1_interrupt,
TP_PROTO(struct hfi1_devdata *dd, const struct is_table *is_entry,
int src),
TP_ARGS(dd, is_entry, src),
TP_STRUCT__entry(DD_DEV_ENTRY(dd)
__array(char, buf, 64)
__field(int, src)
),
TP_fast_assign(DD_DEV_ASSIGN(dd)
is_entry->is_name(__entry->buf, 64,
src - is_entry->start);
__entry->src = src;
),
TP_printk("[%s] source: %s [%d]", __get_str(dev), __entry->buf,
__entry->src)
);
#endif /* __HFI1_TRACE_MISC_H */
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_misc
#include <trace/define_trace.h>
/*
* Copyright(c) 2015, 2016 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#if !defined(__HFI1_TRACE_RC_H) || defined(TRACE_HEADER_MULTI_READ)
#define __HFI1_TRACE_RC_H
#include <linux/tracepoint.h>
#include <linux/trace_seq.h>
#include "hfi.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hfi1_rc
DECLARE_EVENT_CLASS(hfi1_rc_template,
TP_PROTO(struct rvt_qp *qp, u32 psn),
TP_ARGS(qp, psn),
TP_STRUCT__entry(
DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device))
__field(u32, qpn)
__field(u32, s_flags)
__field(u32, psn)
__field(u32, s_psn)
__field(u32, s_next_psn)
__field(u32, s_sending_psn)
__field(u32, s_sending_hpsn)
__field(u32, r_psn)
),
TP_fast_assign(
DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
__entry->qpn = qp->ibqp.qp_num;
__entry->s_flags = qp->s_flags;
__entry->psn = psn;
__entry->s_psn = qp->s_psn;
__entry->s_next_psn = qp->s_next_psn;
__entry->s_sending_psn = qp->s_sending_psn;
__entry->s_sending_hpsn = qp->s_sending_hpsn;
__entry->r_psn = qp->r_psn;
),
TP_printk(
"[%s] qpn 0x%x s_flags 0x%x psn 0x%x s_psn 0x%x s_next_psn 0x%x s_sending_psn 0x%x sending_hpsn 0x%x r_psn 0x%x",
__get_str(dev),
__entry->qpn,
__entry->s_flags,
__entry->psn,
__entry->s_psn,
__entry->s_next_psn,
__entry->s_sending_psn,
__entry->s_sending_hpsn,
__entry->r_psn
)
);
DEFINE_EVENT(hfi1_rc_template, hfi1_sendcomplete,
TP_PROTO(struct rvt_qp *qp, u32 psn),
TP_ARGS(qp, psn)
);
DEFINE_EVENT(hfi1_rc_template, hfi1_ack,
TP_PROTO(struct rvt_qp *qp, u32 psn),
TP_ARGS(qp, psn)
);
DEFINE_EVENT(hfi1_rc_template, hfi1_timeout,
TP_PROTO(struct rvt_qp *qp, u32 psn),
TP_ARGS(qp, psn)
);
DEFINE_EVENT(hfi1_rc_template, hfi1_rcv_error,
TP_PROTO(struct rvt_qp *qp, u32 psn),
TP_ARGS(qp, psn)
);
#endif /* __HFI1_TRACE_RC_H */
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_rc
#include <trace/define_trace.h>
/*
* Copyright(c) 2015, 2016 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#if !defined(__HFI1_TRACE_RX_H) || defined(TRACE_HEADER_MULTI_READ)
#define __HFI1_TRACE_RX_H
#include <linux/tracepoint.h>
#include <linux/trace_seq.h>
#include "hfi.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hfi1_rx
TRACE_EVENT(hfi1_rcvhdr,
TP_PROTO(struct hfi1_devdata *dd,
u32 ctxt,
u64 eflags,
u32 etype,
u32 hlen,
u32 tlen,
u32 updegr,
u32 etail
),
TP_ARGS(dd, ctxt, eflags, etype, hlen, tlen, updegr, etail),
TP_STRUCT__entry(DD_DEV_ENTRY(dd)
__field(u64, eflags)
__field(u32, ctxt)
__field(u32, etype)
__field(u32, hlen)
__field(u32, tlen)
__field(u32, updegr)
__field(u32, etail)
),
TP_fast_assign(DD_DEV_ASSIGN(dd);
__entry->eflags = eflags;
__entry->ctxt = ctxt;
__entry->etype = etype;
__entry->hlen = hlen;
__entry->tlen = tlen;
__entry->updegr = updegr;
__entry->etail = etail;
),
TP_printk(
"[%s] ctxt %d eflags 0x%llx etype %d,%s hlen %d tlen %d updegr %d etail %d",
__get_str(dev),
__entry->ctxt,
__entry->eflags,
__entry->etype, show_packettype(__entry->etype),
__entry->hlen,
__entry->tlen,
__entry->updegr,
__entry->etail
)
);
TRACE_EVENT(hfi1_receive_interrupt,
TP_PROTO(struct hfi1_devdata *dd, u32 ctxt),
TP_ARGS(dd, ctxt),
TP_STRUCT__entry(DD_DEV_ENTRY(dd)
__field(u32, ctxt)
__field(u8, slow_path)
__field(u8, dma_rtail)
),
TP_fast_assign(DD_DEV_ASSIGN(dd);
__entry->ctxt = ctxt;
if (dd->rcd[ctxt]->do_interrupt ==
&handle_receive_interrupt) {
__entry->slow_path = 1;
__entry->dma_rtail = 0xFF;
} else if (dd->rcd[ctxt]->do_interrupt ==
&handle_receive_interrupt_dma_rtail){
__entry->dma_rtail = 1;
__entry->slow_path = 0;
} else if (dd->rcd[ctxt]->do_interrupt ==
&handle_receive_interrupt_nodma_rtail) {
__entry->dma_rtail = 0;
__entry->slow_path = 0;
}
),
TP_printk("[%s] ctxt %d SlowPath: %d DmaRtail: %d",
__get_str(dev),
__entry->ctxt,
__entry->slow_path,
__entry->dma_rtail
)
);
TRACE_EVENT(hfi1_exp_tid_reg,
TP_PROTO(unsigned int ctxt, u16 subctxt, u32 rarr,
u32 npages, unsigned long va, unsigned long pa,
dma_addr_t dma),
TP_ARGS(ctxt, subctxt, rarr, npages, va, pa, dma),
TP_STRUCT__entry(
__field(unsigned int, ctxt)
__field(u16, subctxt)
__field(u32, rarr)
__field(u32, npages)
__field(unsigned long, va)
__field(unsigned long, pa)
__field(dma_addr_t, dma)
),
TP_fast_assign(
__entry->ctxt = ctxt;
__entry->subctxt = subctxt;
__entry->rarr = rarr;
__entry->npages = npages;
__entry->va = va;
__entry->pa = pa;
__entry->dma = dma;
),
TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx, va:0x%lx dma:0x%llx",
__entry->ctxt,
__entry->subctxt,
__entry->rarr,
__entry->npages,
__entry->pa,
__entry->va,
__entry->dma
)
);
TRACE_EVENT(hfi1_exp_tid_unreg,
TP_PROTO(unsigned int ctxt, u16 subctxt, u32 rarr, u32 npages,
unsigned long va, unsigned long pa, dma_addr_t dma),
TP_ARGS(ctxt, subctxt, rarr, npages, va, pa, dma),
TP_STRUCT__entry(
__field(unsigned int, ctxt)
__field(u16, subctxt)
__field(u32, rarr)
__field(u32, npages)
__field(unsigned long, va)
__field(unsigned long, pa)
__field(dma_addr_t, dma)
),
TP_fast_assign(
__entry->ctxt = ctxt;
__entry->subctxt = subctxt;
__entry->rarr = rarr;
__entry->npages = npages;
__entry->va = va;
__entry->pa = pa;
__entry->dma = dma;
),
TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx, va:0x%lx dma:0x%llx",
__entry->ctxt,
__entry->subctxt,
__entry->rarr,
__entry->npages,
__entry->pa,
__entry->va,
__entry->dma
)
);
TRACE_EVENT(hfi1_exp_tid_inval,
TP_PROTO(unsigned int ctxt, u16 subctxt, unsigned long va, u32 rarr,
u32 npages, dma_addr_t dma),
TP_ARGS(ctxt, subctxt, va, rarr, npages, dma),
TP_STRUCT__entry(
__field(unsigned int, ctxt)
__field(u16, subctxt)
__field(unsigned long, va)
__field(u32, rarr)
__field(u32, npages)
__field(dma_addr_t, dma)
),
TP_fast_assign(
__entry->ctxt = ctxt;
__entry->subctxt = subctxt;
__entry->va = va;
__entry->rarr = rarr;
__entry->npages = npages;
__entry->dma = dma;
),
TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx dma: 0x%llx",
__entry->ctxt,
__entry->subctxt,
__entry->rarr,
__entry->npages,
__entry->va,
__entry->dma
)
);
TRACE_EVENT(hfi1_mmu_invalidate,
TP_PROTO(unsigned int ctxt, u16 subctxt, const char *type,
unsigned long start, unsigned long end),
TP_ARGS(ctxt, subctxt, type, start, end),
TP_STRUCT__entry(
__field(unsigned int, ctxt)
__field(u16, subctxt)
__string(type, type)
__field(unsigned long, start)
__field(unsigned long, end)
),
TP_fast_assign(
__entry->ctxt = ctxt;
__entry->subctxt = subctxt;
__assign_str(type, type);
__entry->start = start;
__entry->end = end;
),
TP_printk("[%3u:%02u] MMU Invalidate (%s) 0x%lx - 0x%lx",
__entry->ctxt,
__entry->subctxt,
__get_str(type),
__entry->start,
__entry->end
)
);
#define SNOOP_PRN \
"slid %.4x dlid %.4x qpn 0x%.6x opcode 0x%.2x,%s " \
"svc lvl %d pkey 0x%.4x [header = %d bytes] [data = %d bytes]"
TRACE_EVENT(snoop_capture,
TP_PROTO(struct hfi1_devdata *dd,
int hdr_len,
struct hfi1_ib_header *hdr,
int data_len,
void *data),
TP_ARGS(dd, hdr_len, hdr, data_len, data),
TP_STRUCT__entry(
DD_DEV_ENTRY(dd)
__field(u16, slid)
__field(u16, dlid)
__field(u32, qpn)
__field(u8, opcode)
__field(u8, sl)
__field(u16, pkey)
__field(u32, hdr_len)
__field(u32, data_len)
__field(u8, lnh)
__dynamic_array(u8, raw_hdr, hdr_len)
__dynamic_array(u8, raw_pkt, data_len)
),
TP_fast_assign(
struct hfi1_other_headers *ohdr;
__entry->lnh = (u8)(be16_to_cpu(hdr->lrh[0]) & 3);
if (__entry->lnh == HFI1_LRH_BTH)
ohdr = &hdr->u.oth;
else
ohdr = &hdr->u.l.oth;
DD_DEV_ASSIGN(dd);
__entry->slid = be16_to_cpu(hdr->lrh[3]);
__entry->dlid = be16_to_cpu(hdr->lrh[1]);
__entry->qpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
__entry->opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff;
__entry->sl = (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
__entry->pkey = be32_to_cpu(ohdr->bth[0]) & 0xffff;
__entry->hdr_len = hdr_len;
__entry->data_len = data_len;
memcpy(__get_dynamic_array(raw_hdr), hdr, hdr_len);
memcpy(__get_dynamic_array(raw_pkt), data, data_len);
),
TP_printk(
"[%s] " SNOOP_PRN,
__get_str(dev),
__entry->slid,
__entry->dlid,
__entry->qpn,
__entry->opcode,
show_ib_opcode(__entry->opcode),
__entry->sl,
__entry->pkey,
__entry->hdr_len,
__entry->data_len
)
);
#endif /* __HFI1_TRACE_RX_H */
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_rx
#include <trace/define_trace.h>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册