197549c34SHans Petter Selasky /*
297549c34SHans Petter Selasky * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved.
397549c34SHans Petter Selasky *
497549c34SHans Petter Selasky * This software is available to you under a choice of one of two
597549c34SHans Petter Selasky * licenses. You may choose to be licensed under the terms of the GNU
697549c34SHans Petter Selasky * General Public License (GPL) Version 2, available from the file
797549c34SHans Petter Selasky * COPYING in the main directory of this source tree, or the
897549c34SHans Petter Selasky * OpenIB.org BSD license below:
997549c34SHans Petter Selasky *
1097549c34SHans Petter Selasky * Redistribution and use in source and binary forms, with or
1197549c34SHans Petter Selasky * without modification, are permitted provided that the following
1297549c34SHans Petter Selasky * conditions are met:
1397549c34SHans Petter Selasky *
1497549c34SHans Petter Selasky * - Redistributions of source code must retain the above
1597549c34SHans Petter Selasky * copyright notice, this list of conditions and the following
1697549c34SHans Petter Selasky * disclaimer.
1797549c34SHans Petter Selasky *
1897549c34SHans Petter Selasky * - Redistributions in binary form must reproduce the above
1997549c34SHans Petter Selasky * copyright notice, this list of conditions and the following
2097549c34SHans Petter Selasky * disclaimer in the documentation and/or other materials
2197549c34SHans Petter Selasky * provided with the distribution.
2297549c34SHans Petter Selasky *
2397549c34SHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2497549c34SHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2597549c34SHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2697549c34SHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2797549c34SHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2897549c34SHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2997549c34SHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3097549c34SHans Petter Selasky * SOFTWARE.
3197549c34SHans Petter Selasky *
3297549c34SHans Petter Selasky */
3397549c34SHans Petter Selasky
3497549c34SHans Petter Selasky #define LINUXKPI_PARAM_PREFIX mlx4_
3597549c34SHans Petter Selasky
3697549c34SHans Petter Selasky #include <linux/module.h>
3797549c34SHans Petter Selasky #include <linux/delay.h>
3897549c34SHans Petter Selasky #include <linux/netdevice.h>
3997549c34SHans Petter Selasky #include <linux/slab.h>
4097549c34SHans Petter Selasky
4197549c34SHans Petter Selasky #include <dev/mlx4/driver.h>
4297549c34SHans Petter Selasky #include <dev/mlx4/device.h>
4397549c34SHans Petter Selasky #include <dev/mlx4/cmd.h>
4497549c34SHans Petter Selasky
4597549c34SHans Petter Selasky #include "en.h"
4697549c34SHans Petter Selasky
4797549c34SHans Petter Selasky /* Mellanox ConnectX HCA Ethernet driver */
4897549c34SHans Petter Selasky
4997549c34SHans Petter Selasky #define MLX4_EN_PARM_INT(X, def_val, desc) \
5097549c34SHans Petter Selasky static unsigned int X = def_val;\
5197549c34SHans Petter Selasky module_param(X , uint, 0444); \
5297549c34SHans Petter Selasky MODULE_PARM_DESC(X, desc);
5397549c34SHans Petter Selasky
5497549c34SHans Petter Selasky
5597549c34SHans Petter Selasky /*
5697549c34SHans Petter Selasky * Device scope module parameters
5797549c34SHans Petter Selasky */
5897549c34SHans Petter Selasky
5997549c34SHans Petter Selasky /* Enable RSS UDP traffic */
6097549c34SHans Petter Selasky MLX4_EN_PARM_INT(udp_rss, 1,
61c3191c2eSHans Petter Selasky "Enable RSS for incoming UDP traffic or disabled (0)");
6297549c34SHans Petter Selasky
6397549c34SHans Petter Selasky /* Priority pausing */
6497549c34SHans Petter Selasky MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
6597549c34SHans Petter Selasky " Per priority bit mask");
6697549c34SHans Petter Selasky MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
6797549c34SHans Petter Selasky " Per priority bit mask");
6897549c34SHans Petter Selasky
69c3191c2eSHans Petter Selasky MLX4_EN_PARM_INT(inline_thold, MAX_INLINE,
70c3191c2eSHans Petter Selasky "Threshold for using inline data (range: 17-104, default: 104)");
71c3191c2eSHans Petter Selasky
7297549c34SHans Petter Selasky #define MAX_PFC_TX 0xff
7397549c34SHans Petter Selasky #define MAX_PFC_RX 0xff
7497549c34SHans Petter Selasky
mlx4_en_get_profile(struct mlx4_en_dev * mdev)7597549c34SHans Petter Selasky static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
7697549c34SHans Petter Selasky {
7797549c34SHans Petter Selasky struct mlx4_en_profile *params = &mdev->profile;
7897549c34SHans Petter Selasky int i;
7997549c34SHans Petter Selasky
8097549c34SHans Petter Selasky params->udp_rss = udp_rss;
8197549c34SHans Petter Selasky params->num_tx_rings_p_up = min_t(int, mp_ncpus,
8297549c34SHans Petter Selasky MLX4_EN_MAX_TX_RING_P_UP);
8397549c34SHans Petter Selasky if (params->udp_rss && !(mdev->dev->caps.flags
8497549c34SHans Petter Selasky & MLX4_DEV_CAP_FLAG_UDP_RSS)) {
8597549c34SHans Petter Selasky mlx4_warn(mdev, "UDP RSS is not supported on this device.\n");
8697549c34SHans Petter Selasky params->udp_rss = 0;
8797549c34SHans Petter Selasky }
8897549c34SHans Petter Selasky for (i = 1; i <= MLX4_MAX_PORTS; i++) {
8997549c34SHans Petter Selasky params->prof[i].rx_pause = 1;
9097549c34SHans Petter Selasky params->prof[i].rx_ppp = pfcrx;
9197549c34SHans Petter Selasky params->prof[i].tx_pause = 1;
9297549c34SHans Petter Selasky params->prof[i].tx_ppp = pfctx;
9397549c34SHans Petter Selasky params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
9497549c34SHans Petter Selasky params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
9597549c34SHans Petter Selasky params->prof[i].tx_ring_num = params->num_tx_rings_p_up *
9697549c34SHans Petter Selasky MLX4_EN_NUM_UP;
9797549c34SHans Petter Selasky params->prof[i].rss_rings = 0;
98c3191c2eSHans Petter Selasky params->prof[i].inline_thold = inline_thold;
9997549c34SHans Petter Selasky }
10097549c34SHans Petter Selasky
10197549c34SHans Petter Selasky return 0;
10297549c34SHans Petter Selasky }
10397549c34SHans Petter Selasky
mlx4_en_get_netdev(struct mlx4_dev * dev,void * ctx,u8 port)10497549c34SHans Petter Selasky static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port)
10597549c34SHans Petter Selasky {
10697549c34SHans Petter Selasky struct mlx4_en_dev *endev = ctx;
10797549c34SHans Petter Selasky
10897549c34SHans Petter Selasky return endev->pndev[port];
10997549c34SHans Petter Selasky }
11097549c34SHans Petter Selasky
mlx4_en_event(struct mlx4_dev * dev,void * endev_ptr,enum mlx4_dev_event event,unsigned long port)11197549c34SHans Petter Selasky static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
11297549c34SHans Petter Selasky enum mlx4_dev_event event, unsigned long port)
11397549c34SHans Petter Selasky {
11497549c34SHans Petter Selasky struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr;
11597549c34SHans Petter Selasky struct mlx4_en_priv *priv;
11697549c34SHans Petter Selasky
11797549c34SHans Petter Selasky switch (event) {
11897549c34SHans Petter Selasky case MLX4_DEV_EVENT_PORT_UP:
11997549c34SHans Petter Selasky case MLX4_DEV_EVENT_PORT_DOWN:
12097549c34SHans Petter Selasky if (!mdev->pndev[port])
12197549c34SHans Petter Selasky return;
122*9d593d5aSBjoern A. Zeeb priv = mlx4_netdev_priv(mdev->pndev[port]);
12397549c34SHans Petter Selasky /* To prevent races, we poll the link state in a separate
12497549c34SHans Petter Selasky task rather than changing it here */
12597549c34SHans Petter Selasky priv->link_state = event;
12697549c34SHans Petter Selasky queue_work(mdev->workqueue, &priv->linkstate_task);
12797549c34SHans Petter Selasky break;
12897549c34SHans Petter Selasky
12997549c34SHans Petter Selasky case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
13097549c34SHans Petter Selasky mlx4_err(mdev, "Internal error detected, restarting device\n");
13197549c34SHans Petter Selasky break;
13297549c34SHans Petter Selasky
13397549c34SHans Petter Selasky case MLX4_DEV_EVENT_SLAVE_INIT:
13497549c34SHans Petter Selasky case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
13597549c34SHans Petter Selasky break;
13697549c34SHans Petter Selasky default:
13797549c34SHans Petter Selasky if (port < 1 || port > dev->caps.num_ports ||
13897549c34SHans Petter Selasky !mdev->pndev[port])
13997549c34SHans Petter Selasky return;
14097549c34SHans Petter Selasky mlx4_warn(mdev, "Unhandled event %d for port %d\n", event,
14197549c34SHans Petter Selasky (int) port);
14297549c34SHans Petter Selasky }
14397549c34SHans Petter Selasky }
14497549c34SHans Petter Selasky
mlx4_en_remove(struct mlx4_dev * dev,void * endev_ptr)14597549c34SHans Petter Selasky static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
14697549c34SHans Petter Selasky {
14797549c34SHans Petter Selasky struct mlx4_en_dev *mdev = endev_ptr;
148c3191c2eSHans Petter Selasky int i;
14997549c34SHans Petter Selasky
15097549c34SHans Petter Selasky mutex_lock(&mdev->state_lock);
15197549c34SHans Petter Selasky mdev->device_up = false;
15297549c34SHans Petter Selasky mutex_unlock(&mdev->state_lock);
15397549c34SHans Petter Selasky
15497549c34SHans Petter Selasky mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
15597549c34SHans Petter Selasky if (mdev->pndev[i])
15697549c34SHans Petter Selasky mlx4_en_destroy_netdev(mdev->pndev[i]);
15797549c34SHans Petter Selasky
15897549c34SHans Petter Selasky flush_workqueue(mdev->workqueue);
15997549c34SHans Petter Selasky destroy_workqueue(mdev->workqueue);
160c3191c2eSHans Petter Selasky (void) mlx4_mr_free(dev, &mdev->mr);
16197549c34SHans Petter Selasky iounmap(mdev->uar_map);
16297549c34SHans Petter Selasky mlx4_uar_free(dev, &mdev->priv_uar);
16397549c34SHans Petter Selasky mlx4_pd_free(dev, mdev->priv_pdn);
16497549c34SHans Petter Selasky kfree(mdev);
16597549c34SHans Petter Selasky }
16697549c34SHans Petter Selasky
mlx4_en_activate(struct mlx4_dev * dev,void * ctx)167c3191c2eSHans Petter Selasky static void mlx4_en_activate(struct mlx4_dev *dev, void *ctx)
168c3191c2eSHans Petter Selasky {
169c3191c2eSHans Petter Selasky int i;
170c3191c2eSHans Petter Selasky struct mlx4_en_dev *mdev = ctx;
171c3191c2eSHans Petter Selasky
172c3191c2eSHans Petter Selasky /* Create a netdev for each port */
173c3191c2eSHans Petter Selasky mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
174c3191c2eSHans Petter Selasky mlx4_info(mdev, "Activating port:%d\n", i);
175c3191c2eSHans Petter Selasky if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
176c3191c2eSHans Petter Selasky mdev->pndev[i] = NULL;
177c3191c2eSHans Petter Selasky }
178c3191c2eSHans Petter Selasky }
179c3191c2eSHans Petter Selasky
mlx4_en_add(struct mlx4_dev * dev)18097549c34SHans Petter Selasky static void *mlx4_en_add(struct mlx4_dev *dev)
18197549c34SHans Petter Selasky {
18297549c34SHans Petter Selasky struct mlx4_en_dev *mdev;
18397549c34SHans Petter Selasky int i;
18497549c34SHans Petter Selasky
185c3191c2eSHans Petter Selasky mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
186c3191c2eSHans Petter Selasky if (!mdev)
18797549c34SHans Petter Selasky goto err_free_res;
18897549c34SHans Petter Selasky
18997549c34SHans Petter Selasky if (mlx4_pd_alloc(dev, &mdev->priv_pdn))
19097549c34SHans Petter Selasky goto err_free_dev;
19197549c34SHans Petter Selasky
19297549c34SHans Petter Selasky if (mlx4_uar_alloc(dev, &mdev->priv_uar))
19397549c34SHans Petter Selasky goto err_pd;
19497549c34SHans Petter Selasky
19597549c34SHans Petter Selasky mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT,
19697549c34SHans Petter Selasky PAGE_SIZE);
19797549c34SHans Petter Selasky if (!mdev->uar_map)
19897549c34SHans Petter Selasky goto err_uar;
19997549c34SHans Petter Selasky spin_lock_init(&mdev->uar_lock);
20097549c34SHans Petter Selasky
20197549c34SHans Petter Selasky mdev->dev = dev;
202c3191c2eSHans Petter Selasky mdev->dma_device = &dev->persist->pdev->dev;
203c3191c2eSHans Petter Selasky mdev->pdev = dev->persist->pdev;
20497549c34SHans Petter Selasky mdev->device_up = false;
20597549c34SHans Petter Selasky
20697549c34SHans Petter Selasky mdev->LSO_support = !!(dev->caps.flags & (1 << 15));
20797549c34SHans Petter Selasky if (!mdev->LSO_support)
20897549c34SHans Petter Selasky mlx4_warn(mdev, "LSO not supported, please upgrade to later "
20997549c34SHans Petter Selasky "FW version to enable LSO\n");
21097549c34SHans Petter Selasky
21197549c34SHans Petter Selasky if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
21297549c34SHans Petter Selasky MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ,
21397549c34SHans Petter Selasky 0, 0, &mdev->mr)) {
21497549c34SHans Petter Selasky mlx4_err(mdev, "Failed allocating memory region\n");
21597549c34SHans Petter Selasky goto err_map;
21697549c34SHans Petter Selasky }
21797549c34SHans Petter Selasky if (mlx4_mr_enable(mdev->dev, &mdev->mr)) {
21897549c34SHans Petter Selasky mlx4_err(mdev, "Failed enabling memory region\n");
21997549c34SHans Petter Selasky goto err_mr;
22097549c34SHans Petter Selasky }
22197549c34SHans Petter Selasky
22297549c34SHans Petter Selasky /* Build device profile according to supplied module parameters */
223c3191c2eSHans Petter Selasky if (mlx4_en_get_profile(mdev)) {
224c3191c2eSHans Petter Selasky mlx4_err(mdev, "Bad module parameters, aborting\n");
22597549c34SHans Petter Selasky goto err_mr;
22697549c34SHans Petter Selasky }
22797549c34SHans Petter Selasky
22897549c34SHans Petter Selasky /* Configure which ports to start according to module parameters */
22997549c34SHans Petter Selasky mdev->port_cnt = 0;
23097549c34SHans Petter Selasky mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
23197549c34SHans Petter Selasky mdev->port_cnt++;
23297549c34SHans Petter Selasky
233c3191c2eSHans Petter Selasky /* Set default number of RX rings*/
234c3191c2eSHans Petter Selasky mlx4_en_set_num_rx_rings(mdev);
23597549c34SHans Petter Selasky
23697549c34SHans Petter Selasky /* Create our own workqueue for reset/multicast tasks
23797549c34SHans Petter Selasky * Note: we cannot use the shared workqueue because of deadlocks caused
23897549c34SHans Petter Selasky * by the rtnl lock */
23997549c34SHans Petter Selasky mdev->workqueue = create_singlethread_workqueue("mlx4_en");
240c3191c2eSHans Petter Selasky if (!mdev->workqueue)
24197549c34SHans Petter Selasky goto err_mr;
24297549c34SHans Petter Selasky
24397549c34SHans Petter Selasky /* At this stage all non-port specific tasks are complete:
24497549c34SHans Petter Selasky * mark the card state as up */
24597549c34SHans Petter Selasky mutex_init(&mdev->state_lock);
24697549c34SHans Petter Selasky mdev->device_up = true;
24797549c34SHans Petter Selasky
24897549c34SHans Petter Selasky return mdev;
24997549c34SHans Petter Selasky
25097549c34SHans Petter Selasky err_mr:
251c3191c2eSHans Petter Selasky (void) mlx4_mr_free(dev, &mdev->mr);
25297549c34SHans Petter Selasky err_map:
25397549c34SHans Petter Selasky if (mdev->uar_map)
25497549c34SHans Petter Selasky iounmap(mdev->uar_map);
25597549c34SHans Petter Selasky err_uar:
25697549c34SHans Petter Selasky mlx4_uar_free(dev, &mdev->priv_uar);
25797549c34SHans Petter Selasky err_pd:
25897549c34SHans Petter Selasky mlx4_pd_free(dev, mdev->priv_pdn);
25997549c34SHans Petter Selasky err_free_dev:
26097549c34SHans Petter Selasky kfree(mdev);
26197549c34SHans Petter Selasky err_free_res:
26297549c34SHans Petter Selasky return NULL;
26397549c34SHans Petter Selasky }
26497549c34SHans Petter Selasky
26597549c34SHans Petter Selasky static struct mlx4_interface mlx4_en_interface = {
26697549c34SHans Petter Selasky .add = mlx4_en_add,
26797549c34SHans Petter Selasky .remove = mlx4_en_remove,
26897549c34SHans Petter Selasky .event = mlx4_en_event,
26997549c34SHans Petter Selasky .get_dev = mlx4_en_get_netdev,
27097549c34SHans Petter Selasky .protocol = MLX4_PROT_ETH,
271c3191c2eSHans Petter Selasky .activate = mlx4_en_activate,
27297549c34SHans Petter Selasky };
27397549c34SHans Petter Selasky
mlx4_en_verify_params(void)27497549c34SHans Petter Selasky static void mlx4_en_verify_params(void)
27597549c34SHans Petter Selasky {
27697549c34SHans Petter Selasky if (pfctx > MAX_PFC_TX) {
277c3191c2eSHans Petter Selasky pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n",
27897549c34SHans Petter Selasky pfctx, MAX_PFC_TX);
27997549c34SHans Petter Selasky pfctx = 0;
28097549c34SHans Petter Selasky }
28197549c34SHans Petter Selasky
28297549c34SHans Petter Selasky if (pfcrx > MAX_PFC_RX) {
283c3191c2eSHans Petter Selasky pr_warn("mlx4_en: WARNING: illegal module parameter pfcrx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n",
28497549c34SHans Petter Selasky pfcrx, MAX_PFC_RX);
28597549c34SHans Petter Selasky pfcrx = 0;
28697549c34SHans Petter Selasky }
28797549c34SHans Petter Selasky
288c3191c2eSHans Petter Selasky if (inline_thold < MIN_PKT_LEN || inline_thold > MAX_INLINE) {
289c3191c2eSHans Petter Selasky pr_warn("mlx4_en: WARNING: illegal module parameter inline_thold %d - should be in range %d-%d, will be changed to default (%d)\n",
290c3191c2eSHans Petter Selasky inline_thold, MIN_PKT_LEN, MAX_INLINE, MAX_INLINE);
291c3191c2eSHans Petter Selasky inline_thold = MAX_INLINE;
292c3191c2eSHans Petter Selasky }
293c3191c2eSHans Petter Selasky }
29497549c34SHans Petter Selasky
mlx4_en_init(void)29597549c34SHans Petter Selasky static int __init mlx4_en_init(void)
29697549c34SHans Petter Selasky {
29797549c34SHans Petter Selasky mlx4_en_verify_params();
29897549c34SHans Petter Selasky
29997549c34SHans Petter Selasky return mlx4_register_interface(&mlx4_en_interface);
30097549c34SHans Petter Selasky }
30197549c34SHans Petter Selasky
mlx4_en_cleanup(void)30297549c34SHans Petter Selasky static void __exit mlx4_en_cleanup(void)
30397549c34SHans Petter Selasky {
30497549c34SHans Petter Selasky mlx4_unregister_interface(&mlx4_en_interface);
30597549c34SHans Petter Selasky }
30697549c34SHans Petter Selasky
3071866c98eSHans Petter Selasky module_init_order(mlx4_en_init, SI_ORDER_SIXTH);
3081866c98eSHans Petter Selasky module_exit_order(mlx4_en_cleanup, SI_ORDER_SIXTH);
30997549c34SHans Petter Selasky
31097549c34SHans Petter Selasky static int
mlx4en_evhand(module_t mod,int event,void * arg)31197549c34SHans Petter Selasky mlx4en_evhand(module_t mod, int event, void *arg)
31297549c34SHans Petter Selasky {
31397549c34SHans Petter Selasky return (0);
31497549c34SHans Petter Selasky }
31597549c34SHans Petter Selasky static moduledata_t mlx4en_mod = {
31697549c34SHans Petter Selasky .name = "mlx4en",
31797549c34SHans Petter Selasky .evhand = mlx4en_evhand,
31897549c34SHans Petter Selasky };
31997549c34SHans Petter Selasky DECLARE_MODULE(mlx4en, mlx4en_mod, SI_SUB_OFED_PREINIT, SI_ORDER_ANY);
32097549c34SHans Petter Selasky MODULE_DEPEND(mlx4en, mlx4, 1, 1, 1);
32197549c34SHans Petter Selasky MODULE_DEPEND(mlx4en, linuxkpi, 1, 1, 1);
322