linux/drivers/net/ethernet/huawei/hinic/hinic_port.c
<<
>>
Prefs
   1/*
   2 * Huawei HiNIC PCI Express Linux driver
   3 * Copyright(c) 2017 Huawei Technologies Co., Ltd
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12 * for more details.
  13 *
  14 */
  15
  16#include <linux/types.h>
  17#include <linux/netdevice.h>
  18#include <linux/etherdevice.h>
  19#include <linux/if_vlan.h>
  20#include <linux/pci.h>
  21#include <linux/device.h>
  22#include <linux/errno.h>
  23
  24#include "hinic_hw_if.h"
  25#include "hinic_hw_dev.h"
  26#include "hinic_port.h"
  27#include "hinic_dev.h"
  28
  29#define HINIC_MIN_MTU_SIZE              256
  30#define HINIC_MAX_JUMBO_FRAME_SIZE      15872
  31
  32enum mac_op {
  33        MAC_DEL,
  34        MAC_SET,
  35};
  36
  37/**
  38 * change_mac - change(add or delete) mac address
  39 * @nic_dev: nic device
  40 * @addr: mac address
  41 * @vlan_id: vlan number to set with the mac
  42 * @op: add or delete the mac
  43 *
  44 * Return 0 - Success, negative - Failure
  45 **/
  46static int change_mac(struct hinic_dev *nic_dev, const u8 *addr,
  47                      u16 vlan_id, enum mac_op op)
  48{
  49        struct net_device *netdev = nic_dev->netdev;
  50        struct hinic_hwdev *hwdev = nic_dev->hwdev;
  51        struct hinic_port_mac_cmd port_mac_cmd;
  52        struct hinic_hwif *hwif = hwdev->hwif;
  53        struct pci_dev *pdev = hwif->pdev;
  54        enum hinic_port_cmd cmd;
  55        u16 out_size;
  56        int err;
  57
  58        if (vlan_id >= VLAN_N_VID) {
  59                netif_err(nic_dev, drv, netdev, "Invalid VLAN number\n");
  60                return -EINVAL;
  61        }
  62
  63        if (op == MAC_SET)
  64                cmd = HINIC_PORT_CMD_SET_MAC;
  65        else
  66                cmd = HINIC_PORT_CMD_DEL_MAC;
  67
  68        port_mac_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
  69        port_mac_cmd.vlan_id = vlan_id;
  70        memcpy(port_mac_cmd.mac, addr, ETH_ALEN);
  71
  72        err = hinic_port_msg_cmd(hwdev, cmd, &port_mac_cmd,
  73                                 sizeof(port_mac_cmd),
  74                                 &port_mac_cmd, &out_size);
  75        if (err || (out_size != sizeof(port_mac_cmd)) || port_mac_cmd.status) {
  76                dev_err(&pdev->dev, "Failed to change MAC, ret = %d\n",
  77                        port_mac_cmd.status);
  78                return -EFAULT;
  79        }
  80
  81        return 0;
  82}
  83
  84/**
  85 * hinic_port_add_mac - add mac address
  86 * @nic_dev: nic device
  87 * @addr: mac address
  88 * @vlan_id: vlan number to set with the mac
  89 *
  90 * Return 0 - Success, negative - Failure
  91 **/
  92int hinic_port_add_mac(struct hinic_dev *nic_dev,
  93                       const u8 *addr, u16 vlan_id)
  94{
  95        return change_mac(nic_dev, addr, vlan_id, MAC_SET);
  96}
  97
  98/**
  99 * hinic_port_del_mac - remove mac address
 100 * @nic_dev: nic device
 101 * @addr: mac address
 102 * @vlan_id: vlan number that is connected to the mac
 103 *
 104 * Return 0 - Success, negative - Failure
 105 **/
 106int hinic_port_del_mac(struct hinic_dev *nic_dev, const u8 *addr,
 107                       u16 vlan_id)
 108{
 109        return change_mac(nic_dev, addr, vlan_id, MAC_DEL);
 110}
 111
 112/**
 113 * hinic_port_get_mac - get the mac address of the nic device
 114 * @nic_dev: nic device
 115 * @addr: returned mac address
 116 *
 117 * Return 0 - Success, negative - Failure
 118 **/
 119int hinic_port_get_mac(struct hinic_dev *nic_dev, u8 *addr)
 120{
 121        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 122        struct hinic_port_mac_cmd port_mac_cmd;
 123        struct hinic_hwif *hwif = hwdev->hwif;
 124        struct pci_dev *pdev = hwif->pdev;
 125        u16 out_size;
 126        int err;
 127
 128        port_mac_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
 129
 130        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_MAC,
 131                                 &port_mac_cmd, sizeof(port_mac_cmd),
 132                                 &port_mac_cmd, &out_size);
 133        if (err || (out_size != sizeof(port_mac_cmd)) || port_mac_cmd.status) {
 134                dev_err(&pdev->dev, "Failed to get mac, ret = %d\n",
 135                        port_mac_cmd.status);
 136                return -EFAULT;
 137        }
 138
 139        memcpy(addr, port_mac_cmd.mac, ETH_ALEN);
 140        return 0;
 141}
 142
 143/**
 144 * hinic_port_set_mtu - set mtu
 145 * @nic_dev: nic device
 146 * @new_mtu: new mtu
 147 *
 148 * Return 0 - Success, negative - Failure
 149 **/
 150int hinic_port_set_mtu(struct hinic_dev *nic_dev, int new_mtu)
 151{
 152        struct net_device *netdev = nic_dev->netdev;
 153        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 154        struct hinic_port_mtu_cmd port_mtu_cmd;
 155        struct hinic_hwif *hwif = hwdev->hwif;
 156        struct pci_dev *pdev = hwif->pdev;
 157        int err, max_frame;
 158        u16 out_size;
 159
 160        if (new_mtu < HINIC_MIN_MTU_SIZE) {
 161                netif_err(nic_dev, drv, netdev, "mtu < MIN MTU size");
 162                return -EINVAL;
 163        }
 164
 165        max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
 166        if (max_frame > HINIC_MAX_JUMBO_FRAME_SIZE) {
 167                netif_err(nic_dev, drv, netdev, "mtu > MAX MTU size");
 168                return -EINVAL;
 169        }
 170
 171        port_mtu_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
 172        port_mtu_cmd.mtu = new_mtu;
 173
 174        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_CHANGE_MTU,
 175                                 &port_mtu_cmd, sizeof(port_mtu_cmd),
 176                                 &port_mtu_cmd, &out_size);
 177        if (err || (out_size != sizeof(port_mtu_cmd)) || port_mtu_cmd.status) {
 178                dev_err(&pdev->dev, "Failed to set mtu, ret = %d\n",
 179                        port_mtu_cmd.status);
 180                return -EFAULT;
 181        }
 182
 183        return 0;
 184}
 185
 186/**
 187 * hinic_port_add_vlan - add vlan to the nic device
 188 * @nic_dev: nic device
 189 * @vlan_id: the vlan number to add
 190 *
 191 * Return 0 - Success, negative - Failure
 192 **/
 193int hinic_port_add_vlan(struct hinic_dev *nic_dev, u16 vlan_id)
 194{
 195        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 196        struct hinic_port_vlan_cmd port_vlan_cmd;
 197
 198        port_vlan_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwdev->hwif);
 199        port_vlan_cmd.vlan_id = vlan_id;
 200
 201        return hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_ADD_VLAN,
 202                                  &port_vlan_cmd, sizeof(port_vlan_cmd),
 203                                  NULL, NULL);
 204}
 205
 206/**
 207 * hinic_port_del_vlan - delete vlan from the nic device
 208 * @nic_dev: nic device
 209 * @vlan_id: the vlan number to delete
 210 *
 211 * Return 0 - Success, negative - Failure
 212 **/
 213int hinic_port_del_vlan(struct hinic_dev *nic_dev, u16 vlan_id)
 214{
 215        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 216        struct hinic_port_vlan_cmd port_vlan_cmd;
 217
 218        port_vlan_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwdev->hwif);
 219        port_vlan_cmd.vlan_id = vlan_id;
 220
 221        return hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_DEL_VLAN,
 222                                 &port_vlan_cmd, sizeof(port_vlan_cmd),
 223                                 NULL, NULL);
 224}
 225
 226/**
 227 * hinic_port_set_rx_mode - set rx mode in the nic device
 228 * @nic_dev: nic device
 229 * @rx_mode: the rx mode to set
 230 *
 231 * Return 0 - Success, negative - Failure
 232 **/
 233int hinic_port_set_rx_mode(struct hinic_dev *nic_dev, u32 rx_mode)
 234{
 235        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 236        struct hinic_port_rx_mode_cmd rx_mode_cmd;
 237
 238        rx_mode_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwdev->hwif);
 239        rx_mode_cmd.rx_mode = rx_mode;
 240
 241        return hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RX_MODE,
 242                                  &rx_mode_cmd, sizeof(rx_mode_cmd),
 243                                  NULL, NULL);
 244}
 245
 246/**
 247 * hinic_port_link_state - get the link state
 248 * @nic_dev: nic device
 249 * @link_state: the returned link state
 250 *
 251 * Return 0 - Success, negative - Failure
 252 **/
 253int hinic_port_link_state(struct hinic_dev *nic_dev,
 254                          enum hinic_port_link_state *link_state)
 255{
 256        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 257        struct hinic_hwif *hwif = hwdev->hwif;
 258        struct hinic_port_link_cmd link_cmd;
 259        struct pci_dev *pdev = hwif->pdev;
 260        u16 out_size;
 261        int err;
 262
 263        if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
 264                dev_err(&pdev->dev, "unsupported PCI Function type\n");
 265                return -EINVAL;
 266        }
 267
 268        link_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
 269
 270        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_LINK_STATE,
 271                                 &link_cmd, sizeof(link_cmd),
 272                                 &link_cmd, &out_size);
 273        if (err || (out_size != sizeof(link_cmd)) || link_cmd.status) {
 274                dev_err(&pdev->dev, "Failed to get link state, ret = %d\n",
 275                        link_cmd.status);
 276                return -EINVAL;
 277        }
 278
 279        *link_state = link_cmd.state;
 280        return 0;
 281}
 282
 283/**
 284 * hinic_port_set_state - set port state
 285 * @nic_dev: nic device
 286 * @state: the state to set
 287 *
 288 * Return 0 - Success, negative - Failure
 289 **/
 290int hinic_port_set_state(struct hinic_dev *nic_dev, enum hinic_port_state state)
 291{
 292        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 293        struct hinic_port_state_cmd port_state;
 294        struct hinic_hwif *hwif = hwdev->hwif;
 295        struct pci_dev *pdev = hwif->pdev;
 296        u16 out_size;
 297        int err;
 298
 299        if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
 300                dev_err(&pdev->dev, "unsupported PCI Function type\n");
 301                return -EINVAL;
 302        }
 303
 304        port_state.state = state;
 305
 306        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_PORT_STATE,
 307                                 &port_state, sizeof(port_state),
 308                                 &port_state, &out_size);
 309        if (err || (out_size != sizeof(port_state)) || port_state.status) {
 310                dev_err(&pdev->dev, "Failed to set port state, ret = %d\n",
 311                        port_state.status);
 312                return -EFAULT;
 313        }
 314
 315        return 0;
 316}
 317
 318/**
 319 * hinic_port_set_func_state- set func device state
 320 * @nic_dev: nic device
 321 * @state: the state to set
 322 *
 323 * Return 0 - Success, negative - Failure
 324 **/
 325int hinic_port_set_func_state(struct hinic_dev *nic_dev,
 326                              enum hinic_func_port_state state)
 327{
 328        struct hinic_port_func_state_cmd func_state;
 329        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 330        struct hinic_hwif *hwif = hwdev->hwif;
 331        struct pci_dev *pdev = hwif->pdev;
 332        u16 out_size;
 333        int err;
 334
 335        func_state.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
 336        func_state.state = state;
 337
 338        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_FUNC_STATE,
 339                                 &func_state, sizeof(func_state),
 340                                 &func_state, &out_size);
 341        if (err || (out_size != sizeof(func_state)) || func_state.status) {
 342                dev_err(&pdev->dev, "Failed to set port func state, ret = %d\n",
 343                        func_state.status);
 344                return -EFAULT;
 345        }
 346
 347        return 0;
 348}
 349
 350/**
 351 * hinic_port_get_cap - get port capabilities
 352 * @nic_dev: nic device
 353 * @port_cap: returned port capabilities
 354 *
 355 * Return 0 - Success, negative - Failure
 356 **/
 357int hinic_port_get_cap(struct hinic_dev *nic_dev,
 358                       struct hinic_port_cap *port_cap)
 359{
 360        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 361        struct hinic_hwif *hwif = hwdev->hwif;
 362        struct pci_dev *pdev = hwif->pdev;
 363        u16 out_size;
 364        int err;
 365
 366        port_cap->func_idx = HINIC_HWIF_FUNC_IDX(hwif);
 367
 368        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_CAP,
 369                                 port_cap, sizeof(*port_cap),
 370                                 port_cap, &out_size);
 371        if (err || (out_size != sizeof(*port_cap)) || port_cap->status) {
 372                dev_err(&pdev->dev,
 373                        "Failed to get port capabilities, ret = %d\n",
 374                        port_cap->status);
 375                return -EINVAL;
 376        }
 377
 378        return 0;
 379}
 380
 381/**
 382 * hinic_port_set_tso - set port tso configuration
 383 * @nic_dev: nic device
 384 * @state: the tso state to set
 385 *
 386 * Return 0 - Success, negative - Failure
 387 **/
 388int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state)
 389{
 390        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 391        struct hinic_hwif *hwif = hwdev->hwif;
 392        struct hinic_tso_config tso_cfg = {0};
 393        struct pci_dev *pdev = hwif->pdev;
 394        u16 out_size;
 395        int err;
 396
 397        tso_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
 398        tso_cfg.tso_en = state;
 399
 400        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_TSO,
 401                                 &tso_cfg, sizeof(tso_cfg),
 402                                 &tso_cfg, &out_size);
 403        if (err || out_size != sizeof(tso_cfg) || tso_cfg.status) {
 404                dev_err(&pdev->dev,
 405                        "Failed to set port tso, ret = %d\n",
 406                        tso_cfg.status);
 407                return -EINVAL;
 408        }
 409
 410        return 0;
 411}
 412
 413int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en)
 414{
 415        struct hinic_checksum_offload rx_csum_cfg = {0};
 416        struct hinic_hwdev *hwdev = nic_dev->hwdev;
 417        struct hinic_hwif *hwif;
 418        struct pci_dev *pdev;
 419        u16 out_size;
 420        int err;
 421
 422        if (!hwdev)
 423                return -EINVAL;
 424
 425        hwif = hwdev->hwif;
 426        pdev = hwif->pdev;
 427        rx_csum_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
 428        rx_csum_cfg.rx_csum_offload = en;
 429
 430        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RX_CSUM,
 431                                 &rx_csum_cfg, sizeof(rx_csum_cfg),
 432                                 &rx_csum_cfg, &out_size);
 433        if (err || !out_size || rx_csum_cfg.status) {
 434                dev_err(&pdev->dev,
 435                        "Failed to set rx csum offload, ret = %d\n",
 436                        rx_csum_cfg.status);
 437                return -EINVAL;
 438        }
 439
 440        return 0;
 441}
 442