mlx4_core: Move kernel doorbell management into core
In addition to mlx4_ib, there will be ethernet and FC consumers of mlx4_core, so move the code for managing kernel doorbells into the core module to avoid having to duplicate this multiple times. Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
committed by
Roland Dreier
parent
14fb05b349
commit
6296883ca4
@@ -196,3 +196,114 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mlx4_buf_free);
|
||||
|
||||
static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device)
|
||||
{
|
||||
struct mlx4_db_pgdir *pgdir;
|
||||
|
||||
pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL);
|
||||
if (!pgdir)
|
||||
return NULL;
|
||||
|
||||
bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2);
|
||||
pgdir->bits[0] = pgdir->order0;
|
||||
pgdir->bits[1] = pgdir->order1;
|
||||
pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
|
||||
&pgdir->db_dma, GFP_KERNEL);
|
||||
if (!pgdir->db_page) {
|
||||
kfree(pgdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pgdir;
|
||||
}
|
||||
|
||||
static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir,
|
||||
struct mlx4_db *db, int order)
|
||||
{
|
||||
int o;
|
||||
int i;
|
||||
|
||||
for (o = order; o <= 1; ++o) {
|
||||
i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o);
|
||||
if (i < MLX4_DB_PER_PAGE >> o)
|
||||
goto found;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
|
||||
found:
|
||||
clear_bit(i, pgdir->bits[o]);
|
||||
|
||||
i <<= o;
|
||||
|
||||
if (o > order)
|
||||
set_bit(i ^ 1, pgdir->bits[order]);
|
||||
|
||||
db->u.pgdir = pgdir;
|
||||
db->index = i;
|
||||
db->db = pgdir->db_page + db->index;
|
||||
db->dma = pgdir->db_dma + db->index * 4;
|
||||
db->order = order;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order)
|
||||
{
|
||||
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||
struct mlx4_db_pgdir *pgdir;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&priv->pgdir_mutex);
|
||||
|
||||
list_for_each_entry(pgdir, &priv->pgdir_list, list)
|
||||
if (!mlx4_alloc_db_from_pgdir(pgdir, db, order))
|
||||
goto out;
|
||||
|
||||
pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev));
|
||||
if (!pgdir) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_add(&pgdir->list, &priv->pgdir_list);
|
||||
|
||||
/* This should never fail -- we just allocated an empty page: */
|
||||
WARN_ON(mlx4_alloc_db_from_pgdir(pgdir, db, order));
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->pgdir_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mlx4_db_alloc);
|
||||
|
||||
void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db)
|
||||
{
|
||||
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||
int o;
|
||||
int i;
|
||||
|
||||
mutex_lock(&priv->pgdir_mutex);
|
||||
|
||||
o = db->order;
|
||||
i = db->index;
|
||||
|
||||
if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) {
|
||||
clear_bit(i ^ 1, db->u.pgdir->order0);
|
||||
++o;
|
||||
}
|
||||
i >>= o;
|
||||
set_bit(i, db->u.pgdir->bits[o]);
|
||||
|
||||
if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) {
|
||||
dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
|
||||
db->u.pgdir->db_page, db->u.pgdir->db_dma);
|
||||
list_del(&db->u.pgdir->list);
|
||||
kfree(db->u.pgdir);
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->pgdir_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mlx4_db_free);
|
||||
|
Reference in New Issue
Block a user