Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[pandora-kernel.git] / drivers / net / cnic.c
index 263a294..302be4a 100644 (file)
@@ -699,13 +699,13 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
 static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
 {
        int i;
-       u32 *page_table = dma->pgtbl;
+       __le32 *page_table = (__le32 *) dma->pgtbl;
 
        for (i = 0; i < dma->num_pages; i++) {
                /* Each entry needs to be in big endian format. */
-               *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+               *page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
                page_table++;
-               *page_table = (u32) dma->pg_map_arr[i];
+               *page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
                page_table++;
        }
 }
@@ -713,13 +713,13 @@ static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
 static void cnic_setup_page_tbl_le(struct cnic_dev *dev, struct cnic_dma *dma)
 {
        int i;
-       u32 *page_table = dma->pgtbl;
+       __le32 *page_table = (__le32 *) dma->pgtbl;
 
        for (i = 0; i < dma->num_pages; i++) {
                /* Each entry needs to be in little endian format. */
-               *page_table = dma->pg_map_arr[i] & 0xffffffff;
+               *page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
                page_table++;
-               *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+               *page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
                page_table++;
        }
 }
@@ -2760,6 +2760,8 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
        u32 status_idx = (u16) *cp->kcq1.status_idx_ptr;
        int kcqe_cnt;
 
+       /* status block index must be read before reading other fields */
+       rmb();
        cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
 
        while ((kcqe_cnt = cnic_get_kcqes(dev, &cp->kcq1))) {
@@ -2770,6 +2772,8 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
                barrier();
                if (status_idx != *cp->kcq1.status_idx_ptr) {
                        status_idx = (u16) *cp->kcq1.status_idx_ptr;
+                       /* status block index must be read first */
+                       rmb();
                        cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
                } else
                        break;
@@ -2888,6 +2892,8 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
        u32 last_status = *info->status_idx_ptr;
        int kcqe_cnt;
 
+       /* status block index must be read before reading the KCQ */
+       rmb();
        while ((kcqe_cnt = cnic_get_kcqes(dev, info))) {
 
                service_kcqes(dev, kcqe_cnt);
@@ -2898,6 +2904,8 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
                        break;
 
                last_status = *info->status_idx_ptr;
+               /* status block index must be read before reading the KCQ */
+               rmb();
        }
        return last_status;
 }
@@ -2906,26 +2914,35 @@ static void cnic_service_bnx2x_bh(unsigned long data)
 {
        struct cnic_dev *dev = (struct cnic_dev *) data;
        struct cnic_local *cp = dev->cnic_priv;
-       u32 status_idx;
+       u32 status_idx, new_status_idx;
 
        if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
                return;
 
-       status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
+       while (1) {
+               status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
 
-       CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
+               CNIC_WR16(dev, cp->kcq1.io_addr,
+                         cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
-               status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
+               if (!BNX2X_CHIP_IS_E2(cp->chip_id)) {
+                       cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
+                                          status_idx, IGU_INT_ENABLE, 1);
+                       break;
+               }
+
+               new_status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
+
+               if (new_status_idx != status_idx)
+                       continue;
 
                CNIC_WR16(dev, cp->kcq2.io_addr, cp->kcq2.sw_prod_idx +
                          MAX_KCQ_IDX);
 
                cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF,
                                status_idx, IGU_INT_ENABLE, 1);
-       } else {
-               cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
-                                  status_idx, IGU_INT_ENABLE, 1);
+
+               break;
        }
 }