]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/net/benet/be_cmds.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6.git] / drivers / net / benet / be_cmds.c
index bee7b822d120fd3a6d7699bf9ee24e0079587284..ee1ad9693c8f064b89a133b6d6f0eb252a80a0dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -59,6 +59,13 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
 
        compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
                                CQE_STATUS_COMPL_MASK;
+
+       if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) &&
+               (compl->tag1 == CMD_SUBSYSTEM_COMMON)) {
+               adapter->flash_status = compl_status;
+               complete(&adapter->flash_compl);
+       }
+
        if (compl_status == MCC_STATUS_SUCCESS) {
                if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) {
                        struct be_cmd_resp_get_stats *resp =
@@ -104,10 +111,26 @@ static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
        return NULL;
 }
 
-int be_process_mcc(struct be_adapter *adapter)
+void be_async_mcc_enable(struct be_adapter *adapter)
+{
+       spin_lock_bh(&adapter->mcc_cq_lock);
+
+       be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, 0);
+       adapter->mcc_obj.rearm_cq = true;
+
+       spin_unlock_bh(&adapter->mcc_cq_lock);
+}
+
+void be_async_mcc_disable(struct be_adapter *adapter)
+{
+       adapter->mcc_obj.rearm_cq = false;
+}
+
+int be_process_mcc(struct be_adapter *adapter, int *status)
 {
        struct be_mcc_compl *compl;
-       int num = 0, status = 0;
+       int num = 0;
+       struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
 
        spin_lock_bh(&adapter->mcc_cq_lock);
        while ((compl = be_mcc_compl_get(adapter))) {
@@ -119,31 +142,31 @@ int be_process_mcc(struct be_adapter *adapter)
                        be_async_link_state_process(adapter,
                                (struct be_async_event_link_state *) compl);
                } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
-                               status = be_mcc_compl_process(adapter, compl);
-                               atomic_dec(&adapter->mcc_obj.q.used);
+                               *status = be_mcc_compl_process(adapter, compl);
+                               atomic_dec(&mcc_obj->q.used);
                }
                be_mcc_compl_use(compl);
                num++;
        }
 
-       if (num)
-               be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, num);
-
        spin_unlock_bh(&adapter->mcc_cq_lock);
-       return status;
+       return num;
 }
 
 /* Wait till no more pending mcc requests are present */
 static int be_mcc_wait_compl(struct be_adapter *adapter)
 {
 #define mcc_timeout            120000 /* 12s timeout */
-       int i, status;
+       int i, num, status = 0;
+       struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+
        for (i = 0; i < mcc_timeout; i++) {
-               status = be_process_mcc(adapter);
-               if (status)
-                       return status;
+               num = be_process_mcc(adapter, &status);
+               if (num)
+                       be_cq_notify(adapter, mcc_obj->cq.id,
+                               mcc_obj->rearm_cq, num);
 
-               if (atomic_read(&adapter->mcc_obj.q.used) == 0)
+               if (atomic_read(&mcc_obj->q.used) == 0)
                        break;
                udelay(100);
        }
@@ -151,7 +174,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
                dev_err(&adapter->pdev->dev, "mccq poll timed out\n");
                return -1;
        }
-       return 0;
+       return status;
 }
 
 /* Notify MCC requests and wait for completion */
@@ -163,23 +186,29 @@ static int be_mcc_notify_wait(struct be_adapter *adapter)
 
 static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
 {
-       int cnt = 0, wait = 5;
+       int msecs = 0;
        u32 ready;
 
        do {
-               ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
+               ready = ioread32(db);
+               if (ready == 0xffffffff) {
+                       dev_err(&adapter->pdev->dev,
+                               "pci slot disconnected\n");
+                       return -1;
+               }
+
+               ready &= MPU_MAILBOX_DB_RDY_MASK;
                if (ready)
                        break;
 
-               if (cnt > 4000000) {
+               if (msecs > 4000) {
                        dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
                        return -1;
                }
 
-               if (cnt > 50)
-                       wait = 200;
-               cnt += wait;
-               udelay(wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(msecs_to_jiffies(1));
+               msecs++;
        } while (true);
 
        return 0;
@@ -198,6 +227,11 @@ static int be_mbox_notify_wait(struct be_adapter *adapter)
        struct be_mcc_mailbox *mbox = mbox_mem->va;
        struct be_mcc_compl *compl = &mbox->compl;
 
+       /* wait for ready to be set */
+       status = be_mbox_db_ready_wait(adapter, db);
+       if (status != 0)
+               return status;
+
        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;
@@ -259,7 +293,7 @@ int be_cmd_POST(struct be_adapter *adapter)
                } else {
                        return 0;
                }
-       } while (timeout < 20);
+       } while (timeout < 40);
 
        dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage);
        return -1;
@@ -286,7 +320,7 @@ static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
                                MCC_WRB_SGE_CNT_SHIFT;
        wrb->payload_length = payload_len;
        wrb->tag0 = opcode;
