1, NULL, index, eqctx );
}
+static inline int
+hermon_cmd_query_eq ( struct hermon *hermon, unsigned int index,
+ struct hermonprm_eqc *eqctx ) {
+ return hermon_cmd ( hermon,
+ HERMON_HCR_OUT_CMD ( HERMON_HCR_QUERY_EQ,
+ 1, sizeof ( *eqctx ) ),
+ 0, NULL, index, eqctx );
+}
+
static inline int
hermon_cmd_sw2hw_cq ( struct hermon *hermon, unsigned long cqn,
const struct hermonprm_completion_queue_context *cqctx ){
MLX_FILL_1 ( &cqctx, 2,
page_offset, ( hermon_cq->mtt.page_offset >> 5 ) );
MLX_FILL_2 ( &cqctx, 3,
- usr_page, HERMON_UAR_PAGE,
+ usr_page, HERMON_UAR_NON_EQ_PAGE,
log_cq_size, fls ( cq->num_cqes - 1 ) );
MLX_FILL_1 ( &cqctx, 7, mtt_base_addr_l,
( hermon_cq->mtt.mtt_base_addr >> 3 ) );
goto err_hermon_qp;
}
+ /* Calculate doorbell address */
+ hermon_qp->send.doorbell =
+ ( hermon->uar + HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE +
+ HERMON_DB_POST_SND_OFFSET );
+
/* Allocate work queue buffer */
hermon_qp->send.num_wqes = ( qp->send.num_wqes /* headroom */ + 1 +
( 2048 / sizeof ( hermon_qp->send.wqe[0] ) ) );
qpc_eec_data.log_sq_stride,
( fls ( sizeof ( hermon_qp->send.wqe[0] ) - 1 ) - 4 ) );
MLX_FILL_1 ( &qpctx, 5,
- qpc_eec_data.usr_page, HERMON_UAR_PAGE );
+ qpc_eec_data.usr_page, HERMON_UAR_NON_EQ_PAGE );
MLX_FILL_1 ( &qpctx, 33, qpc_eec_data.cqn_snd, qp->send.cq->cqn );
MLX_FILL_1 ( &qpctx, 38, qpc_eec_data.page_offset,
( hermon_qp->mtt.page_offset >> 6 ) );
/* Ring doorbell register */
MLX_FILL_1 ( &db_reg.send, 0, qn, qp->qpn );
DBGCP ( hermon, "Ringing doorbell %08lx with %08lx\n",
- virt_to_phys ( hermon->uar + HERMON_DB_POST_SND_OFFSET ),
- db_reg.dword[0] );
- writel ( db_reg.dword[0], ( hermon->uar + HERMON_DB_POST_SND_OFFSET ));
+ virt_to_phys ( hermon_send_wq->doorbell ), db_reg.dword[0] );
+ writel ( db_reg.dword[0], ( hermon_send_wq->doorbell ) );
/* Update work queue's index */
wq->next_idx++;
/* Update doorbell record */
MLX_FILL_1 ( &hermon_cq->doorbell, 0, update_ci,
- ( cq->next_idx & 0xffffffUL ) );
+ ( cq->next_idx & 0x00ffffffUL ) );
}
}
unsigned int i;
int rc;
+ /* Select event queue number */
+ hermon_eq->eqn = ( 4 * hermon->cap.reserved_uars );
+ if ( hermon_eq->eqn < hermon->cap.reserved_eqs )
+ hermon_eq->eqn = hermon->cap.reserved_eqs;
+
+ /* Calculate doorbell address */
+ hermon_eq->doorbell =
+ ( hermon->uar + HERMON_DB_EQ_OFFSET ( hermon_eq->eqn ) );
+
/* Allocate event queue itself */
hermon_eq->eqe_size =
( HERMON_NUM_EQES * sizeof ( hermon_eq->eqe[0] ) );
MLX_FILL_1 ( &eqctx, 3, log_eq_size, fls ( HERMON_NUM_EQES - 1 ) );
MLX_FILL_1 ( &eqctx, 7, mtt_base_addr_l,
( hermon_eq->mtt.mtt_base_addr >> 3 ) );
- if ( ( rc = hermon_cmd_sw2hw_eq ( hermon, 0, &eqctx ) ) != 0 ) {
+ if ( ( rc = hermon_cmd_sw2hw_eq ( hermon, hermon_eq->eqn,
+ &eqctx ) ) != 0 ) {
DBGC ( hermon, "Hermon %p SW2HW_EQ failed: %s\n",
hermon, strerror ( rc ) );
goto err_sw2hw_eq;
/* Map events to this event queue */
memset ( &mask, 0, sizeof ( mask ) );
MLX_FILL_1 ( &mask, 1, port_state_change, 1 );
- if ( ( rc = hermon_cmd_map_eq ( hermon, ( HERMON_MAP_EQ_MAP | 0 ),
+ if ( ( rc = hermon_cmd_map_eq ( hermon,
+ ( HERMON_MAP_EQ | hermon_eq->eqn ),
&mask ) ) != 0 ) {
DBGC ( hermon, "Hermon %p MAP_EQ failed: %s\n",
hermon, strerror ( rc ) );
goto err_map_eq;
}
+ DBGC ( hermon, "Hermon %p EQN %#lx ring at [%p,%p])\n",
+ hermon, hermon_eq->eqn, hermon_eq->eqe,
+ ( ( ( void * ) hermon_eq->eqe ) + hermon_eq->eqe_size ) );
return 0;
err_map_eq:
- hermon_cmd_hw2sw_eq ( hermon, 0, &eqctx );
+ hermon_cmd_hw2sw_eq ( hermon, hermon_eq->eqn, &eqctx );
err_sw2hw_eq:
hermon_free_mtt ( hermon, &hermon_eq->mtt );
err_alloc_mtt:
/* Unmap events from event queue */
memset ( &mask, 0, sizeof ( mask ) );
MLX_FILL_1 ( &mask, 1, port_state_change, 1 );
- if ( ( rc = hermon_cmd_map_eq ( hermon, ( HERMON_MAP_EQ_UNMAP | 0 ),
+ if ( ( rc = hermon_cmd_map_eq ( hermon,
+ ( HERMON_UNMAP_EQ | hermon_eq->eqn ),
&mask ) ) != 0 ) {
DBGC ( hermon, "Hermon %p FATAL MAP_EQ failed to unmap: %s\n",
hermon, strerror ( rc ) );
}
/* Take ownership back from hardware */
- if ( ( rc = hermon_cmd_hw2sw_eq ( hermon, 0, &eqctx ) ) != 0 ) {
+ if ( ( rc = hermon_cmd_hw2sw_eq ( hermon, hermon_eq->eqn,
+ &eqctx ) ) != 0 ) {
DBGC ( hermon, "Hermon %p FATAL HW2SW_EQ failed: %s\n",
hermon, strerror ( rc ) );
/* Leak memory and return; at least we avoid corruption */
unsigned int event_type;
while ( 1 ) {
+ /* Look for event entry */
eqe_idx_mask = ( HERMON_NUM_EQES - 1 );
eqe = &hermon_eq->eqe[hermon_eq->next_idx & eqe_idx_mask];
if ( MLX_GET ( &eqe->generic, owner ) ^
hermon_eq->next_idx++;
/* Ring doorbell */
- memset ( &db_reg, 0, sizeof ( db_reg ) );
- MLX_FILL_1 ( &db_reg.event, 0, ci, hermon_eq->next_idx );
+ MLX_FILL_1 ( &db_reg.event, 0,
+ ci, ( hermon_eq->next_idx & 0x00ffffffUL ) );
DBGCP ( hermon, "Ringing doorbell %08lx with %08lx\n",
- virt_to_phys ( hermon->uar + HERMON_DB_EQ0_OFFSET ),
+ virt_to_phys ( hermon_eq->doorbell ),
db_reg.dword[0] );
- writel ( db_reg.dword[0],
- ( hermon->uar + HERMON_DB_EQ0_OFFSET ) );
+ writel ( db_reg.dword[0], hermon_eq->doorbell );
}
}
/* Get PCI BARs */
hermon->config = ioremap ( pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR),
HERMON_PCI_CONFIG_BAR_SIZE );
- hermon->uar = ioremap ( ( pci_bar_start ( pci, HERMON_PCI_UAR_BAR ) +
- HERMON_UAR_PAGE * HERMON_PAGE_SIZE ),
- HERMON_PAGE_SIZE );
+ hermon->uar = ioremap ( pci_bar_start ( pci, HERMON_PCI_UAR_BAR ),
+ HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE );
/* Allocate space for mailboxes */
hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE,
#define HERMON_HCR_MAP_EQ 0x0012
#define HERMON_HCR_SW2HW_EQ 0x0013
#define HERMON_HCR_HW2SW_EQ 0x0014
+#define HERMON_HCR_QUERY_EQ 0x0015
#define HERMON_HCR_SW2HW_CQ 0x0016
#define HERMON_HCR_HW2SW_CQ 0x0017
#define HERMON_HCR_RST2INIT_QP 0x0019
#define HERMON_PAGE_SIZE 4096
#define HERMON_DB_POST_SND_OFFSET 0x14
-#define HERMON_DB_EQ0_OFFSET 0x800
+#define HERMON_DB_EQ_OFFSET(_eqn) \
+ ( 0x800 + HERMON_PAGE_SIZE * ( (_eqn) / 4 ) + 0x08 * ( (_eqn) % 4 ) )
#define HERMON_QP_OPT_PARAM_QKEY 0x00000020UL
-#define HERMON_MAP_EQ_MAP ( 0UL << 31 )
-#define HERMON_MAP_EQ_UNMAP ( 1UL << 31 )
+#define HERMON_MAP_EQ ( 0UL << 31 )
+#define HERMON_UNMAP_EQ ( 1UL << 31 )
#define HERMON_EV_PORT_STATE_CHANGE 0x09
* Pages 0-127 are reserved for event queue doorbells only, so we use
* page 128.
*/
-#define HERMON_UAR_PAGE 128
+#define HERMON_UAR_NON_EQ_PAGE 128
/** Maximum number of allocatable MTT entries
*
union hermon_send_wqe *wqe;
/** Size of work queue */
size_t wqe_size;
+ /** Doorbell register */
+ void *doorbell;
};
/** Alignment of Hermon receive work queue entries */
*
* This is a policy decision, not a device limit.
*/
-#define HERMON_MAX_EQS 4
+#define HERMON_MAX_EQS 8
/** A Hermon event queue */
struct hermon_event_queue {
size_t eqe_size;
/** MTT descriptor */
struct hermon_mtt mtt;
+ /** Event queue number */
+ unsigned long eqn;
/** Next event queue entry index */
unsigned long next_idx;
+ /** Doorbell register */
+ void *doorbell;
};
/** Number of event queue entries