/* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.
*/
staticinlinevoid tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
{ /* * This barrier makes sure that all updates to ownership bits * done by set_eqe_hw() hit memory before the consumer index * is updated. set_eq_ci() allows the HCA to possibly write * more EQ entries, and we want to avoid the exceedingly * unlikely possibility of the HCA writing an entry and then * having set_eqe_hw() overwrite the owner field.
*/
wmb();
mthca_write64(MTHCA_EQ_DB_SET_CI | eq->eqn, ci & (eq->nent - 1),
dev->kar + MTHCA_EQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
staticinlinevoid arbel_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
{ /* See comment in tavor_set_eq_ci() above. */
wmb();
__raw_writel((__force u32) cpu_to_be32(ci),
dev->eq_regs.arbel.eq_set_ci_base + eq->eqn * 8); /* We still want ordering, just not swabbing, so add a barrier */
mb();
}
case MTHCA_EVENT_TYPE_EQ_OVERFLOW:
mthca_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); break;
case MTHCA_EVENT_TYPE_EEC_CATAS_ERROR: case MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR: case MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR: case MTHCA_EVENT_TYPE_ECC_DETECT: default:
mthca_warn(dev, "Unhandled event %02x(%02x) on EQ %d\n",
eqe->type, eqe->subtype, eq->eqn); break;
}
/* * The HCA will think the queue has overflowed if we * don't tell it we've been processing events. We * create our EQs with MTHCA_NUM_SPARE_EQE extra * entries, so we must update our consumer index at * least that often.
*/ if (unlikely(set_ci >= MTHCA_NUM_SPARE_EQE)) { /* * Conditional on hca_type is OK here because * this is a rare case, not the fast path.
*/
set_eq_ci(dev, eq, eq->cons_index);
set_ci = 0;
}
}
/* * Rely on caller to set consumer index so that we don't have * to test hca_type in our interrupt handling fast path.
*/ return eqes_found;
}
for (i = 0; i < MTHCA_NUM_EQ; ++i) if (ecr & dev->eq_table.eq[i].eqn_mask) { if (mthca_eq_int(dev, &dev->eq_table.eq[i]))
tavor_set_eq_ci(dev, &dev->eq_table.eq[i],
dev->eq_table.eq[i].cons_index);
tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);
}
/* MSI-X vectors always belong to us */ return IRQ_HANDLED;
}
static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr)
{ struct mthca_dev *dev = dev_ptr; int work = 0; int i;
if (dev->eq_table.clr_mask)
writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);
for (i = 0; i < MTHCA_NUM_EQ; ++i) if (mthca_eq_int(dev, &dev->eq_table.eq[i])) {
work = 1;
arbel_set_eq_ci(dev, &dev->eq_table.eq[i],
dev->eq_table.eq[i].cons_index);
}
for (i = 0; i < npages; ++i) {
eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
PAGE_SIZE, &t, GFP_KERNEL); if (!eq->page_list[i].buf) goto err_out_free_pages;
err_out_free_pages: for (i = 0; i < npages; ++i) if (eq->page_list[i].buf)
dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
eq->page_list[i].buf,
dma_unmap_addr(&eq->page_list[i],
mapping));
staticvoid mthca_free_eq(struct mthca_dev *dev, struct mthca_eq *eq)
{ struct mthca_mailbox *mailbox; int err; int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
PAGE_SIZE; int i;
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); if (IS_ERR(mailbox)) return;
err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn); if (err)
mthca_warn(dev, "HW2SW_EQ returned %d\n", err);
dev->eq_table.arm_mask &= ~eq->eqn_mask;
if (0) {
mthca_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) { if (i % 4 == 0)
printk("[%02x] ", i * 4);
printk(" %08x", be32_to_cpup(mailbox->buf + i * 4)); if ((i + 1) % 4 == 0)
printk("\n");
}
}
mthca_free_mr(dev, &eq->mr); for (i = 0; i < npages; ++i)
dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
eq->page_list[i].buf,
dma_unmap_addr(&eq->page_list[i], mapping));
staticvoid mthca_free_irqs(struct mthca_dev *dev)
{ int i;
if (dev->eq_table.have_irq)
free_irq(dev->pdev->irq, dev); for (i = 0; i < MTHCA_NUM_EQ; ++i) if (dev->eq_table.eq[i].have_irq) {
free_irq(dev->eq_table.eq[i].msi_x_vector,
dev->eq_table.eq + i);
dev->eq_table.eq[i].have_irq = 0;
}
}
*map = ioremap(base + offset, size); if (!*map) return -ENOMEM;
return 0;
}
staticint mthca_map_eq_regs(struct mthca_dev *dev)
{ if (mthca_is_memfree(dev)) { /* * We assume that the EQ arm and EQ set CI registers * fall within the first BAR. We can't trust the * values firmware gives us, since those addresses are * valid on the HCA's side of the PCI bus but not * necessarily the host side.
*/ if (mthca_map_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
&dev->clr_base)) {
mthca_err(dev, "Couldn't map interrupt clear register, " "aborting.\n"); return -ENOMEM;
}
/* * Add 4 because we limit ourselves to EQs 0 ... 31, * so we only need the low word of the register.
*/ if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.eq_arm_base) + 4, 4,
&dev->eq_regs.arbel.eq_arm)) {
mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
iounmap(dev->clr_base); return -ENOMEM;
}
int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt)
{ int ret;
/* * We assume that mapping one page is enough for the whole EQ * context table. This is fine with all current HCAs, because * we only use 32 EQs and each EQ uses 32 bytes of context * memory, or 1 KB total.
*/
dev->eq_table.icm_virt = icm_virt;
dev->eq_table.icm_page = alloc_page(GFP_HIGHUSER); if (!dev->eq_table.icm_page) return -ENOMEM;
dev->eq_table.icm_dma =
dma_map_page(&dev->pdev->dev, dev->eq_table.icm_page, 0,
PAGE_SIZE, DMA_BIDIRECTIONAL); if (dma_mapping_error(&dev->pdev->dev, dev->eq_table.icm_dma)) {
__free_page(dev->eq_table.icm_page); return -ENOMEM;
}
ret = mthca_MAP_ICM_page(dev, dev->eq_table.icm_dma, icm_virt); if (ret) {
dma_unmap_page(&dev->pdev->dev, dev->eq_table.icm_dma,
PAGE_SIZE, DMA_BIDIRECTIONAL);
__free_page(dev->eq_table.icm_page);
}
err = mthca_MAP_EQ(dev, async_mask(dev),
0, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn); if (err)
mthca_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, err);
err = mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,
0, dev->eq_table.eq[MTHCA_EQ_CMD].eqn); if (err)
mthca_warn(dev, "MAP_EQ for cmd EQ %d failed (%d)\n",
dev->eq_table.eq[MTHCA_EQ_CMD].eqn, err);
for (i = 0; i < MTHCA_NUM_EQ; ++i) if (mthca_is_memfree(dev))
arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask); else
tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.