/*
* Copyright (C) 2005 - 2009 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@serverengines.com
*
* ServerEngines
* 209 N. Fair Oaks Ave
* Sunnyvale, CA 94085
*/
#include "be.h"
static int be_mbox_db_ready_wait(void __iomem *db)
{
int cnt = 0, wait = 5;
u32 ready;
do {
ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
if (ready)
break;
if (cnt > 200000) {
printk(KERN_WARNING DRV_NAME
": mbox_db poll timed out\n");
return -1;
}
if (cnt > 50)
wait = 200;
cnt += wait;
udelay(wait);
} while (true);
return 0;
}
/*
* Insert the mailbox address into the doorbell in two steps
*/
static int be_mbox_db_ring(struct be_ctrl_info *ctrl)
{
int status;
u16 compl_status, extd_status;
u32 val = 0;
void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
struct be_dma_mem *mbox_mem = &ctrl->mbox_mem;
struct be_mcc_mailbox *mbox = mbox_mem->va;
struct be_mcc_cq_entry *cqe = &mbox->cqe;
memset(cqe, 0, sizeof(*cqe));
val &= ~MPU_MAILBOX_DB_RDY_MASK;
val |= MPU_MAILBOX_DB_HI_MASK;
/* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
iowrite32(val, db);
/* wait for ready to be set */
status = be_mbox_db_ready_wait(db);
if (status != 0)
return status;
val = 0;
val &= ~MPU_MAILBOX_DB_RDY_MASK;
val &= ~MPU_MAILBOX_DB_HI_MASK;
/* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
val |= (u32)(mbox_mem->dma >> 4) << 2;
iowrite32(val, db);
status = be_mbox_db_ready_wait(db);
if (status != 0)
return status;
/* compl entry has been made now */
be_dws_le_to_cpu(cqe, sizeof(*cqe));
if (!(cqe->flags & CQE_FLAGS_VALID_MASK)) {
printk(KERN_WARNING DRV_NAME ": ERROR invalid mbox compl\n");
return -1;
}
compl_status = (cqe->status >> CQE_STATUS_COMPL_SHIFT) &
CQE_STATUS_COMPL_MASK;
if (compl_status != MCC_STATUS_SUCCESS) {
extd_status = (cqe->status >> CQE_STATUS_EXTD_SHIFT) &
CQE_STATUS_EXTD_MASK;
printk(KERN_WARNING DRV_NAME
": ERROR in cmd compl. status(compl/extd)=%d/%d\n",
compl_status, extd_status);
}
return compl_status;
}
static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage)
{
u32 sem = ioread32(ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
*stage = sem & EP_SEMAPHORE_POST_STAGE_MASK;
if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK)
return -1;
else
return 0;
}
static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage)
{
u16 stage, cnt, error;
for (cnt = 0; cnt < 5000; cnt++) {
error = be_POST_stage_get(ctrl, &stage);
if (error)
return -1;
if (stage == poll_stage)
break;
udelay(1000);
}
if (stage != poll_stage)
return -1;
return 0;
}
int be_cmd_POST(struct be_ctrl_info *ctrl)
{
u16 stage, error;
error = be_POST_stage_get(ctrl, &stage);
if (error)
goto err;
if (stage == POST_STAGE_ARMFW_RDY)
return 0;
if (stage != POST_STAGE_AWAITING_HOST_RDY)
goto err;
/* On awaiting host rdy, reset and again poll on awaiting host rdy */
iowrite32(POST_STAGE_BE_RESET, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
error = be_POST_stage_poll(ctrl, POST_STAGE_AWAITING_HOST_RDY);
if (error)
goto err;
/* Now kickoff POST and poll on armfw ready */
iowrite32(POST_STAGE_HOST_RDY, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
error = be_POST_stage_poll(ctrl, POST_STAGE_ARMFW_RDY);
if (error)
goto err;
return 0;
err:
printk(KERN_WARNING DRV_NAME ": ERROR, stage=%d\n", stage);
return -1;
}
static inline void *embedded_payload(struct be_mcc_wrb *wrb)
{
return wrb->payload.embedded_payload;
}
static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
{
return &wrb->payload.sgl[0];
}
/* Don't touch the hdr after it's prepared */
static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
bool embedded, u8 sge_cnt)
{
if (embedded)
wrb->