-       be_dws_cpu_to_le(wrb, 20);
+       be_dws_cpu_to_le(wrb, 8);
 }
 
 /* Don't touch the hdr after it's prepared */
@@ -296,6 +330,7 @@ static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
        req_hdr->opcode = opcode;
        req_hdr->subsystem = subsystem;
        req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
+       req_hdr->version = 0;
 }
 
 static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
@@ -396,6 +431,9 @@ int be_cmd_fw_clean(struct be_adapter *adapter)
        u8 *wrb;
        int status;
 
+       if (adapter->eeh_err)
+               return -EIO;
+
        spin_lock(&adapter->mbox_lock);
 
        wrb = (u8 *)wrb_from_mbox(adapter);
@@ -433,8 +471,6 @@ int be_cmd_eq_create(struct be_adapter *adapter,
 
        req->num_pages =  cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
 
-       AMAP_SET_BITS(struct amap_eq_context, func, req->context,
-                       be_pci_func(adapter));
        AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
        /* 4byte eqe*/
        AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
@@ -597,7 +633,6 @@ int be_cmd_cq_create(struct be_adapter *adapter,
        AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
        AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
        AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
-       AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter));
        be_dws_cpu_to_le(ctxt, sizeof(req->context));
 
        be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
@@ -644,9 +679,8 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                        OPCODE_COMMON_MCC_CREATE, sizeof(*req));
 
-       req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+       req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
 
-       AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter));
        AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
        AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
                be_encoded_q_len(mccq->len));
@@ -695,8 +729,6 @@ int be_cmd_txq_create(struct be_adapter *adapter,
 
        AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt,
                be_encoded_q_len(txq->len));
-       AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt,
-                       be_pci_func(adapter));
        AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1);
        AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id);
 
@@ -768,6 +800,9 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
        u8 subsys = 0, opcode = 0;
        int status;
 
+       if (adapter->eeh_err)
+               return -EIO;
+
        spin_lock(&adapter->mbox_lock);
 
        wrb = wrb_from_mbox(adapter);
@@ -814,7 +849,8 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
  * Uses mbox
  */
 int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
-               u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id)
+               u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id,
+               u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_if_create *req;
@@ -831,6 +867,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req));
 
+       req->hdr.domain = domain;
        req->capability_flags = cpu_to_le32(cap_flags);
        req->enable_flags = cpu_to_le32(en_flags);
        req->pmac_invalid = pmac_invalid;
@@ -856,6 +893,9 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id)
        struct be_cmd_req_if_destroy *req;
        int status;
 
+       if (adapter->eeh_err)
+               return -EIO;
+
        spin_lock(&adapter->mbox_lock);
 
        wrb = wrb_from_mbox(adapter);
@@ -1079,6 +1119,10 @@ int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en)
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
                OPCODE_ETH_PROMISCUOUS, sizeof(*req));
 
+       /* In FW versions X.102.149/X.101.487 and later,
+        * the port setting associated only with the
+        * issuing pci function will take effect
+        */
        if (port_num)
                req->port1_promiscuous = en;
        else
@@ -1096,8 +1140,7 @@ err:
  * (mc == NULL) => multicast promiscous
  */
 int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
-               struct dev_mc_list *mc_list, u32 mc_count,
-               struct be_dma_mem *mem)
+               struct net_device *netdev, struct be_dma_mem *mem)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_mcast_mac_config *req = mem->va;
@@ -1124,14 +1167,15 @@ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
                OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req));
 
        req->interface_id = if_id;
-       if (mc_list) {
+       if (netdev) {
                int i;
-               struct dev_mc_list *mc;
+               struct netdev_hw_addr *ha;
 
-               req->num_mac = cpu_to_le16(mc_count);
+               req->num_mac = cpu_to_le16(netdev_mc_count(netdev));
 
-               for (mc = mc_list, i = 0; mc; mc = mc->next, i++)
-                       memcpy(req->mac[i].byte, mc->dmi_addr, ETH_ALEN);
+               i = 0;
+               netdev_for_each_mc_addr(ha, netdev)
+                       memcpy(req->mac[i].byte, ha->addr, ETH_ALEN);
        } else {
                req->promiscuous = 1;
        }
@@ -1374,22 +1418,24 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
                        u32 flash_type, u32 flash_opcode, u32 buf_size)
 {
        struct be_mcc_wrb *wrb;
-       struct be_cmd_write_flashrom *req = cmd->va;
+       struct be_cmd_write_flashrom *req;
        struct be_sge *sge;
        int status;
 
        spin_lock_bh(&adapter->mcc_lock);
+       adapter->flash_status = 0;
 
        wrb = wrb_from_mccq(adapter);
        if (!wrb) {
                status = -EBUSY;
-               goto err;
+               goto err_unlock;
        }
        req = cmd->va;
        sge = nonembedded_sgl(wrb);
 
        be_wrb_hdr_prepare(wrb, cmd->size, false, 1,
                        OPCODE_COMMON_WRITE_FLASHROM);
+       wrb->tag1 = CMD_SUBSYSTEM_COMMON;
 
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                OPCODE_COMMON_WRITE_FLASHROM, cmd->size);
@@ -1401,14 +1447,24 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
        req->params.op_code = cpu_to_le32(flash_opcode);
        req->params.data_buf_size = cpu_to_le32(buf_size);
 
