diff options
author | Roland Dreier <roland@purestorage.com> | 2012-09-26 00:24:07 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2012-09-30 23:33:46 -0400 |
commit | f3d4c89ee4a8c993cc334a67f84a3fb724a1dd35 (patch) | |
tree | 5b003102f64cf1df23a43f738627e2f7cf1e21cc /drivers/net/ethernet | |
parent | 84b1f1538fadd066cc9877c2276f3fefd8a79bc4 (diff) |
mlx4_core: Fix crash on uninitialized priv->cmd.slave_sem
On an SR-IOV master device, __mlx4_init_one() calls mlx4_init_hca()
before mlx4_multi_func_init(). However, for unlucky configurations,
mlx4_init_hca() might call mlx4_SENSE_PORT() (via mlx4_dev_cap()), and
that calls mlx4_cmd_imm() with MLX4_CMD_WRAPPED set.
However, on a multifunction device with MLX4_CMD_WRAPPED, __mlx4_cmd()
calls into mlx4_slave_cmd(), and that immediately tries to do
down(&priv->cmd.slave_sem);
but priv->cmd.slave_sem isn't initialized until mlx4_multi_func_init()
(which we haven't called yet). The next thing it tries to do is access
priv->mfunc.vhcr, but that hasn't been allocated yet.
Fix this by moving the initialization of slave_sem and vhcr up into
mlx4_cmd_init(). Also, since slave_sem is really just being used as a
mutex, convert it into a slave_cmd_mutex.
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 51 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/main.c | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4.h | 2 |
3 files changed, 38 insertions, 26 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 90774b7e47a4..3d1899ff1076 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c | |||
@@ -395,7 +395,8 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, | |||
395 | struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; | 395 | struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; |
396 | int ret; | 396 | int ret; |
397 | 397 | ||
398 | down(&priv->cmd.slave_sem); | 398 | mutex_lock(&priv->cmd.slave_cmd_mutex); |
399 | |||
399 | vhcr->in_param = cpu_to_be64(in_param); | 400 | vhcr->in_param = cpu_to_be64(in_param); |
400 | vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; | 401 | vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; |
401 | vhcr->in_modifier = cpu_to_be32(in_modifier); | 402 | vhcr->in_modifier = cpu_to_be32(in_modifier); |
@@ -403,6 +404,7 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, | |||
403 | vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); | 404 | vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); |
404 | vhcr->status = 0; | 405 | vhcr->status = 0; |
405 | vhcr->flags = !!(priv->cmd.use_events) << 6; | 406 | vhcr->flags = !!(priv->cmd.use_events) << 6; |
407 | |||
406 | if (mlx4_is_master(dev)) { | 408 | if (mlx4_is_master(dev)) { |
407 | ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); | 409 | ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); |
408 | if (!ret) { | 410 | if (!ret) { |
@@ -439,7 +441,8 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, | |||
439 | mlx4_err(dev, "failed execution of VHCR_POST command" | 441 | mlx4_err(dev, "failed execution of VHCR_POST command" |
440 | "opcode 0x%x\n", op); | 442 | "opcode 0x%x\n", op); |
441 | } | 443 | } |
442 | up(&priv->cmd.slave_sem); | 444 | |
445 | mutex_unlock(&priv->cmd.slave_cmd_mutex); | ||
443 | return ret; | 446 | return ret; |
444 | } | 447 | } |
445 | 448 | ||
@@ -1559,14 +1562,15 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, | |||
1559 | if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && | 1562 | if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && |
1560 | (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) | 1563 | (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) |
1561 | goto reset_slave; | 1564 | goto reset_slave; |
1562 | down(&priv->cmd.slave_sem); | 1565 | |
1566 | mutex_lock(&priv->cmd.slave_cmd_mutex); | ||
1563 | if (mlx4_master_process_vhcr(dev, slave, NULL)) { | 1567 | if (mlx4_master_process_vhcr(dev, slave, NULL)) { |
1564 | mlx4_err(dev, "Failed processing vhcr for slave:%d," | 1568 | mlx4_err(dev, "Failed processing vhcr for slave:%d," |
1565 | " resetting slave.\n", slave); | 1569 | " resetting slave.\n", slave); |
1566 | up(&priv->cmd.slave_sem); | 1570 | mutex_unlock(&priv->cmd.slave_cmd_mutex); |
1567 | goto reset_slave; | 1571 | goto reset_slave; |
1568 | } | 1572 | } |
1569 | up(&priv->cmd.slave_sem); | 1573 | mutex_unlock(&priv->cmd.slave_cmd_mutex); |
1570 | break; | 1574 | break; |
1571 | default: | 1575 | default: |
1572 | mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); | 1576 | mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); |
@@ -1707,14 +1711,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) | |||
1707 | struct mlx4_slave_state *s_state; | 1711 | struct mlx4_slave_state *s_state; |
1708 | int i, j, err, port; | 1712 | int i, j, err, port; |
1709 | 1713 | ||
1710 | priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, | ||
1711 | &priv->mfunc.vhcr_dma, | ||
1712 | GFP_KERNEL); | ||
1713 | if (!priv->mfunc.vhcr) { | ||
1714 | mlx4_err(dev, "Couldn't allocate vhcr.\n"); | ||
1715 | return -ENOMEM; | ||
1716 | } | ||
1717 | |||
1718 | if (mlx4_is_master(dev)) | 1714 | if (mlx4_is_master(dev)) |
1719 | priv->mfunc.comm = | 1715 | priv->mfunc.comm = |
1720 | ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) + | 1716 | ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) + |
@@ -1777,7 +1773,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) | |||
1777 | if (mlx4_init_resource_tracker(dev)) | 1773 | if (mlx4_init_resource_tracker(dev)) |
1778 | goto err_thread; | 1774 | goto err_thread; |
1779 | 1775 | ||
1780 | sema_init(&priv->cmd.slave_sem, 1); | ||
1781 | err = mlx4_ARM_COMM_CHANNEL(dev); | 1776 | err = mlx4_ARM_COMM_CHANNEL(dev); |
1782 | if (err) { | 1777 | if (err) { |
1783 | mlx4_err(dev, " Failed to arm comm channel eq: %x\n", | 1778 | mlx4_err(dev, " Failed to arm comm channel eq: %x\n", |
@@ -1791,8 +1786,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) | |||
1791 | mlx4_err(dev, "Couldn't sync toggles\n"); | 1786 | mlx4_err(dev, "Couldn't sync toggles\n"); |
1792 | goto err_comm; | 1787 | goto err_comm; |
1793 | } | 1788 | } |
1794 | |||
1795 | sema_init(&priv->cmd.slave_sem, 1); | ||
1796 | } | 1789 | } |
1797 | return 0; | 1790 | return 0; |
1798 | 1791 | ||
@@ -1822,6 +1815,7 @@ int mlx4_cmd_init(struct mlx4_dev *dev) | |||
1822 | struct mlx4_priv *priv = mlx4_priv(dev); | 1815 | struct mlx4_priv *priv = mlx4_priv(dev); |
1823 | 1816 | ||
1824 | mutex_init(&priv->cmd.hcr_mutex); | 1817 | mutex_init(&priv->cmd.hcr_mutex); |
1818 | mutex_init(&priv->cmd.slave_cmd_mutex); | ||
1825 | sema_init(&priv->cmd.poll_sem, 1); | 1819 | sema_init(&priv->cmd.poll_sem, 1); |
1826 | priv->cmd.use_events = 0; | 1820 | priv->cmd.use_events = 0; |
1827 | priv->cmd.toggle = 1; | 1821 | priv->cmd.toggle = 1; |
@@ -1838,14 +1832,30 @@ int mlx4_cmd_init(struct mlx4_dev *dev) | |||
1838 | } | 1832 | } |
1839 | } | 1833 | } |
1840 | 1834 | ||
1835 | if (mlx4_is_mfunc(dev)) { | ||
1836 | priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, | ||
1837 | &priv->mfunc.vhcr_dma, | ||
1838 | GFP_KERNEL); | ||
1839 | if (!priv->mfunc.vhcr) { | ||
1840 | mlx4_err(dev, "Couldn't allocate VHCR.\n"); | ||
1841 | goto err_hcr; | ||
1842 | } | ||
1843 | } | ||
1844 | |||
1841 | priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, | 1845 | priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, |
1842 | MLX4_MAILBOX_SIZE, | 1846 | MLX4_MAILBOX_SIZE, |
1843 | MLX4_MAILBOX_SIZE, 0); | 1847 | MLX4_MAILBOX_SIZE, 0); |
1844 | if (!priv->cmd.pool) | 1848 | if (!priv->cmd.pool) |
1845 | goto err_hcr; | 1849 | goto err_vhcr; |
1846 | 1850 | ||
1847 | return 0; | 1851 | return 0; |
1848 | 1852 | ||
1853 | err_vhcr: | ||
1854 | if (mlx4_is_mfunc(dev)) | ||
1855 | dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, | ||
1856 | priv->mfunc.vhcr, priv->mfunc.vhcr_dma); | ||
1857 | priv->mfunc.vhcr = NULL; | ||
1858 | |||
1849 | err_hcr: | 1859 | err_hcr: |
1850 | if (!mlx4_is_slave(dev)) | 1860 | if (!mlx4_is_slave(dev)) |
1851 | iounmap(priv->cmd.hcr); | 1861 | iounmap(priv->cmd.hcr); |
@@ -1868,9 +1878,6 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev) | |||
1868 | } | 1878 | } |
1869 | 1879 | ||
1870 | iounmap(priv->mfunc.comm); | 1880 | iounmap(priv->mfunc.comm); |
1871 | dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, | ||
1872 | priv->mfunc.vhcr, priv->mfunc.vhcr_dma); | ||
1873 | priv->mfunc.vhcr = NULL; | ||
1874 | } | 1881 | } |
1875 | 1882 | ||
1876 | void mlx4_cmd_cleanup(struct mlx4_dev *dev) | 1883 | void mlx4_cmd_cleanup(struct mlx4_dev *dev) |
@@ -1881,6 +1888,10 @@ void mlx4_cmd_cleanup(struct mlx4_dev *dev) | |||
1881 | 1888 | ||
1882 | if (!mlx4_is_slave(dev)) | 1889 | if (!mlx4_is_slave(dev)) |
1883 | iounmap(priv->cmd.hcr); | 1890 | iounmap(priv->cmd.hcr); |
1891 | if (mlx4_is_mfunc(dev)) | ||
1892 | dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, | ||
1893 | priv->mfunc.vhcr, priv->mfunc.vhcr_dma); | ||
1894 | priv->mfunc.vhcr = NULL; | ||
1884 | } | 1895 | } |
1885 | 1896 | ||
1886 | /* | 1897 | /* |
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 296288c7cb37..1e9f816a94db 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c | |||
@@ -1159,10 +1159,10 @@ static void mlx4_slave_exit(struct mlx4_dev *dev) | |||
1159 | { | 1159 | { |
1160 | struct mlx4_priv *priv = mlx4_priv(dev); | 1160 | struct mlx4_priv *priv = mlx4_priv(dev); |
1161 | 1161 | ||
1162 | down(&priv->cmd.slave_sem); | 1162 | mutex_lock(&priv->cmd.slave_cmd_mutex); |
1163 | if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) | 1163 | if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) |
1164 | mlx4_warn(dev, "Failed to close slave function.\n"); | 1164 | mlx4_warn(dev, "Failed to close slave function.\n"); |
1165 | up(&priv->cmd.slave_sem); | 1165 | mutex_unlock(&priv->cmd.slave_cmd_mutex); |
1166 | } | 1166 | } |
1167 | 1167 | ||
1168 | static int map_bf_area(struct mlx4_dev *dev) | 1168 | static int map_bf_area(struct mlx4_dev *dev) |
@@ -1214,7 +1214,7 @@ static int mlx4_init_slave(struct mlx4_dev *dev) | |||
1214 | u32 slave_read; | 1214 | u32 slave_read; |
1215 | u32 cmd_channel_ver; | 1215 | u32 cmd_channel_ver; |
1216 | 1216 | ||
1217 | down(&priv->cmd.slave_sem); | 1217 | mutex_lock(&priv->cmd.slave_cmd_mutex); |
1218 | priv->cmd.max_cmds = 1; | 1218 | priv->cmd.max_cmds = 1; |
1219 | mlx4_warn(dev, "Sending reset\n"); | 1219 | mlx4_warn(dev, "Sending reset\n"); |
1220 | ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, | 1220 | ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, |
@@ -1263,12 +1263,13 @@ static int mlx4_init_slave(struct mlx4_dev *dev) | |||
1263 | goto err; | 1263 | goto err; |
1264 | if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME)) | 1264 | if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME)) |
1265 | goto err; | 1265 | goto err; |
1266 | up(&priv->cmd.slave_sem); | 1266 | |
1267 | mutex_unlock(&priv->cmd.slave_cmd_mutex); | ||
1267 | return 0; | 1268 | return 0; |
1268 | 1269 | ||
1269 | err: | 1270 | err: |
1270 | mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); | 1271 | mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); |
1271 | up(&priv->cmd.slave_sem); | 1272 | mutex_unlock(&priv->cmd.slave_cmd_mutex); |
1272 | return -EIO; | 1273 | return -EIO; |
1273 | } | 1274 | } |
1274 | 1275 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 4b1fbd84a68f..71eed05426ec 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h | |||
@@ -513,9 +513,9 @@ struct mlx4_cmd { | |||
513 | struct pci_pool *pool; | 513 | struct pci_pool *pool; |
514 | void __iomem *hcr; | 514 | void __iomem *hcr; |
515 | struct mutex hcr_mutex; | 515 | struct mutex hcr_mutex; |
516 | struct mutex slave_cmd_mutex; | ||
516 | struct semaphore poll_sem; | 517 | struct semaphore poll_sem; |
517 | struct semaphore event_sem; | 518 | struct semaphore event_sem; |
518 | struct semaphore slave_sem; | ||
519 | int max_cmds; | 519 | int max_cmds; |
520 | spinlock_t context_lock; | 520 | spinlock_t context_lock; |
521 | int free_head; | 521 | int free_head; |