-       status = be_mcc_notify_wait(adapter);
+       be_mcc_notify(adapter);
+       spin_unlock_bh(&adapter->mcc_lock);
 
-err:
+       if (!wait_for_completion_timeout(&adapter->flash_compl,
+                       msecs_to_jiffies(12000)))
+               status = -1;
+       else
+               status = adapter->flash_status;
+
+       return status;
+
+err_unlock:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
 
-int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc)
+int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
+                        int offset)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_write_flashrom *req;
@@ -1429,10 +1485,10 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc)
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4);
 
-       req->params.op_type = cpu_to_le32(FLASHROM_TYPE_REDBOOT);
+       req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT);
        req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
-       req->params.offset = 0x3FFFC;
-       req->params.data_buf_size = 0x4;
+       req->params.offset = cpu_to_le32(offset);
+       req->params.data_buf_size = cpu_to_le32(0x4);
 
        status = be_mcc_notify_wait(adapter);
        if (!status)
@@ -1443,7 +1499,7 @@ err:
        return status;
 }
 
-extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
+int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
                                struct be_dma_mem *nonemb_cmd)
 {
        struct be_mcc_wrb *wrb;
@@ -1478,3 +1534,162 @@ err:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
+
+int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
+                       u8 loopback_type, u8 enable)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_set_lmode *req;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+
+       req = embedded_payload(wrb);
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
+                               OPCODE_LOWLEVEL_SET_LOOPBACK_MODE);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
+                       OPCODE_LOWLEVEL_SET_LOOPBACK_MODE,
+                       sizeof(*req));
+
+       req->src_port = port_num;
+       req->dest_port = port_num;
+       req->loopback_type = loopback_type;
+       req->loopback_state = enable;
+
+       status = be_mcc_notify_wait(adapter);
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
+int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
+               u32 loopback_type, u32 pkt_size, u32 num_pkts, u64 pattern)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_loopback_test *req;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+
+       req = embedded_payload(wrb);
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
+                               OPCODE_LOWLEVEL_LOOPBACK_TEST);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
+                       OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req));
+       req->hdr.timeout = cpu_to_le32(4);
+
+       req->pattern = cpu_to_le64(pattern);
+       req->src_port = cpu_to_le32(port_num);
+       req->dest_port = cpu_to_le32(port_num);
+       req->pkt_size = cpu_to_le32(pkt_size);
+       req->num_pkts = cpu_to_le32(num_pkts);
+       req->loopback_type = cpu_to_le32(loopback_type);
+
+       status = be_mcc_notify_wait(adapter);
+       if (!status) {
+               struct be_cmd_resp_loopback_test *resp = embedded_payload(wrb);
+               status = le32_to_cpu(resp->status);
+       }
+
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
+int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
+                               u32 byte_cnt, struct be_dma_mem *cmd)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_ddrdma_test *req;
+       struct be_sge *sge;
+       int status;
+       int i, j = 0;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+       req = cmd->va;
+       sge = nonembedded_sgl(wrb);
+       be_wrb_hdr_prepare(wrb, cmd->size, false, 1,
+                               OPCODE_LOWLEVEL_HOST_DDR_DMA);
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
+                       OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size);
+
+       sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
+       sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
+       sge->len = cpu_to_le32(cmd->size);
+
+       req->pattern = cpu_to_le64(pattern);
+       req->byte_count = cpu_to_le32(byte_cnt);
+       for (i = 0; i < byte_cnt; i++) {
+               req->snd_buff[i] = (u8)(pattern >> (j*8));
+               j++;
+               if (j > 7)
+                       j = 0;
+       }
+
+       status = be_mcc_notify_wait(adapter);
+
+       if (!status) {
+               struct be_cmd_resp_ddrdma_test *resp;
+               resp = cmd->va;
+               if ((memcmp(resp->rcv_buff, req->snd_buff, byte_cnt) != 0) ||
+                               resp->snd_err) {
+                       status = -1;
+               }
+       }
+
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
+int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+                               struct be_dma_mem *nonemb_cmd)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_seeprom_read *req;
+       struct be_sge *sge;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       req = nonemb_cmd->va;
+       sge = nonembedded_sgl(wrb);
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+                       OPCODE_COMMON_SEEPROM_READ);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_SEEPROM_READ, sizeof(*req));
+
+       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+       sge->len = cpu_to_le32(nonemb_cmd->size);
+
+       status = be_mcc_notify_wait(adapter);
+
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}