3197 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * drivers/net/ethernet/rocker/rocker.c - Rocker switch device driver4 * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>5 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>6 */7 8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/pci.h>11#include <linux/interrupt.h>12#include <linux/sched.h>13#include <linux/wait.h>14#include <linux/spinlock.h>15#include <linux/sort.h>16#include <linux/random.h>17#include <linux/netdevice.h>18#include <linux/skbuff.h>19#include <linux/socket.h>20#include <linux/etherdevice.h>21#include <linux/ethtool.h>22#include <linux/if_ether.h>23#include <linux/if_vlan.h>24#include <linux/if_bridge.h>25#include <linux/bitops.h>26#include <linux/ctype.h>27#include <linux/workqueue.h>28#include <net/switchdev.h>29#include <net/rtnetlink.h>30#include <net/netevent.h>31#include <net/arp.h>32#include <net/fib_rules.h>33#include <net/fib_notifier.h>34#include <linux/io-64-nonatomic-lo-hi.h>35 36#include "rocker_hw.h"37#include "rocker.h"38#include "rocker_tlv.h"39 40static const char rocker_driver_name[] = "rocker";41 42static const struct pci_device_id rocker_pci_id_table[] = {43 {PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_ROCKER), 0},44 {0, }45};46 47struct rocker_wait {48 wait_queue_head_t wait;49 bool done;50 bool nowait;51};52 53static void rocker_wait_reset(struct rocker_wait *wait)54{55 wait->done = false;56 wait->nowait = false;57}58 59static void rocker_wait_init(struct rocker_wait *wait)60{61 init_waitqueue_head(&wait->wait);62 rocker_wait_reset(wait);63}64 65static struct rocker_wait *rocker_wait_create(void)66{67 struct rocker_wait *wait;68 69 wait = kzalloc(sizeof(*wait), GFP_KERNEL);70 if (!wait)71 return NULL;72 return wait;73}74 75static void rocker_wait_destroy(struct rocker_wait *wait)76{77 kfree(wait);78}79 80static bool rocker_wait_event_timeout(struct rocker_wait *wait,81 unsigned long timeout)82{83 wait_event_timeout(wait->wait, wait->done, HZ / 10);84 if (!wait->done)85 return false;86 return true;87}88 89static void rocker_wait_wake_up(struct rocker_wait *wait)90{91 wait->done = true;92 wake_up(&wait->wait);93}94 95static u32 rocker_msix_vector(const struct rocker *rocker, unsigned int vector)96{97 return rocker->msix_entries[vector].vector;98}99 100static u32 rocker_msix_tx_vector(const struct rocker_port *rocker_port)101{102 return rocker_msix_vector(rocker_port->rocker,103 ROCKER_MSIX_VEC_TX(rocker_port->port_number));104}105 106static u32 rocker_msix_rx_vector(const struct rocker_port *rocker_port)107{108 return rocker_msix_vector(rocker_port->rocker,109 ROCKER_MSIX_VEC_RX(rocker_port->port_number));110}111 112#define rocker_write32(rocker, reg, val) \113 writel((val), (rocker)->hw_addr + (ROCKER_ ## reg))114#define rocker_read32(rocker, reg) \115 readl((rocker)->hw_addr + (ROCKER_ ## reg))116#define rocker_write64(rocker, reg, val) \117 writeq((val), (rocker)->hw_addr + (ROCKER_ ## reg))118#define rocker_read64(rocker, reg) \119 readq((rocker)->hw_addr + (ROCKER_ ## reg))120 121/*****************************122 * HW basic testing functions123 *****************************/124 125static int rocker_reg_test(const struct rocker *rocker)126{127 const struct pci_dev *pdev = rocker->pdev;128 u64 test_reg;129 u64 rnd;130 131 rnd = get_random_u32();132 rnd >>= 1;133 rocker_write32(rocker, TEST_REG, rnd);134 test_reg = rocker_read32(rocker, TEST_REG);135 if (test_reg != rnd * 2) {136 dev_err(&pdev->dev, "unexpected 32bit register value %08llx, expected %08llx\n",137 test_reg, rnd * 2);138 return -EIO;139 }140 141 rnd = get_random_u32();142 rnd <<= 31;143 rnd |= get_random_u32();144 rocker_write64(rocker, TEST_REG64, rnd);145 test_reg = rocker_read64(rocker, TEST_REG64);146 if (test_reg != rnd * 2) {147 dev_err(&pdev->dev, "unexpected 64bit register value %16llx, expected %16llx\n",148 test_reg, rnd * 2);149 return -EIO;150 }151 152 return 0;153}154 155static int rocker_dma_test_one(const struct rocker *rocker,156 struct rocker_wait *wait, u32 test_type,157 dma_addr_t dma_handle, const unsigned char *buf,158 const unsigned char *expect, size_t size)159{160 const struct pci_dev *pdev = rocker->pdev;161 int i;162 163 rocker_wait_reset(wait);164 rocker_write32(rocker, TEST_DMA_CTRL, test_type);165 166 if (!rocker_wait_event_timeout(wait, HZ / 10)) {167 dev_err(&pdev->dev, "no interrupt received within a timeout\n");168 return -EIO;169 }170 171 for (i = 0; i < size; i++) {172 if (buf[i] != expect[i]) {173 dev_err(&pdev->dev, "unexpected memory content %02x at byte %x\n, %02x expected",174 buf[i], i, expect[i]);175 return -EIO;176 }177 }178 return 0;179}180 181#define ROCKER_TEST_DMA_BUF_SIZE (PAGE_SIZE * 4)182#define ROCKER_TEST_DMA_FILL_PATTERN 0x96183 184static int rocker_dma_test_offset(const struct rocker *rocker,185 struct rocker_wait *wait, int offset)186{187 struct pci_dev *pdev = rocker->pdev;188 unsigned char *alloc;189 unsigned char *buf;190 unsigned char *expect;191 dma_addr_t dma_handle;192 int i;193 int err;194 195 alloc = kzalloc(ROCKER_TEST_DMA_BUF_SIZE * 2 + offset,196 GFP_KERNEL | GFP_DMA);197 if (!alloc)198 return -ENOMEM;199 buf = alloc + offset;200 expect = buf + ROCKER_TEST_DMA_BUF_SIZE;201 202 dma_handle = dma_map_single(&pdev->dev, buf, ROCKER_TEST_DMA_BUF_SIZE,203 DMA_BIDIRECTIONAL);204 if (dma_mapping_error(&pdev->dev, dma_handle)) {205 err = -EIO;206 goto free_alloc;207 }208 209 rocker_write64(rocker, TEST_DMA_ADDR, dma_handle);210 rocker_write32(rocker, TEST_DMA_SIZE, ROCKER_TEST_DMA_BUF_SIZE);211 212 memset(expect, ROCKER_TEST_DMA_FILL_PATTERN, ROCKER_TEST_DMA_BUF_SIZE);213 err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_FILL,214 dma_handle, buf, expect,215 ROCKER_TEST_DMA_BUF_SIZE);216 if (err)217 goto unmap;218 219 memset(expect, 0, ROCKER_TEST_DMA_BUF_SIZE);220 err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_CLEAR,221 dma_handle, buf, expect,222 ROCKER_TEST_DMA_BUF_SIZE);223 if (err)224 goto unmap;225 226 get_random_bytes(buf, ROCKER_TEST_DMA_BUF_SIZE);227 for (i = 0; i < ROCKER_TEST_DMA_BUF_SIZE; i++)228 expect[i] = ~buf[i];229 err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_INVERT,230 dma_handle, buf, expect,231 ROCKER_TEST_DMA_BUF_SIZE);232 if (err)233 goto unmap;234 235unmap:236 dma_unmap_single(&pdev->dev, dma_handle, ROCKER_TEST_DMA_BUF_SIZE,237 DMA_BIDIRECTIONAL);238free_alloc:239 kfree(alloc);240 241 return err;242}243 244static int rocker_dma_test(const struct rocker *rocker,245 struct rocker_wait *wait)246{247 int i;248 int err;249 250 for (i = 0; i < 8; i++) {251 err = rocker_dma_test_offset(rocker, wait, i);252 if (err)253 return err;254 }255 return 0;256}257 258static irqreturn_t rocker_test_irq_handler(int irq, void *dev_id)259{260 struct rocker_wait *wait = dev_id;261 262 rocker_wait_wake_up(wait);263 264 return IRQ_HANDLED;265}266 267static int rocker_basic_hw_test(const struct rocker *rocker)268{269 const struct pci_dev *pdev = rocker->pdev;270 struct rocker_wait wait;271 int err;272 273 err = rocker_reg_test(rocker);274 if (err) {275 dev_err(&pdev->dev, "reg test failed\n");276 return err;277 }278 279 err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_TEST),280 rocker_test_irq_handler, 0,281 rocker_driver_name, &wait);282 if (err) {283 dev_err(&pdev->dev, "cannot assign test irq\n");284 return err;285 }286 287 rocker_wait_init(&wait);288 rocker_write32(rocker, TEST_IRQ, ROCKER_MSIX_VEC_TEST);289 290 if (!rocker_wait_event_timeout(&wait, HZ / 10)) {291 dev_err(&pdev->dev, "no interrupt received within a timeout\n");292 err = -EIO;293 goto free_irq;294 }295 296 err = rocker_dma_test(rocker, &wait);297 if (err)298 dev_err(&pdev->dev, "dma test failed\n");299 300free_irq:301 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_TEST), &wait);302 return err;303}304 305/******************************************306 * DMA rings and descriptors manipulations307 ******************************************/308 309static u32 __pos_inc(u32 pos, size_t limit)310{311 return ++pos == limit ? 0 : pos;312}313 314static int rocker_desc_err(const struct rocker_desc_info *desc_info)315{316 int err = desc_info->desc->comp_err & ~ROCKER_DMA_DESC_COMP_ERR_GEN;317 318 switch (err) {319 case ROCKER_OK:320 return 0;321 case -ROCKER_ENOENT:322 return -ENOENT;323 case -ROCKER_ENXIO:324 return -ENXIO;325 case -ROCKER_ENOMEM:326 return -ENOMEM;327 case -ROCKER_EEXIST:328 return -EEXIST;329 case -ROCKER_EINVAL:330 return -EINVAL;331 case -ROCKER_EMSGSIZE:332 return -EMSGSIZE;333 case -ROCKER_ENOTSUP:334 return -EOPNOTSUPP;335 case -ROCKER_ENOBUFS:336 return -ENOBUFS;337 }338 339 return -EINVAL;340}341 342static void rocker_desc_gen_clear(const struct rocker_desc_info *desc_info)343{344 desc_info->desc->comp_err &= ~ROCKER_DMA_DESC_COMP_ERR_GEN;345}346 347static bool rocker_desc_gen(const struct rocker_desc_info *desc_info)348{349 u32 comp_err = desc_info->desc->comp_err;350 351 return comp_err & ROCKER_DMA_DESC_COMP_ERR_GEN ? true : false;352}353 354static void *355rocker_desc_cookie_ptr_get(const struct rocker_desc_info *desc_info)356{357 return (void *)(uintptr_t)desc_info->desc->cookie;358}359 360static void rocker_desc_cookie_ptr_set(const struct rocker_desc_info *desc_info,361 void *ptr)362{363 desc_info->desc->cookie = (uintptr_t) ptr;364}365 366static struct rocker_desc_info *367rocker_desc_head_get(const struct rocker_dma_ring_info *info)368{369 struct rocker_desc_info *desc_info;370 u32 head = __pos_inc(info->head, info->size);371 372 desc_info = &info->desc_info[info->head];373 if (head == info->tail)374 return NULL; /* ring full */375 desc_info->tlv_size = 0;376 return desc_info;377}378 379static void rocker_desc_commit(const struct rocker_desc_info *desc_info)380{381 desc_info->desc->buf_size = desc_info->data_size;382 desc_info->desc->tlv_size = desc_info->tlv_size;383}384 385static void rocker_desc_head_set(const struct rocker *rocker,386 struct rocker_dma_ring_info *info,387 const struct rocker_desc_info *desc_info)388{389 u32 head = __pos_inc(info->head, info->size);390 391 BUG_ON(head == info->tail);392 rocker_desc_commit(desc_info);393 info->head = head;394 rocker_write32(rocker, DMA_DESC_HEAD(info->type), head);395}396 397static struct rocker_desc_info *398rocker_desc_tail_get(struct rocker_dma_ring_info *info)399{400 struct rocker_desc_info *desc_info;401 402 if (info->tail == info->head)403 return NULL; /* nothing to be done between head and tail */404 desc_info = &info->desc_info[info->tail];405 if (!rocker_desc_gen(desc_info))406 return NULL; /* gen bit not set, desc is not ready yet */407 info->tail = __pos_inc(info->tail, info->size);408 desc_info->tlv_size = desc_info->desc->tlv_size;409 return desc_info;410}411 412static void rocker_dma_ring_credits_set(const struct rocker *rocker,413 const struct rocker_dma_ring_info *info,414 u32 credits)415{416 if (credits)417 rocker_write32(rocker, DMA_DESC_CREDITS(info->type), credits);418}419 420static unsigned long rocker_dma_ring_size_fix(size_t size)421{422 return max(ROCKER_DMA_SIZE_MIN,423 min(roundup_pow_of_two(size), ROCKER_DMA_SIZE_MAX));424}425 426static int rocker_dma_ring_create(const struct rocker *rocker,427 unsigned int type,428 size_t size,429 struct rocker_dma_ring_info *info)430{431 int i;432 433 BUG_ON(size != rocker_dma_ring_size_fix(size));434 info->size = size;435 info->type = type;436 info->head = 0;437 info->tail = 0;438 info->desc_info = kcalloc(info->size, sizeof(*info->desc_info),439 GFP_KERNEL);440 if (!info->desc_info)441 return -ENOMEM;442 443 info->desc = dma_alloc_coherent(&rocker->pdev->dev,444 info->size * sizeof(*info->desc),445 &info->mapaddr, GFP_KERNEL);446 if (!info->desc) {447 kfree(info->desc_info);448 return -ENOMEM;449 }450 451 for (i = 0; i < info->size; i++)452 info->desc_info[i].desc = &info->desc[i];453 454 rocker_write32(rocker, DMA_DESC_CTRL(info->type),455 ROCKER_DMA_DESC_CTRL_RESET);456 rocker_write64(rocker, DMA_DESC_ADDR(info->type), info->mapaddr);457 rocker_write32(rocker, DMA_DESC_SIZE(info->type), info->size);458 459 return 0;460}461 462static void rocker_dma_ring_destroy(const struct rocker *rocker,463 const struct rocker_dma_ring_info *info)464{465 rocker_write64(rocker, DMA_DESC_ADDR(info->type), 0);466 467 dma_free_coherent(&rocker->pdev->dev,468 info->size * sizeof(struct rocker_desc), info->desc,469 info->mapaddr);470 kfree(info->desc_info);471}472 473static void rocker_dma_ring_pass_to_producer(const struct rocker *rocker,474 struct rocker_dma_ring_info *info)475{476 int i;477 478 BUG_ON(info->head || info->tail);479 480 /* When ring is consumer, we need to advance head for each desc.481 * That tells hw that the desc is ready to be used by it.482 */483 for (i = 0; i < info->size - 1; i++)484 rocker_desc_head_set(rocker, info, &info->desc_info[i]);485 rocker_desc_commit(&info->desc_info[i]);486}487 488static int rocker_dma_ring_bufs_alloc(const struct rocker *rocker,489 const struct rocker_dma_ring_info *info,490 int direction, size_t buf_size)491{492 struct pci_dev *pdev = rocker->pdev;493 int i;494 int err;495 496 for (i = 0; i < info->size; i++) {497 struct rocker_desc_info *desc_info = &info->desc_info[i];498 struct rocker_desc *desc = &info->desc[i];499 dma_addr_t dma_handle;500 char *buf;501 502 buf = kzalloc(buf_size, GFP_KERNEL | GFP_DMA);503 if (!buf) {504 err = -ENOMEM;505 goto rollback;506 }507 508 dma_handle = dma_map_single(&pdev->dev, buf, buf_size,509 direction);510 if (dma_mapping_error(&pdev->dev, dma_handle)) {511 kfree(buf);512 err = -EIO;513 goto rollback;514 }515 516 desc_info->data = buf;517 desc_info->data_size = buf_size;518 dma_unmap_addr_set(desc_info, mapaddr, dma_handle);519 520 desc->buf_addr = dma_handle;521 desc->buf_size = buf_size;522 }523 return 0;524 525rollback:526 for (i--; i >= 0; i--) {527 const struct rocker_desc_info *desc_info = &info->desc_info[i];528 529 dma_unmap_single(&pdev->dev,530 dma_unmap_addr(desc_info, mapaddr),531 desc_info->data_size, direction);532 kfree(desc_info->data);533 }534 return err;535}536 537static void rocker_dma_ring_bufs_free(const struct rocker *rocker,538 const struct rocker_dma_ring_info *info,539 int direction)540{541 struct pci_dev *pdev = rocker->pdev;542 int i;543 544 for (i = 0; i < info->size; i++) {545 const struct rocker_desc_info *desc_info = &info->desc_info[i];546 struct rocker_desc *desc = &info->desc[i];547 548 desc->buf_addr = 0;549 desc->buf_size = 0;550 dma_unmap_single(&pdev->dev,551 dma_unmap_addr(desc_info, mapaddr),552 desc_info->data_size, direction);553 kfree(desc_info->data);554 }555}556 557static int rocker_dma_cmd_ring_wait_alloc(struct rocker_desc_info *desc_info)558{559 struct rocker_wait *wait;560 561 wait = rocker_wait_create();562 if (!wait)563 return -ENOMEM;564 rocker_desc_cookie_ptr_set(desc_info, wait);565 return 0;566}567 568static void569rocker_dma_cmd_ring_wait_free(const struct rocker_desc_info *desc_info)570{571 struct rocker_wait *wait = rocker_desc_cookie_ptr_get(desc_info);572 573 rocker_wait_destroy(wait);574}575 576static int rocker_dma_cmd_ring_waits_alloc(const struct rocker *rocker)577{578 const struct rocker_dma_ring_info *cmd_ring = &rocker->cmd_ring;579 int i;580 int err;581 582 for (i = 0; i < cmd_ring->size; i++) {583 err = rocker_dma_cmd_ring_wait_alloc(&cmd_ring->desc_info[i]);584 if (err)585 goto rollback;586 }587 return 0;588 589rollback:590 for (i--; i >= 0; i--)591 rocker_dma_cmd_ring_wait_free(&cmd_ring->desc_info[i]);592 return err;593}594 595static void rocker_dma_cmd_ring_waits_free(const struct rocker *rocker)596{597 const struct rocker_dma_ring_info *cmd_ring = &rocker->cmd_ring;598 int i;599 600 for (i = 0; i < cmd_ring->size; i++)601 rocker_dma_cmd_ring_wait_free(&cmd_ring->desc_info[i]);602}603 604static int rocker_dma_rings_init(struct rocker *rocker)605{606 const struct pci_dev *pdev = rocker->pdev;607 int err;608 609 err = rocker_dma_ring_create(rocker, ROCKER_DMA_CMD,610 ROCKER_DMA_CMD_DEFAULT_SIZE,611 &rocker->cmd_ring);612 if (err) {613 dev_err(&pdev->dev, "failed to create command dma ring\n");614 return err;615 }616 617 spin_lock_init(&rocker->cmd_ring_lock);618 619 err = rocker_dma_ring_bufs_alloc(rocker, &rocker->cmd_ring,620 DMA_BIDIRECTIONAL, PAGE_SIZE);621 if (err) {622 dev_err(&pdev->dev, "failed to alloc command dma ring buffers\n");623 goto err_dma_cmd_ring_bufs_alloc;624 }625 626 err = rocker_dma_cmd_ring_waits_alloc(rocker);627 if (err) {628 dev_err(&pdev->dev, "failed to alloc command dma ring waits\n");629 goto err_dma_cmd_ring_waits_alloc;630 }631 632 err = rocker_dma_ring_create(rocker, ROCKER_DMA_EVENT,633 ROCKER_DMA_EVENT_DEFAULT_SIZE,634 &rocker->event_ring);635 if (err) {636 dev_err(&pdev->dev, "failed to create event dma ring\n");637 goto err_dma_event_ring_create;638 }639 640 err = rocker_dma_ring_bufs_alloc(rocker, &rocker->event_ring,641 DMA_FROM_DEVICE, PAGE_SIZE);642 if (err) {643 dev_err(&pdev->dev, "failed to alloc event dma ring buffers\n");644 goto err_dma_event_ring_bufs_alloc;645 }646 rocker_dma_ring_pass_to_producer(rocker, &rocker->event_ring);647 return 0;648 649err_dma_event_ring_bufs_alloc:650 rocker_dma_ring_destroy(rocker, &rocker->event_ring);651err_dma_event_ring_create:652 rocker_dma_cmd_ring_waits_free(rocker);653err_dma_cmd_ring_waits_alloc:654 rocker_dma_ring_bufs_free(rocker, &rocker->cmd_ring,655 DMA_BIDIRECTIONAL);656err_dma_cmd_ring_bufs_alloc:657 rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);658 return err;659}660 661static void rocker_dma_rings_fini(struct rocker *rocker)662{663 rocker_dma_ring_bufs_free(rocker, &rocker->event_ring,664 DMA_BIDIRECTIONAL);665 rocker_dma_ring_destroy(rocker, &rocker->event_ring);666 rocker_dma_cmd_ring_waits_free(rocker);667 rocker_dma_ring_bufs_free(rocker, &rocker->cmd_ring,668 DMA_BIDIRECTIONAL);669 rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);670}671 672static int rocker_dma_rx_ring_skb_map(const struct rocker_port *rocker_port,673 struct rocker_desc_info *desc_info,674 struct sk_buff *skb, size_t buf_len)675{676 const struct rocker *rocker = rocker_port->rocker;677 struct pci_dev *pdev = rocker->pdev;678 dma_addr_t dma_handle;679 680 dma_handle = dma_map_single(&pdev->dev, skb->data, buf_len,681 DMA_FROM_DEVICE);682 if (dma_mapping_error(&pdev->dev, dma_handle))683 return -EIO;684 if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_RX_FRAG_ADDR, dma_handle))685 goto tlv_put_failure;686 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_RX_FRAG_MAX_LEN, buf_len))687 goto tlv_put_failure;688 return 0;689 690tlv_put_failure:691 dma_unmap_single(&pdev->dev, dma_handle, buf_len, DMA_FROM_DEVICE);692 desc_info->tlv_size = 0;693 return -EMSGSIZE;694}695 696static size_t rocker_port_rx_buf_len(const struct rocker_port *rocker_port)697{698 return rocker_port->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;699}700 701static int rocker_dma_rx_ring_skb_alloc(const struct rocker_port *rocker_port,702 struct rocker_desc_info *desc_info)703{704 struct net_device *dev = rocker_port->dev;705 struct sk_buff *skb;706 size_t buf_len = rocker_port_rx_buf_len(rocker_port);707 int err;708 709 /* Ensure that hw will see tlv_size zero in case of an error.710 * That tells hw to use another descriptor.711 */712 rocker_desc_cookie_ptr_set(desc_info, NULL);713 desc_info->tlv_size = 0;714 715 skb = netdev_alloc_skb_ip_align(dev, buf_len);716 if (!skb)717 return -ENOMEM;718 err = rocker_dma_rx_ring_skb_map(rocker_port, desc_info, skb, buf_len);719 if (err) {720 dev_kfree_skb_any(skb);721 return err;722 }723 rocker_desc_cookie_ptr_set(desc_info, skb);724 return 0;725}726 727static void rocker_dma_rx_ring_skb_unmap(const struct rocker *rocker,728 const struct rocker_tlv **attrs)729{730 struct pci_dev *pdev = rocker->pdev;731 dma_addr_t dma_handle;732 size_t len;733 734 if (!attrs[ROCKER_TLV_RX_FRAG_ADDR] ||735 !attrs[ROCKER_TLV_RX_FRAG_MAX_LEN])736 return;737 dma_handle = rocker_tlv_get_u64(attrs[ROCKER_TLV_RX_FRAG_ADDR]);738 len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_MAX_LEN]);739 dma_unmap_single(&pdev->dev, dma_handle, len, DMA_FROM_DEVICE);740}741 742static void rocker_dma_rx_ring_skb_free(const struct rocker *rocker,743 const struct rocker_desc_info *desc_info)744{745 const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];746 struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);747 748 if (!skb)749 return;750 rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info);751 rocker_dma_rx_ring_skb_unmap(rocker, attrs);752 dev_kfree_skb_any(skb);753}754 755static int rocker_dma_rx_ring_skbs_alloc(const struct rocker_port *rocker_port)756{757 const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;758 const struct rocker *rocker = rocker_port->rocker;759 int i;760 int err;761 762 for (i = 0; i < rx_ring->size; i++) {763 err = rocker_dma_rx_ring_skb_alloc(rocker_port,764 &rx_ring->desc_info[i]);765 if (err)766 goto rollback;767 }768 return 0;769 770rollback:771 for (i--; i >= 0; i--)772 rocker_dma_rx_ring_skb_free(rocker, &rx_ring->desc_info[i]);773 return err;774}775 776static void rocker_dma_rx_ring_skbs_free(const struct rocker_port *rocker_port)777{778 const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;779 const struct rocker *rocker = rocker_port->rocker;780 int i;781 782 for (i = 0; i < rx_ring->size; i++)783 rocker_dma_rx_ring_skb_free(rocker, &rx_ring->desc_info[i]);784}785 786static int rocker_port_dma_rings_init(struct rocker_port *rocker_port)787{788 struct rocker *rocker = rocker_port->rocker;789 int err;790 791 err = rocker_dma_ring_create(rocker,792 ROCKER_DMA_TX(rocker_port->port_number),793 ROCKER_DMA_TX_DEFAULT_SIZE,794 &rocker_port->tx_ring);795 if (err) {796 netdev_err(rocker_port->dev, "failed to create tx dma ring\n");797 return err;798 }799 800 err = rocker_dma_ring_bufs_alloc(rocker, &rocker_port->tx_ring,801 DMA_TO_DEVICE,802 ROCKER_DMA_TX_DESC_SIZE);803 if (err) {804 netdev_err(rocker_port->dev, "failed to alloc tx dma ring buffers\n");805 goto err_dma_tx_ring_bufs_alloc;806 }807 808 err = rocker_dma_ring_create(rocker,809 ROCKER_DMA_RX(rocker_port->port_number),810 ROCKER_DMA_RX_DEFAULT_SIZE,811 &rocker_port->rx_ring);812 if (err) {813 netdev_err(rocker_port->dev, "failed to create rx dma ring\n");814 goto err_dma_rx_ring_create;815 }816 817 err = rocker_dma_ring_bufs_alloc(rocker, &rocker_port->rx_ring,818 DMA_BIDIRECTIONAL,819 ROCKER_DMA_RX_DESC_SIZE);820 if (err) {821 netdev_err(rocker_port->dev, "failed to alloc rx dma ring buffers\n");822 goto err_dma_rx_ring_bufs_alloc;823 }824 825 err = rocker_dma_rx_ring_skbs_alloc(rocker_port);826 if (err) {827 netdev_err(rocker_port->dev, "failed to alloc rx dma ring skbs\n");828 goto err_dma_rx_ring_skbs_alloc;829 }830 rocker_dma_ring_pass_to_producer(rocker, &rocker_port->rx_ring);831 832 return 0;833 834err_dma_rx_ring_skbs_alloc:835 rocker_dma_ring_bufs_free(rocker, &rocker_port->rx_ring,836 DMA_BIDIRECTIONAL);837err_dma_rx_ring_bufs_alloc:838 rocker_dma_ring_destroy(rocker, &rocker_port->rx_ring);839err_dma_rx_ring_create:840 rocker_dma_ring_bufs_free(rocker, &rocker_port->tx_ring,841 DMA_TO_DEVICE);842err_dma_tx_ring_bufs_alloc:843 rocker_dma_ring_destroy(rocker, &rocker_port->tx_ring);844 return err;845}846 847static void rocker_port_dma_rings_fini(struct rocker_port *rocker_port)848{849 struct rocker *rocker = rocker_port->rocker;850 851 rocker_dma_rx_ring_skbs_free(rocker_port);852 rocker_dma_ring_bufs_free(rocker, &rocker_port->rx_ring,853 DMA_BIDIRECTIONAL);854 rocker_dma_ring_destroy(rocker, &rocker_port->rx_ring);855 rocker_dma_ring_bufs_free(rocker, &rocker_port->tx_ring,856 DMA_TO_DEVICE);857 rocker_dma_ring_destroy(rocker, &rocker_port->tx_ring);858}859 860static void rocker_port_set_enable(const struct rocker_port *rocker_port,861 bool enable)862{863 u64 val = rocker_read64(rocker_port->rocker, PORT_PHYS_ENABLE);864 865 if (enable)866 val |= 1ULL << rocker_port->pport;867 else868 val &= ~(1ULL << rocker_port->pport);869 rocker_write64(rocker_port->rocker, PORT_PHYS_ENABLE, val);870}871 872/********************************873 * Interrupt handler and helpers874 ********************************/875 876static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)877{878 struct rocker *rocker = dev_id;879 const struct rocker_desc_info *desc_info;880 struct rocker_wait *wait;881 u32 credits = 0;882 883 spin_lock(&rocker->cmd_ring_lock);884 while ((desc_info = rocker_desc_tail_get(&rocker->cmd_ring))) {885 wait = rocker_desc_cookie_ptr_get(desc_info);886 if (wait->nowait) {887 rocker_desc_gen_clear(desc_info);888 } else {889 rocker_wait_wake_up(wait);890 }891 credits++;892 }893 spin_unlock(&rocker->cmd_ring_lock);894 rocker_dma_ring_credits_set(rocker, &rocker->cmd_ring, credits);895 896 return IRQ_HANDLED;897}898 899static void rocker_port_link_up(const struct rocker_port *rocker_port)900{901 netif_carrier_on(rocker_port->dev);902 netdev_info(rocker_port->dev, "Link is up\n");903}904 905static void rocker_port_link_down(const struct rocker_port *rocker_port)906{907 netif_carrier_off(rocker_port->dev);908 netdev_info(rocker_port->dev, "Link is down\n");909}910 911static int rocker_event_link_change(const struct rocker *rocker,912 const struct rocker_tlv *info)913{914 const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_LINK_CHANGED_MAX + 1];915 unsigned int port_number;916 bool link_up;917 struct rocker_port *rocker_port;918 919 rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_LINK_CHANGED_MAX, info);920 if (!attrs[ROCKER_TLV_EVENT_LINK_CHANGED_PPORT] ||921 !attrs[ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP])922 return -EIO;923 port_number =924 rocker_tlv_get_u32(attrs[ROCKER_TLV_EVENT_LINK_CHANGED_PPORT]) - 1;925 link_up = rocker_tlv_get_u8(attrs[ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP]);926 927 if (port_number >= rocker->port_count)928 return -EINVAL;929 930 rocker_port = rocker->ports[port_number];931 if (netif_carrier_ok(rocker_port->dev) != link_up) {932 if (link_up)933 rocker_port_link_up(rocker_port);934 else935 rocker_port_link_down(rocker_port);936 }937 938 return 0;939}940 941static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,942 const unsigned char *addr,943 __be16 vlan_id);944 945static int rocker_event_mac_vlan_seen(const struct rocker *rocker,946 const struct rocker_tlv *info)947{948 const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1];949 unsigned int port_number;950 struct rocker_port *rocker_port;951 const unsigned char *addr;952 __be16 vlan_id;953 954 rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);955 if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT] ||956 !attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC] ||957 !attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID])958 return -EIO;959 port_number =960 rocker_tlv_get_u32(attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT]) - 1;961 addr = rocker_tlv_data(attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC]);962 vlan_id = rocker_tlv_get_be16(attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID]);963 964 if (port_number >= rocker->port_count)965 return -EINVAL;966 967 rocker_port = rocker->ports[port_number];968 return rocker_world_port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);969}970 971static int rocker_event_process(const struct rocker *rocker,972 const struct rocker_desc_info *desc_info)973{974 const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAX + 1];975 const struct rocker_tlv *info;976 u16 type;977 978 rocker_tlv_parse_desc(attrs, ROCKER_TLV_EVENT_MAX, desc_info);979 if (!attrs[ROCKER_TLV_EVENT_TYPE] ||980 !attrs[ROCKER_TLV_EVENT_INFO])981 return -EIO;982 983 type = rocker_tlv_get_u16(attrs[ROCKER_TLV_EVENT_TYPE]);984 info = attrs[ROCKER_TLV_EVENT_INFO];985 986 switch (type) {987 case ROCKER_TLV_EVENT_TYPE_LINK_CHANGED:988 return rocker_event_link_change(rocker, info);989 case ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN:990 return rocker_event_mac_vlan_seen(rocker, info);991 }992 993 return -EOPNOTSUPP;994}995 996static irqreturn_t rocker_event_irq_handler(int irq, void *dev_id)997{998 struct rocker *rocker = dev_id;999 const struct pci_dev *pdev = rocker->pdev;1000 const struct rocker_desc_info *desc_info;1001 u32 credits = 0;1002 int err;1003 1004 while ((desc_info = rocker_desc_tail_get(&rocker->event_ring))) {1005 err = rocker_desc_err(desc_info);1006 if (err) {1007 dev_err(&pdev->dev, "event desc received with err %d\n",1008 err);1009 } else {1010 err = rocker_event_process(rocker, desc_info);1011 if (err)1012 dev_err(&pdev->dev, "event processing failed with err %d\n",1013 err);1014 }1015 rocker_desc_gen_clear(desc_info);1016 rocker_desc_head_set(rocker, &rocker->event_ring, desc_info);1017 credits++;1018 }1019 rocker_dma_ring_credits_set(rocker, &rocker->event_ring, credits);1020 1021 return IRQ_HANDLED;1022}1023 1024static irqreturn_t rocker_tx_irq_handler(int irq, void *dev_id)1025{1026 struct rocker_port *rocker_port = dev_id;1027 1028 napi_schedule(&rocker_port->napi_tx);1029 return IRQ_HANDLED;1030}1031 1032static irqreturn_t rocker_rx_irq_handler(int irq, void *dev_id)1033{1034 struct rocker_port *rocker_port = dev_id;1035 1036 napi_schedule(&rocker_port->napi_rx);1037 return IRQ_HANDLED;1038}1039 1040/********************1041 * Command interface1042 ********************/1043 1044int rocker_cmd_exec(struct rocker_port *rocker_port, bool nowait,1045 rocker_cmd_prep_cb_t prepare, void *prepare_priv,1046 rocker_cmd_proc_cb_t process, void *process_priv)1047{1048 struct rocker *rocker = rocker_port->rocker;1049 struct rocker_desc_info *desc_info;1050 struct rocker_wait *wait;1051 unsigned long lock_flags;1052 int err;1053 1054 spin_lock_irqsave(&rocker->cmd_ring_lock, lock_flags);1055 1056 desc_info = rocker_desc_head_get(&rocker->cmd_ring);1057 if (!desc_info) {1058 spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);1059 return -EAGAIN;1060 }1061 1062 wait = rocker_desc_cookie_ptr_get(desc_info);1063 rocker_wait_init(wait);1064 wait->nowait = nowait;1065 1066 err = prepare(rocker_port, desc_info, prepare_priv);1067 if (err) {1068 spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);1069 return err;1070 }1071 1072 rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);1073 1074 spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);1075 1076 if (nowait)1077 return 0;1078 1079 if (!rocker_wait_event_timeout(wait, HZ / 10))1080 return -EIO;1081 1082 err = rocker_desc_err(desc_info);1083 if (err)1084 return err;1085 1086 if (process)1087 err = process(rocker_port, desc_info, process_priv);1088 1089 rocker_desc_gen_clear(desc_info);1090 return err;1091}1092 1093static int1094rocker_cmd_get_port_settings_prep(const struct rocker_port *rocker_port,1095 struct rocker_desc_info *desc_info,1096 void *priv)1097{1098 struct rocker_tlv *cmd_info;1099 1100 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,1101 ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS))1102 return -EMSGSIZE;1103 cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);1104 if (!cmd_info)1105 return -EMSGSIZE;1106 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,1107 rocker_port->pport))1108 return -EMSGSIZE;1109 rocker_tlv_nest_end(desc_info, cmd_info);1110 return 0;1111}1112 1113static int1114rocker_cmd_get_port_settings_ethtool_proc(const struct rocker_port *rocker_port,1115 const struct rocker_desc_info *desc_info,1116 void *priv)1117{1118 struct ethtool_link_ksettings *ecmd = priv;1119 const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];1120 const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];1121 u32 speed;1122 u8 duplex;1123 u8 autoneg;1124 1125 rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);1126 if (!attrs[ROCKER_TLV_CMD_INFO])1127 return -EIO;1128 1129 rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,1130 attrs[ROCKER_TLV_CMD_INFO]);1131 if (!info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] ||1132 !info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] ||1133 !info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG])1134 return -EIO;1135 1136 speed = rocker_tlv_get_u32(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]);1137 duplex = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]);1138 autoneg = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]);1139 1140 ethtool_link_ksettings_zero_link_mode(ecmd, supported);1141 ethtool_link_ksettings_add_link_mode(ecmd, supported, TP);1142 1143 ecmd->base.phy_address = 0xff;1144 ecmd->base.port = PORT_TP;1145 ecmd->base.speed = speed;1146 ecmd->base.duplex = duplex ? DUPLEX_FULL : DUPLEX_HALF;1147 ecmd->base.autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;1148 1149 return 0;1150}1151 1152static int1153rocker_cmd_get_port_settings_macaddr_proc(const struct rocker_port *rocker_port,1154 const struct rocker_desc_info *desc_info,1155 void *priv)1156{1157 unsigned char *macaddr = priv;1158 const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];1159 const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];1160 const struct rocker_tlv *attr;1161 1162 rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);1163 if (!attrs[ROCKER_TLV_CMD_INFO])1164 return -EIO;1165 1166 rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,1167 attrs[ROCKER_TLV_CMD_INFO]);1168 attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR];1169 if (!attr)1170 return -EIO;1171 1172 if (rocker_tlv_len(attr) != ETH_ALEN)1173 return -EINVAL;1174 1175 ether_addr_copy(macaddr, rocker_tlv_data(attr));1176 return 0;1177}1178 1179static int1180rocker_cmd_get_port_settings_mode_proc(const struct rocker_port *rocker_port,1181 const struct rocker_desc_info *desc_info,1182 void *priv)1183{1184 u8 *p_mode = priv;1185 const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];1186 const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];1187 const struct rocker_tlv *attr;1188 1189 rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);1190 if (!attrs[ROCKER_TLV_CMD_INFO])1191 return -EIO;1192 1193 rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,1194 attrs[ROCKER_TLV_CMD_INFO]);1195 attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE];1196 if (!attr)1197 return -EIO;1198 1199 *p_mode = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);1200 return 0;1201}1202 1203struct port_name {1204 char *buf;1205 size_t len;1206};1207 1208static int1209rocker_cmd_get_port_settings_phys_name_proc(const struct rocker_port *rocker_port,1210 const struct rocker_desc_info *desc_info,1211 void *priv)1212{1213 const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];1214 const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];1215 struct port_name *name = priv;1216 const struct rocker_tlv *attr;1217 size_t i, j, len;1218 const char *str;1219 1220 rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);1221 if (!attrs[ROCKER_TLV_CMD_INFO])1222 return -EIO;1223 1224 rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,1225 attrs[ROCKER_TLV_CMD_INFO]);1226 attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME];1227 if (!attr)1228 return -EIO;1229 1230 len = min_t(size_t, rocker_tlv_len(attr), name->len);1231 str = rocker_tlv_data(attr);1232 1233 /* make sure name only contains alphanumeric characters */1234 for (i = j = 0; i < len; ++i) {1235 if (isalnum(str[i])) {1236 name->buf[j] = str[i];1237 j++;1238 }1239 }1240 1241 if (j == 0)1242 return -EIO;1243 1244 name->buf[j] = '\0';1245 1246 return 0;1247}1248 1249static int1250rocker_cmd_set_port_settings_ethtool_prep(const struct rocker_port *rocker_port,1251 struct rocker_desc_info *desc_info,1252 void *priv)1253{1254 struct ethtool_link_ksettings *ecmd = priv;1255 struct rocker_tlv *cmd_info;1256 1257 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,1258 ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))1259 return -EMSGSIZE;1260 cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);1261 if (!cmd_info)1262 return -EMSGSIZE;1263 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,1264 rocker_port->pport))1265 return -EMSGSIZE;1266 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED,1267 ecmd->base.speed))1268 return -EMSGSIZE;1269 if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX,1270 ecmd->base.duplex))1271 return -EMSGSIZE;1272 if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG,1273 ecmd->base.autoneg))1274 return -EMSGSIZE;1275 rocker_tlv_nest_end(desc_info, cmd_info);1276 return 0;1277}1278 1279static int1280rocker_cmd_set_port_settings_macaddr_prep(const struct rocker_port *rocker_port,1281 struct rocker_desc_info *desc_info,1282 void *priv)1283{1284 const unsigned char *macaddr = priv;1285 struct rocker_tlv *cmd_info;1286 1287 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,1288 ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))1289 return -EMSGSIZE;1290 cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);1291 if (!cmd_info)1292 return -EMSGSIZE;1293 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,1294 rocker_port->pport))1295 return -EMSGSIZE;1296 if (rocker_tlv_put(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,1297 ETH_ALEN, macaddr))1298 return -EMSGSIZE;1299 rocker_tlv_nest_end(desc_info, cmd_info);1300 return 0;1301}1302 1303static int1304rocker_cmd_set_port_settings_mtu_prep(const struct rocker_port *rocker_port,1305 struct rocker_desc_info *desc_info,1306 void *priv)1307{1308 int mtu = *(int *)priv;1309 struct rocker_tlv *cmd_info;1310 1311 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,1312 ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))1313 return -EMSGSIZE;1314 cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);1315 if (!cmd_info)1316 return -EMSGSIZE;1317 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,1318 rocker_port->pport))1319 return -EMSGSIZE;1320 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MTU,1321 mtu))1322 return -EMSGSIZE;1323 rocker_tlv_nest_end(desc_info, cmd_info);1324 return 0;1325}1326 1327static int1328rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port,1329 struct rocker_desc_info *desc_info,1330 void *priv)1331{1332 bool learning = *(bool *)priv;1333 struct rocker_tlv *cmd_info;1334 1335 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,1336 ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))1337 return -EMSGSIZE;1338 cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);1339 if (!cmd_info)1340 return -EMSGSIZE;1341 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,1342 rocker_port->pport))1343 return -EMSGSIZE;1344 if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,1345 learning))1346 return -EMSGSIZE;1347 rocker_tlv_nest_end(desc_info, cmd_info);1348 return 0;1349}1350 1351static int1352rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,1353 struct ethtool_link_ksettings *ecmd)1354{1355 return rocker_cmd_exec(rocker_port, false,1356 rocker_cmd_get_port_settings_prep, NULL,1357 rocker_cmd_get_port_settings_ethtool_proc,1358 ecmd);1359}1360 1361static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,1362 unsigned char *macaddr)1363{1364 return rocker_cmd_exec(rocker_port, false,1365 rocker_cmd_get_port_settings_prep, NULL,1366 rocker_cmd_get_port_settings_macaddr_proc,1367 macaddr);1368}1369 1370static int rocker_cmd_get_port_settings_mode(struct rocker_port *rocker_port,1371 u8 *p_mode)1372{1373 return rocker_cmd_exec(rocker_port, false,1374 rocker_cmd_get_port_settings_prep, NULL,1375 rocker_cmd_get_port_settings_mode_proc, p_mode);1376}1377 1378static int1379rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,1380 const struct ethtool_link_ksettings *ecmd)1381{1382 struct ethtool_link_ksettings copy_ecmd;1383 1384 memcpy(©_ecmd, ecmd, sizeof(copy_ecmd));1385 1386 return rocker_cmd_exec(rocker_port, false,1387 rocker_cmd_set_port_settings_ethtool_prep,1388 ©_ecmd, NULL, NULL);1389}1390 1391static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,1392 unsigned char *macaddr)1393{1394 return rocker_cmd_exec(rocker_port, false,1395 rocker_cmd_set_port_settings_macaddr_prep,1396 macaddr, NULL, NULL);1397}1398 1399static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port,1400 int mtu)1401{1402 return rocker_cmd_exec(rocker_port, false,1403 rocker_cmd_set_port_settings_mtu_prep,1404 &mtu, NULL, NULL);1405}1406 1407int rocker_port_set_learning(struct rocker_port *rocker_port,1408 bool learning)1409{1410 return rocker_cmd_exec(rocker_port, false,1411 rocker_cmd_set_port_learning_prep,1412 &learning, NULL, NULL);1413}1414 1415/**********************1416 * Worlds manipulation1417 **********************/1418 1419static struct rocker_world_ops *rocker_world_ops[] = {1420 &rocker_ofdpa_ops,1421};1422 1423#define ROCKER_WORLD_OPS_LEN ARRAY_SIZE(rocker_world_ops)1424 1425static struct rocker_world_ops *rocker_world_ops_find(u8 mode)1426{1427 int i;1428 1429 for (i = 0; i < ROCKER_WORLD_OPS_LEN; i++)1430 if (rocker_world_ops[i]->mode == mode)1431 return rocker_world_ops[i];1432 return NULL;1433}1434 1435static int rocker_world_init(struct rocker *rocker, u8 mode)1436{1437 struct rocker_world_ops *wops;1438 int err;1439 1440 wops = rocker_world_ops_find(mode);1441 if (!wops) {1442 dev_err(&rocker->pdev->dev, "port mode \"%d\" is not supported\n",1443 mode);1444 return -EINVAL;1445 }1446 rocker->wops = wops;1447 rocker->wpriv = kzalloc(wops->priv_size, GFP_KERNEL);1448 if (!rocker->wpriv)1449 return -ENOMEM;1450 if (!wops->init)1451 return 0;1452 err = wops->init(rocker);1453 if (err)1454 kfree(rocker->wpriv);1455 return err;1456}1457 1458static void rocker_world_fini(struct rocker *rocker)1459{1460 struct rocker_world_ops *wops = rocker->wops;1461 1462 if (!wops || !wops->fini)1463 return;1464 wops->fini(rocker);1465 kfree(rocker->wpriv);1466}1467 1468static int rocker_world_check_init(struct rocker_port *rocker_port)1469{1470 struct rocker *rocker = rocker_port->rocker;1471 u8 mode;1472 int err;1473 1474 err = rocker_cmd_get_port_settings_mode(rocker_port, &mode);1475 if (err) {1476 dev_err(&rocker->pdev->dev, "failed to get port mode\n");1477 return err;1478 }1479 if (rocker->wops) {1480 if (rocker->wops->mode != mode) {1481 dev_err(&rocker->pdev->dev, "hardware has ports in different worlds, which is not supported\n");1482 return -EINVAL;1483 }1484 return 0;1485 }1486 return rocker_world_init(rocker, mode);1487}1488 1489static int rocker_world_port_pre_init(struct rocker_port *rocker_port)1490{1491 struct rocker_world_ops *wops = rocker_port->rocker->wops;1492 int err;1493 1494 rocker_port->wpriv = kzalloc(wops->port_priv_size, GFP_KERNEL);1495 if (!rocker_port->wpriv)1496 return -ENOMEM;1497 if (!wops->port_pre_init)1498 return 0;1499 err = wops->port_pre_init(rocker_port);1500 if (err)1501 kfree(rocker_port->wpriv);1502 return 0;1503}1504 1505static int rocker_world_port_init(struct rocker_port *rocker_port)1506{1507 struct rocker_world_ops *wops = rocker_port->rocker->wops;1508 1509 if (!wops->port_init)1510 return 0;1511 return wops->port_init(rocker_port);1512}1513 1514static void rocker_world_port_fini(struct rocker_port *rocker_port)1515{1516 struct rocker_world_ops *wops = rocker_port->rocker->wops;1517 1518 if (!wops->port_fini)1519 return;1520 wops->port_fini(rocker_port);1521}1522 1523static void rocker_world_port_post_fini(struct rocker_port *rocker_port)1524{1525 struct rocker_world_ops *wops = rocker_port->rocker->wops;1526 1527 if (!wops->port_post_fini)1528 return;1529 wops->port_post_fini(rocker_port);1530 kfree(rocker_port->wpriv);1531}1532 1533static int rocker_world_port_open(struct rocker_port *rocker_port)1534{1535 struct rocker_world_ops *wops = rocker_port->rocker->wops;1536 1537 if (!wops->port_open)1538 return 0;1539 return wops->port_open(rocker_port);1540}1541 1542static void rocker_world_port_stop(struct rocker_port *rocker_port)1543{1544 struct rocker_world_ops *wops = rocker_port->rocker->wops;1545 1546 if (!wops->port_stop)1547 return;1548 wops->port_stop(rocker_port);1549}1550 1551static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port,1552 u8 state)1553{1554 struct rocker_world_ops *wops = rocker_port->rocker->wops;1555 1556 if (!wops->port_attr_stp_state_set)1557 return -EOPNOTSUPP;1558 1559 return wops->port_attr_stp_state_set(rocker_port, state);1560}1561 1562static int1563rocker_world_port_attr_bridge_flags_support_get(const struct rocker_port *1564 rocker_port,1565 unsigned long *1566 p_brport_flags_support)1567{1568 struct rocker_world_ops *wops = rocker_port->rocker->wops;1569 1570 if (!wops->port_attr_bridge_flags_support_get)1571 return -EOPNOTSUPP;1572 return wops->port_attr_bridge_flags_support_get(rocker_port,1573 p_brport_flags_support);1574}1575 1576static int1577rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port,1578 struct switchdev_brport_flags flags)1579{1580 struct rocker_world_ops *wops = rocker_port->rocker->wops;1581 unsigned long brport_flags_s;1582 int err;1583 1584 if (!wops->port_attr_bridge_flags_set)1585 return -EOPNOTSUPP;1586 1587 err = rocker_world_port_attr_bridge_flags_support_get(rocker_port,1588 &brport_flags_s);1589 if (err)1590 return err;1591 1592 if (flags.mask & ~brport_flags_s)1593 return -EINVAL;1594 1595 return 0;1596}1597 1598static int1599rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port,1600 struct switchdev_brport_flags flags)1601{1602 struct rocker_world_ops *wops = rocker_port->rocker->wops;1603 1604 if (!wops->port_attr_bridge_flags_set)1605 return -EOPNOTSUPP;1606 1607 return wops->port_attr_bridge_flags_set(rocker_port, flags.val);1608}1609 1610static int1611rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,1612 u32 ageing_time)1613{1614 struct rocker_world_ops *wops = rocker_port->rocker->wops;1615 1616 if (!wops->port_attr_bridge_ageing_time_set)1617 return -EOPNOTSUPP;1618 1619 return wops->port_attr_bridge_ageing_time_set(rocker_port, ageing_time);1620}1621 1622static int1623rocker_world_port_obj_vlan_add(struct rocker_port *rocker_port,1624 const struct switchdev_obj_port_vlan *vlan)1625{1626 struct rocker_world_ops *wops = rocker_port->rocker->wops;1627 1628 if (!wops->port_obj_vlan_add)1629 return -EOPNOTSUPP;1630 1631 return wops->port_obj_vlan_add(rocker_port, vlan);1632}1633 1634static int1635rocker_world_port_obj_vlan_del(struct rocker_port *rocker_port,1636 const struct switchdev_obj_port_vlan *vlan)1637{1638 struct rocker_world_ops *wops = rocker_port->rocker->wops;1639 1640 if (netif_is_bridge_master(vlan->obj.orig_dev))1641 return -EOPNOTSUPP;1642 1643 if (!wops->port_obj_vlan_del)1644 return -EOPNOTSUPP;1645 return wops->port_obj_vlan_del(rocker_port, vlan);1646}1647 1648static int1649rocker_world_port_fdb_add(struct rocker_port *rocker_port,1650 struct switchdev_notifier_fdb_info *info)1651{1652 struct rocker_world_ops *wops = rocker_port->rocker->wops;1653 1654 if (!wops->port_obj_fdb_add)1655 return -EOPNOTSUPP;1656 1657 return wops->port_obj_fdb_add(rocker_port, info->vid, info->addr);1658}1659 1660static int1661rocker_world_port_fdb_del(struct rocker_port *rocker_port,1662 struct switchdev_notifier_fdb_info *info)1663{1664 struct rocker_world_ops *wops = rocker_port->rocker->wops;1665 1666 if (!wops->port_obj_fdb_del)1667 return -EOPNOTSUPP;1668 return wops->port_obj_fdb_del(rocker_port, info->vid, info->addr);1669}1670 1671static int rocker_world_port_master_linked(struct rocker_port *rocker_port,1672 struct net_device *master,1673 struct netlink_ext_ack *extack)1674{1675 struct rocker_world_ops *wops = rocker_port->rocker->wops;1676 1677 if (!wops->port_master_linked)1678 return -EOPNOTSUPP;1679 return wops->port_master_linked(rocker_port, master, extack);1680}1681 1682static int rocker_world_port_master_unlinked(struct rocker_port *rocker_port,1683 struct net_device *master)1684{1685 struct rocker_world_ops *wops = rocker_port->rocker->wops;1686 1687 if (!wops->port_master_unlinked)1688 return -EOPNOTSUPP;1689 return wops->port_master_unlinked(rocker_port, master);1690}1691 1692static int rocker_world_port_neigh_update(struct rocker_port *rocker_port,1693 struct neighbour *n)1694{1695 struct rocker_world_ops *wops = rocker_port->rocker->wops;1696 1697 if (!wops->port_neigh_update)1698 return -EOPNOTSUPP;1699 return wops->port_neigh_update(rocker_port, n);1700}1701 1702static int rocker_world_port_neigh_destroy(struct rocker_port *rocker_port,1703 struct neighbour *n)1704{1705 struct rocker_world_ops *wops = rocker_port->rocker->wops;1706 1707 if (!wops->port_neigh_destroy)1708 return -EOPNOTSUPP;1709 return wops->port_neigh_destroy(rocker_port, n);1710}1711 1712static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,1713 const unsigned char *addr,1714 __be16 vlan_id)1715{1716 struct rocker_world_ops *wops = rocker_port->rocker->wops;1717 1718 if (!wops->port_ev_mac_vlan_seen)1719 return -EOPNOTSUPP;1720 return wops->port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);1721}1722 1723static int rocker_world_fib4_add(struct rocker *rocker,1724 const struct fib_entry_notifier_info *fen_info)1725{1726 struct rocker_world_ops *wops = rocker->wops;1727 1728 if (!wops->fib4_add)1729 return 0;1730 return wops->fib4_add(rocker, fen_info);1731}1732 1733static int rocker_world_fib4_del(struct rocker *rocker,1734 const struct fib_entry_notifier_info *fen_info)1735{1736 struct rocker_world_ops *wops = rocker->wops;1737 1738 if (!wops->fib4_del)1739 return 0;1740 return wops->fib4_del(rocker, fen_info);1741}1742 1743static void rocker_world_fib4_abort(struct rocker *rocker)1744{1745 struct rocker_world_ops *wops = rocker->wops;1746 1747 if (wops->fib4_abort)1748 wops->fib4_abort(rocker);1749}1750 1751/*****************1752 * Net device ops1753 *****************/1754 1755static int rocker_port_open(struct net_device *dev)1756{1757 struct rocker_port *rocker_port = netdev_priv(dev);1758 int err;1759 1760 err = rocker_port_dma_rings_init(rocker_port);1761 if (err)1762 return err;1763 1764 err = request_irq(rocker_msix_tx_vector(rocker_port),1765 rocker_tx_irq_handler, 0,1766 rocker_driver_name, rocker_port);1767 if (err) {1768 netdev_err(rocker_port->dev, "cannot assign tx irq\n");1769 goto err_request_tx_irq;1770 }1771 1772 err = request_irq(rocker_msix_rx_vector(rocker_port),1773 rocker_rx_irq_handler, 0,1774 rocker_driver_name, rocker_port);1775 if (err) {1776 netdev_err(rocker_port->dev, "cannot assign rx irq\n");1777 goto err_request_rx_irq;1778 }1779 1780 err = rocker_world_port_open(rocker_port);1781 if (err) {1782 netdev_err(rocker_port->dev, "cannot open port in world\n");1783 goto err_world_port_open;1784 }1785 1786 napi_enable(&rocker_port->napi_tx);1787 napi_enable(&rocker_port->napi_rx);1788 if (!dev->proto_down)1789 rocker_port_set_enable(rocker_port, true);1790 netif_start_queue(dev);1791 return 0;1792 1793err_world_port_open:1794 free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);1795err_request_rx_irq:1796 free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);1797err_request_tx_irq:1798 rocker_port_dma_rings_fini(rocker_port);1799 return err;1800}1801 1802static int rocker_port_stop(struct net_device *dev)1803{1804 struct rocker_port *rocker_port = netdev_priv(dev);1805 1806 netif_stop_queue(dev);1807 rocker_port_set_enable(rocker_port, false);1808 napi_disable(&rocker_port->napi_rx);1809 napi_disable(&rocker_port->napi_tx);1810 rocker_world_port_stop(rocker_port);1811 free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);1812 free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);1813 rocker_port_dma_rings_fini(rocker_port);1814 1815 return 0;1816}1817 1818static void rocker_tx_desc_frags_unmap(const struct rocker_port *rocker_port,1819 const struct rocker_desc_info *desc_info)1820{1821 const struct rocker *rocker = rocker_port->rocker;1822 struct pci_dev *pdev = rocker->pdev;1823 const struct rocker_tlv *attrs[ROCKER_TLV_TX_MAX + 1];1824 struct rocker_tlv *attr;1825 int rem;1826 1827 rocker_tlv_parse_desc(attrs, ROCKER_TLV_TX_MAX, desc_info);1828 if (!attrs[ROCKER_TLV_TX_FRAGS])1829 return;1830 rocker_tlv_for_each_nested(attr, attrs[ROCKER_TLV_TX_FRAGS], rem) {1831 const struct rocker_tlv *frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_MAX + 1];1832 dma_addr_t dma_handle;1833 size_t len;1834 1835 if (rocker_tlv_type(attr) != ROCKER_TLV_TX_FRAG)1836 continue;1837 rocker_tlv_parse_nested(frag_attrs, ROCKER_TLV_TX_FRAG_ATTR_MAX,1838 attr);1839 if (!frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] ||1840 !frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_LEN])1841 continue;1842 dma_handle = rocker_tlv_get_u64(frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);1843 len = rocker_tlv_get_u16(frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);1844 dma_unmap_single(&pdev->dev, dma_handle, len, DMA_TO_DEVICE);1845 }1846}1847 1848static int rocker_tx_desc_frag_map_put(const struct rocker_port *rocker_port,1849 struct rocker_desc_info *desc_info,1850 char *buf, size_t buf_len)1851{1852 const struct rocker *rocker = rocker_port->rocker;1853 struct pci_dev *pdev = rocker->pdev;1854 dma_addr_t dma_handle;1855 struct rocker_tlv *frag;1856 1857 dma_handle = dma_map_single(&pdev->dev, buf, buf_len, DMA_TO_DEVICE);1858 if (unlikely(dma_mapping_error(&pdev->dev, dma_handle))) {1859 if (net_ratelimit())1860 netdev_err(rocker_port->dev, "failed to dma map tx frag\n");1861 return -EIO;1862 }1863 frag = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAG);1864 if (!frag)1865 goto unmap_frag;1866 if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_TX_FRAG_ATTR_ADDR,1867 dma_handle))1868 goto nest_cancel;1869 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_TX_FRAG_ATTR_LEN,1870 buf_len))1871 goto nest_cancel;1872 rocker_tlv_nest_end(desc_info, frag);1873 return 0;1874 1875nest_cancel:1876 rocker_tlv_nest_cancel(desc_info, frag);1877unmap_frag:1878 dma_unmap_single(&pdev->dev, dma_handle, buf_len, DMA_TO_DEVICE);1879 return -EMSGSIZE;1880}1881 1882static netdev_tx_t rocker_port_xmit(struct sk_buff *skb, struct net_device *dev)1883{1884 struct rocker_port *rocker_port = netdev_priv(dev);1885 struct rocker *rocker = rocker_port->rocker;1886 struct rocker_desc_info *desc_info;1887 struct rocker_tlv *frags;1888 int i;1889 int err;1890 1891 desc_info = rocker_desc_head_get(&rocker_port->tx_ring);1892 if (unlikely(!desc_info)) {1893 if (net_ratelimit())1894 netdev_err(dev, "tx ring full when queue awake\n");1895 return NETDEV_TX_BUSY;1896 }1897 1898 rocker_desc_cookie_ptr_set(desc_info, skb);1899 1900 frags = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAGS);1901 if (!frags)1902 goto out;1903 err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,1904 skb->data, skb_headlen(skb));1905 if (err)1906 goto nest_cancel;1907 if (skb_shinfo(skb)->nr_frags > ROCKER_TX_FRAGS_MAX) {1908 err = skb_linearize(skb);1909 if (err)1910 goto unmap_frags;1911 }1912 1913 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {1914 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];1915 1916 err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,1917 skb_frag_address(frag),1918 skb_frag_size(frag));1919 if (err)1920 goto unmap_frags;1921 }1922 rocker_tlv_nest_end(desc_info, frags);1923 1924 rocker_desc_gen_clear(desc_info);1925 rocker_desc_head_set(rocker, &rocker_port->tx_ring, desc_info);1926 1927 desc_info = rocker_desc_head_get(&rocker_port->tx_ring);1928 if (!desc_info)1929 netif_stop_queue(dev);1930 1931 return NETDEV_TX_OK;1932 1933unmap_frags:1934 rocker_tx_desc_frags_unmap(rocker_port, desc_info);1935nest_cancel:1936 rocker_tlv_nest_cancel(desc_info, frags);1937out:1938 dev_kfree_skb(skb);1939 dev->stats.tx_dropped++;1940 1941 return NETDEV_TX_OK;1942}1943 1944static int rocker_port_set_mac_address(struct net_device *dev, void *p)1945{1946 struct sockaddr *addr = p;1947 struct rocker_port *rocker_port = netdev_priv(dev);1948 int err;1949 1950 if (!is_valid_ether_addr(addr->sa_data))1951 return -EADDRNOTAVAIL;1952 1953 err = rocker_cmd_set_port_settings_macaddr(rocker_port, addr->sa_data);1954 if (err)1955 return err;1956 eth_hw_addr_set(dev, addr->sa_data);1957 return 0;1958}1959 1960static int rocker_port_change_mtu(struct net_device *dev, int new_mtu)1961{1962 struct rocker_port *rocker_port = netdev_priv(dev);1963 int running = netif_running(dev);1964 int err;1965 1966 if (running)1967 rocker_port_stop(dev);1968 1969 netdev_info(dev, "MTU change from %d to %d\n", dev->mtu, new_mtu);1970 WRITE_ONCE(dev->mtu, new_mtu);1971 1972 err = rocker_cmd_set_port_settings_mtu(rocker_port, new_mtu);1973 if (err)1974 return err;1975 1976 if (running)1977 err = rocker_port_open(dev);1978 1979 return err;1980}1981 1982static int rocker_port_get_phys_port_name(struct net_device *dev,1983 char *buf, size_t len)1984{1985 struct rocker_port *rocker_port = netdev_priv(dev);1986 struct port_name name = { .buf = buf, .len = len };1987 int err;1988 1989 err = rocker_cmd_exec(rocker_port, false,1990 rocker_cmd_get_port_settings_prep, NULL,1991 rocker_cmd_get_port_settings_phys_name_proc,1992 &name);1993 1994 return err ? -EOPNOTSUPP : 0;1995}1996 1997static void rocker_port_neigh_destroy(struct net_device *dev,1998 struct neighbour *n)1999{2000 struct rocker_port *rocker_port = netdev_priv(n->dev);2001 int err;2002 2003 err = rocker_world_port_neigh_destroy(rocker_port, n);2004 if (err)2005 netdev_warn(rocker_port->dev, "failed to handle neigh destroy (err %d)\n",2006 err);2007}2008 2009static int rocker_port_get_port_parent_id(struct net_device *dev,2010 struct netdev_phys_item_id *ppid)2011{2012 const struct rocker_port *rocker_port = netdev_priv(dev);2013 const struct rocker *rocker = rocker_port->rocker;2014 2015 ppid->id_len = sizeof(rocker->hw.id);2016 memcpy(&ppid->id, &rocker->hw.id, ppid->id_len);2017 2018 return 0;2019}2020 2021static const struct net_device_ops rocker_port_netdev_ops = {2022 .ndo_open = rocker_port_open,2023 .ndo_stop = rocker_port_stop,2024 .ndo_start_xmit = rocker_port_xmit,2025 .ndo_set_mac_address = rocker_port_set_mac_address,2026 .ndo_change_mtu = rocker_port_change_mtu,2027 .ndo_get_phys_port_name = rocker_port_get_phys_port_name,2028 .ndo_neigh_destroy = rocker_port_neigh_destroy,2029 .ndo_get_port_parent_id = rocker_port_get_port_parent_id,2030};2031 2032/********************2033 * swdev interface2034 ********************/2035 2036static int rocker_port_attr_set(struct net_device *dev,2037 const struct switchdev_attr *attr)2038{2039 struct rocker_port *rocker_port = netdev_priv(dev);2040 int err = 0;2041 2042 switch (attr->id) {2043 case SWITCHDEV_ATTR_ID_PORT_STP_STATE:2044 err = rocker_world_port_attr_stp_state_set(rocker_port,2045 attr->u.stp_state);2046 break;2047 case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:2048 err = rocker_world_port_attr_pre_bridge_flags_set(rocker_port,2049 attr->u.brport_flags);2050 break;2051 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:2052 err = rocker_world_port_attr_bridge_flags_set(rocker_port,2053 attr->u.brport_flags);2054 break;2055 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:2056 err = rocker_world_port_attr_bridge_ageing_time_set(rocker_port,2057 attr->u.ageing_time);2058 break;2059 default:2060 err = -EOPNOTSUPP;2061 break;2062 }2063 2064 return err;2065}2066 2067static int rocker_port_obj_add(struct net_device *dev,2068 const struct switchdev_obj *obj)2069{2070 struct rocker_port *rocker_port = netdev_priv(dev);2071 int err = 0;2072 2073 switch (obj->id) {2074 case SWITCHDEV_OBJ_ID_PORT_VLAN:2075 err = rocker_world_port_obj_vlan_add(rocker_port,2076 SWITCHDEV_OBJ_PORT_VLAN(obj));2077 break;2078 default:2079 err = -EOPNOTSUPP;2080 break;2081 }2082 2083 return err;2084}2085 2086static int rocker_port_obj_del(struct net_device *dev,2087 const struct switchdev_obj *obj)2088{2089 struct rocker_port *rocker_port = netdev_priv(dev);2090 int err = 0;2091 2092 switch (obj->id) {2093 case SWITCHDEV_OBJ_ID_PORT_VLAN:2094 err = rocker_world_port_obj_vlan_del(rocker_port,2095 SWITCHDEV_OBJ_PORT_VLAN(obj));2096 break;2097 default:2098 err = -EOPNOTSUPP;2099 break;2100 }2101 2102 return err;2103}2104 2105struct rocker_fib_event_work {2106 struct work_struct work;2107 union {2108 struct fib_entry_notifier_info fen_info;2109 struct fib_rule_notifier_info fr_info;2110 };2111 struct rocker *rocker;2112 unsigned long event;2113};2114 2115static void rocker_router_fib_event_work(struct work_struct *work)2116{2117 struct rocker_fib_event_work *fib_work =2118 container_of(work, struct rocker_fib_event_work, work);2119 struct rocker *rocker = fib_work->rocker;2120 struct fib_rule *rule;2121 int err;2122 2123 /* Protect internal structures from changes */2124 rtnl_lock();2125 switch (fib_work->event) {2126 case FIB_EVENT_ENTRY_REPLACE:2127 err = rocker_world_fib4_add(rocker, &fib_work->fen_info);2128 if (err)2129 rocker_world_fib4_abort(rocker);2130 fib_info_put(fib_work->fen_info.fi);2131 break;2132 case FIB_EVENT_ENTRY_DEL:2133 rocker_world_fib4_del(rocker, &fib_work->fen_info);2134 fib_info_put(fib_work->fen_info.fi);2135 break;2136 case FIB_EVENT_RULE_ADD:2137 case FIB_EVENT_RULE_DEL:2138 rule = fib_work->fr_info.rule;2139 if (!fib4_rule_default(rule))2140 rocker_world_fib4_abort(rocker);2141 fib_rule_put(rule);2142 break;2143 }2144 rtnl_unlock();2145 kfree(fib_work);2146}2147 2148/* Called with rcu_read_lock() */2149static int rocker_router_fib_event(struct notifier_block *nb,2150 unsigned long event, void *ptr)2151{2152 struct rocker *rocker = container_of(nb, struct rocker, fib_nb);2153 struct rocker_fib_event_work *fib_work;2154 struct fib_notifier_info *info = ptr;2155 2156 if (info->family != AF_INET)2157 return NOTIFY_DONE;2158 2159 fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC);2160 if (WARN_ON(!fib_work))2161 return NOTIFY_BAD;2162 2163 INIT_WORK(&fib_work->work, rocker_router_fib_event_work);2164 fib_work->rocker = rocker;2165 fib_work->event = event;2166 2167 switch (event) {2168 case FIB_EVENT_ENTRY_REPLACE:2169 case FIB_EVENT_ENTRY_DEL:2170 if (info->family == AF_INET) {2171 struct fib_entry_notifier_info *fen_info = ptr;2172 2173 if (fen_info->fi->fib_nh_is_v6) {2174 NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");2175 kfree(fib_work);2176 return notifier_from_errno(-EINVAL);2177 }2178 if (fen_info->fi->nh) {2179 NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");2180 kfree(fib_work);2181 return notifier_from_errno(-EINVAL);2182 }2183 }2184 2185 memcpy(&fib_work->fen_info, ptr, sizeof(fib_work->fen_info));2186 /* Take referece on fib_info to prevent it from being2187 * freed while work is queued. Release it afterwards.2188 */2189 fib_info_hold(fib_work->fen_info.fi);2190 break;2191 case FIB_EVENT_RULE_ADD:2192 case FIB_EVENT_RULE_DEL:2193 memcpy(&fib_work->fr_info, ptr, sizeof(fib_work->fr_info));2194 fib_rule_get(fib_work->fr_info.rule);2195 break;2196 }2197 2198 queue_work(rocker->rocker_owq, &fib_work->work);2199 2200 return NOTIFY_DONE;2201}2202 2203/********************2204 * ethtool interface2205 ********************/2206 2207static int2208rocker_port_get_link_ksettings(struct net_device *dev,2209 struct ethtool_link_ksettings *ecmd)2210{2211 struct rocker_port *rocker_port = netdev_priv(dev);2212 2213 return rocker_cmd_get_port_settings_ethtool(rocker_port, ecmd);2214}2215 2216static int2217rocker_port_set_link_ksettings(struct net_device *dev,2218 const struct ethtool_link_ksettings *ecmd)2219{2220 struct rocker_port *rocker_port = netdev_priv(dev);2221 2222 return rocker_cmd_set_port_settings_ethtool(rocker_port, ecmd);2223}2224 2225static void rocker_port_get_drvinfo(struct net_device *dev,2226 struct ethtool_drvinfo *drvinfo)2227{2228 strscpy(drvinfo->driver, rocker_driver_name, sizeof(drvinfo->driver));2229}2230 2231static struct rocker_port_stats {2232 char str[ETH_GSTRING_LEN];2233 int type;2234} rocker_port_stats[] = {2235 { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, },2236 { "rx_bytes", ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, },2237 { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, },2238 { "rx_errors", ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, },2239 2240 { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, },2241 { "tx_bytes", ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, },2242 { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, },2243 { "tx_errors", ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, },2244};2245 2246#define ROCKER_PORT_STATS_LEN ARRAY_SIZE(rocker_port_stats)2247 2248static void rocker_port_get_strings(struct net_device *netdev, u32 stringset,2249 u8 *data)2250{2251 u8 *p = data;2252 int i;2253 2254 switch (stringset) {2255 case ETH_SS_STATS:2256 for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {2257 memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN);2258 p += ETH_GSTRING_LEN;2259 }2260 break;2261 }2262}2263 2264static int2265rocker_cmd_get_port_stats_prep(const struct rocker_port *rocker_port,2266 struct rocker_desc_info *desc_info,2267 void *priv)2268{2269 struct rocker_tlv *cmd_stats;2270 2271 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,2272 ROCKER_TLV_CMD_TYPE_GET_PORT_STATS))2273 return -EMSGSIZE;2274 2275 cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);2276 if (!cmd_stats)2277 return -EMSGSIZE;2278 2279 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_PPORT,2280 rocker_port->pport))2281 return -EMSGSIZE;2282 2283 rocker_tlv_nest_end(desc_info, cmd_stats);2284 2285 return 0;2286}2287 2288static int2289rocker_cmd_get_port_stats_ethtool_proc(const struct rocker_port *rocker_port,2290 const struct rocker_desc_info *desc_info,2291 void *priv)2292{2293 const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];2294 const struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];2295 const struct rocker_tlv *pattr;2296 u32 pport;2297 u64 *data = priv;2298 int i;2299 2300 rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);2301 2302 if (!attrs[ROCKER_TLV_CMD_INFO])2303 return -EIO;2304 2305 rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX,2306 attrs[ROCKER_TLV_CMD_INFO]);2307 2308 if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_PPORT])2309 return -EIO;2310 2311 pport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_PPORT]);2312 if (pport != rocker_port->pport)2313 return -EIO;2314 2315 for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {2316 pattr = stats_attrs[rocker_port_stats[i].type];2317 if (!pattr)2318 continue;2319 2320 data[i] = rocker_tlv_get_u64(pattr);2321 }2322 2323 return 0;2324}2325 2326static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,2327 void *priv)2328{2329 return rocker_cmd_exec(rocker_port, false,2330 rocker_cmd_get_port_stats_prep, NULL,2331 rocker_cmd_get_port_stats_ethtool_proc,2332 priv);2333}2334 2335static void rocker_port_get_stats(struct net_device *dev,2336 struct ethtool_stats *stats, u64 *data)2337{2338 struct rocker_port *rocker_port = netdev_priv(dev);2339 2340 if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) {2341 int i;2342 2343 for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i)2344 data[i] = 0;2345 }2346}2347 2348static int rocker_port_get_sset_count(struct net_device *netdev, int sset)2349{2350 switch (sset) {2351 case ETH_SS_STATS:2352 return ROCKER_PORT_STATS_LEN;2353 default:2354 return -EOPNOTSUPP;2355 }2356}2357 2358static const struct ethtool_ops rocker_port_ethtool_ops = {2359 .get_drvinfo = rocker_port_get_drvinfo,2360 .get_link = ethtool_op_get_link,2361 .get_strings = rocker_port_get_strings,2362 .get_ethtool_stats = rocker_port_get_stats,2363 .get_sset_count = rocker_port_get_sset_count,2364 .get_link_ksettings = rocker_port_get_link_ksettings,2365 .set_link_ksettings = rocker_port_set_link_ksettings,2366};2367 2368/*****************2369 * NAPI interface2370 *****************/2371 2372static struct rocker_port *rocker_port_napi_tx_get(struct napi_struct *napi)2373{2374 return container_of(napi, struct rocker_port, napi_tx);2375}2376 2377static int rocker_port_poll_tx(struct napi_struct *napi, int budget)2378{2379 struct rocker_port *rocker_port = rocker_port_napi_tx_get(napi);2380 const struct rocker *rocker = rocker_port->rocker;2381 const struct rocker_desc_info *desc_info;2382 u32 credits = 0;2383 int err;2384 2385 /* Cleanup tx descriptors */2386 while ((desc_info = rocker_desc_tail_get(&rocker_port->tx_ring))) {2387 struct sk_buff *skb;2388 2389 err = rocker_desc_err(desc_info);2390 if (err && net_ratelimit())2391 netdev_err(rocker_port->dev, "tx desc received with err %d\n",2392 err);2393 rocker_tx_desc_frags_unmap(rocker_port, desc_info);2394 2395 skb = rocker_desc_cookie_ptr_get(desc_info);2396 if (err == 0) {2397 rocker_port->dev->stats.tx_packets++;2398 rocker_port->dev->stats.tx_bytes += skb->len;2399 } else {2400 rocker_port->dev->stats.tx_errors++;2401 }2402 2403 dev_kfree_skb_any(skb);2404 credits++;2405 }2406 2407 if (credits && netif_queue_stopped(rocker_port->dev))2408 netif_wake_queue(rocker_port->dev);2409 2410 napi_complete(napi);2411 rocker_dma_ring_credits_set(rocker, &rocker_port->tx_ring, credits);2412 2413 return 0;2414}2415 2416static int rocker_port_rx_proc(const struct rocker *rocker,2417 const struct rocker_port *rocker_port,2418 struct rocker_desc_info *desc_info)2419{2420 const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];2421 struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);2422 size_t rx_len;2423 u16 rx_flags = 0;2424 2425 if (!skb)2426 return -ENOENT;2427 2428 rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info);2429 if (!attrs[ROCKER_TLV_RX_FRAG_LEN])2430 return -EINVAL;2431 if (attrs[ROCKER_TLV_RX_FLAGS])2432 rx_flags = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FLAGS]);2433 2434 rocker_dma_rx_ring_skb_unmap(rocker, attrs);2435 2436 rx_len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_LEN]);2437 skb_put(skb, rx_len);2438 skb->protocol = eth_type_trans(skb, rocker_port->dev);2439 2440 if (rx_flags & ROCKER_RX_FLAGS_FWD_OFFLOAD)2441 skb->offload_fwd_mark = 1;2442 2443 rocker_port->dev->stats.rx_packets++;2444 rocker_port->dev->stats.rx_bytes += skb->len;2445 2446 netif_receive_skb(skb);2447 2448 return rocker_dma_rx_ring_skb_alloc(rocker_port, desc_info);2449}2450 2451static struct rocker_port *rocker_port_napi_rx_get(struct napi_struct *napi)2452{2453 return container_of(napi, struct rocker_port, napi_rx);2454}2455 2456static int rocker_port_poll_rx(struct napi_struct *napi, int budget)2457{2458 struct rocker_port *rocker_port = rocker_port_napi_rx_get(napi);2459 const struct rocker *rocker = rocker_port->rocker;2460 struct rocker_desc_info *desc_info;2461 u32 credits = 0;2462 int err;2463 2464 /* Process rx descriptors */2465 while (credits < budget &&2466 (desc_info = rocker_desc_tail_get(&rocker_port->rx_ring))) {2467 err = rocker_desc_err(desc_info);2468 if (err) {2469 if (net_ratelimit())2470 netdev_err(rocker_port->dev, "rx desc received with err %d\n",2471 err);2472 } else {2473 err = rocker_port_rx_proc(rocker, rocker_port,2474 desc_info);2475 if (err && net_ratelimit())2476 netdev_err(rocker_port->dev, "rx processing failed with err %d\n",2477 err);2478 }2479 if (err)2480 rocker_port->dev->stats.rx_errors++;2481 2482 rocker_desc_gen_clear(desc_info);2483 rocker_desc_head_set(rocker, &rocker_port->rx_ring, desc_info);2484 credits++;2485 }2486 2487 if (credits < budget)2488 napi_complete_done(napi, credits);2489 2490 rocker_dma_ring_credits_set(rocker, &rocker_port->rx_ring, credits);2491 2492 return credits;2493}2494 2495/*****************2496 * PCI driver ops2497 *****************/2498 2499static void rocker_carrier_init(const struct rocker_port *rocker_port)2500{2501 const struct rocker *rocker = rocker_port->rocker;2502 u64 link_status = rocker_read64(rocker, PORT_PHYS_LINK_STATUS);2503 bool link_up;2504 2505 link_up = link_status & (1 << rocker_port->pport);2506 if (link_up)2507 netif_carrier_on(rocker_port->dev);2508 else2509 netif_carrier_off(rocker_port->dev);2510}2511 2512static void rocker_remove_ports(struct rocker *rocker)2513{2514 struct rocker_port *rocker_port;2515 int i;2516 2517 for (i = 0; i < rocker->port_count; i++) {2518 rocker_port = rocker->ports[i];2519 if (!rocker_port)2520 continue;2521 rocker_world_port_fini(rocker_port);2522 unregister_netdev(rocker_port->dev);2523 rocker_world_port_post_fini(rocker_port);2524 free_netdev(rocker_port->dev);2525 }2526 rocker_world_fini(rocker);2527 kfree(rocker->ports);2528}2529 2530static void rocker_port_dev_addr_init(struct rocker_port *rocker_port)2531{2532 const struct rocker *rocker = rocker_port->rocker;2533 const struct pci_dev *pdev = rocker->pdev;2534 u8 addr[ETH_ALEN];2535 int err;2536 2537 err = rocker_cmd_get_port_settings_macaddr(rocker_port, addr);2538 if (!err) {2539 eth_hw_addr_set(rocker_port->dev, addr);2540 } else {2541 dev_warn(&pdev->dev, "failed to get mac address, using random\n");2542 eth_hw_addr_random(rocker_port->dev);2543 }2544}2545 2546#define ROCKER_PORT_MIN_MTU ETH_MIN_MTU2547#define ROCKER_PORT_MAX_MTU 90002548static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)2549{2550 struct pci_dev *pdev = rocker->pdev;2551 struct rocker_port *rocker_port;2552 struct net_device *dev;2553 int err;2554 2555 dev = alloc_etherdev(sizeof(struct rocker_port));2556 if (!dev)2557 return -ENOMEM;2558 SET_NETDEV_DEV(dev, &pdev->dev);2559 rocker_port = netdev_priv(dev);2560 rocker_port->dev = dev;2561 rocker_port->rocker = rocker;2562 rocker_port->port_number = port_number;2563 rocker_port->pport = port_number + 1;2564 2565 err = rocker_world_check_init(rocker_port);2566 if (err) {2567 dev_err(&pdev->dev, "world init failed\n");2568 goto err_world_check_init;2569 }2570 2571 rocker_port_dev_addr_init(rocker_port);2572 dev->netdev_ops = &rocker_port_netdev_ops;2573 dev->ethtool_ops = &rocker_port_ethtool_ops;2574 netif_napi_add_tx(dev, &rocker_port->napi_tx, rocker_port_poll_tx);2575 netif_napi_add(dev, &rocker_port->napi_rx, rocker_port_poll_rx);2576 rocker_carrier_init(rocker_port);2577 2578 dev->features |= NETIF_F_SG;2579 dev->netns_local = true;2580 2581 /* MTU range: 68 - 9000 */2582 dev->min_mtu = ROCKER_PORT_MIN_MTU;2583 dev->max_mtu = ROCKER_PORT_MAX_MTU;2584 2585 err = rocker_world_port_pre_init(rocker_port);2586 if (err) {2587 dev_err(&pdev->dev, "port world pre-init failed\n");2588 goto err_world_port_pre_init;2589 }2590 err = register_netdev(dev);2591 if (err) {2592 dev_err(&pdev->dev, "register_netdev failed\n");2593 goto err_register_netdev;2594 }2595 rocker->ports[port_number] = rocker_port;2596 2597 err = rocker_world_port_init(rocker_port);2598 if (err) {2599 dev_err(&pdev->dev, "port world init failed\n");2600 goto err_world_port_init;2601 }2602 2603 return 0;2604 2605err_world_port_init:2606 rocker->ports[port_number] = NULL;2607 unregister_netdev(dev);2608err_register_netdev:2609 rocker_world_port_post_fini(rocker_port);2610err_world_port_pre_init:2611err_world_check_init:2612 free_netdev(dev);2613 return err;2614}2615 2616static int rocker_probe_ports(struct rocker *rocker)2617{2618 int i;2619 size_t alloc_size;2620 int err;2621 2622 alloc_size = sizeof(struct rocker_port *) * rocker->port_count;2623 rocker->ports = kzalloc(alloc_size, GFP_KERNEL);2624 if (!rocker->ports)2625 return -ENOMEM;2626 for (i = 0; i < rocker->port_count; i++) {2627 err = rocker_probe_port(rocker, i);2628 if (err)2629 goto remove_ports;2630 }2631 return 0;2632 2633remove_ports:2634 rocker_remove_ports(rocker);2635 return err;2636}2637 2638static int rocker_msix_init(struct rocker *rocker)2639{2640 struct pci_dev *pdev = rocker->pdev;2641 int msix_entries;2642 int i;2643 int err;2644 2645 msix_entries = pci_msix_vec_count(pdev);2646 if (msix_entries < 0)2647 return msix_entries;2648 2649 if (msix_entries != ROCKER_MSIX_VEC_COUNT(rocker->port_count))2650 return -EINVAL;2651 2652 rocker->msix_entries = kmalloc_array(msix_entries,2653 sizeof(struct msix_entry),2654 GFP_KERNEL);2655 if (!rocker->msix_entries)2656 return -ENOMEM;2657 2658 for (i = 0; i < msix_entries; i++)2659 rocker->msix_entries[i].entry = i;2660 2661 err = pci_enable_msix_exact(pdev, rocker->msix_entries, msix_entries);2662 if (err < 0)2663 goto err_enable_msix;2664 2665 return 0;2666 2667err_enable_msix:2668 kfree(rocker->msix_entries);2669 return err;2670}2671 2672static void rocker_msix_fini(const struct rocker *rocker)2673{2674 pci_disable_msix(rocker->pdev);2675 kfree(rocker->msix_entries);2676}2677 2678static bool rocker_port_dev_check(const struct net_device *dev)2679{2680 return dev->netdev_ops == &rocker_port_netdev_ops;2681}2682 2683static int2684rocker_switchdev_port_attr_set_event(struct net_device *netdev,2685 struct switchdev_notifier_port_attr_info *port_attr_info)2686{2687 int err;2688 2689 err = rocker_port_attr_set(netdev, port_attr_info->attr);2690 2691 port_attr_info->handled = true;2692 return notifier_from_errno(err);2693}2694 2695struct rocker_switchdev_event_work {2696 struct work_struct work;2697 struct switchdev_notifier_fdb_info fdb_info;2698 struct rocker_port *rocker_port;2699 unsigned long event;2700};2701 2702static void2703rocker_fdb_offload_notify(struct rocker_port *rocker_port,2704 struct switchdev_notifier_fdb_info *recv_info)2705{2706 struct switchdev_notifier_fdb_info info = {};2707 2708 info.addr = recv_info->addr;2709 info.vid = recv_info->vid;2710 info.offloaded = true;2711 call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,2712 rocker_port->dev, &info.info, NULL);2713}2714 2715static void rocker_switchdev_event_work(struct work_struct *work)2716{2717 struct rocker_switchdev_event_work *switchdev_work =2718 container_of(work, struct rocker_switchdev_event_work, work);2719 struct rocker_port *rocker_port = switchdev_work->rocker_port;2720 struct switchdev_notifier_fdb_info *fdb_info;2721 int err;2722 2723 rtnl_lock();2724 switch (switchdev_work->event) {2725 case SWITCHDEV_FDB_ADD_TO_DEVICE:2726 fdb_info = &switchdev_work->fdb_info;2727 if (!fdb_info->added_by_user || fdb_info->is_local)2728 break;2729 err = rocker_world_port_fdb_add(rocker_port, fdb_info);2730 if (err) {2731 netdev_dbg(rocker_port->dev, "fdb add failed err=%d\n", err);2732 break;2733 }2734 rocker_fdb_offload_notify(rocker_port, fdb_info);2735 break;2736 case SWITCHDEV_FDB_DEL_TO_DEVICE:2737 fdb_info = &switchdev_work->fdb_info;2738 if (!fdb_info->added_by_user || fdb_info->is_local)2739 break;2740 err = rocker_world_port_fdb_del(rocker_port, fdb_info);2741 if (err)2742 netdev_dbg(rocker_port->dev, "fdb add failed err=%d\n", err);2743 break;2744 }2745 rtnl_unlock();2746 2747 kfree(switchdev_work->fdb_info.addr);2748 kfree(switchdev_work);2749 dev_put(rocker_port->dev);2750}2751 2752/* called under rcu_read_lock() */2753static int rocker_switchdev_event(struct notifier_block *unused,2754 unsigned long event, void *ptr)2755{2756 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);2757 struct rocker_switchdev_event_work *switchdev_work;2758 struct switchdev_notifier_fdb_info *fdb_info = ptr;2759 struct rocker_port *rocker_port;2760 2761 if (!rocker_port_dev_check(dev))2762 return NOTIFY_DONE;2763 2764 if (event == SWITCHDEV_PORT_ATTR_SET)2765 return rocker_switchdev_port_attr_set_event(dev, ptr);2766 2767 rocker_port = netdev_priv(dev);2768 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);2769 if (WARN_ON(!switchdev_work))2770 return NOTIFY_BAD;2771 2772 INIT_WORK(&switchdev_work->work, rocker_switchdev_event_work);2773 switchdev_work->rocker_port = rocker_port;2774 switchdev_work->event = event;2775 2776 switch (event) {2777 case SWITCHDEV_FDB_ADD_TO_DEVICE:2778 case SWITCHDEV_FDB_DEL_TO_DEVICE:2779 memcpy(&switchdev_work->fdb_info, ptr,2780 sizeof(switchdev_work->fdb_info));2781 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);2782 if (unlikely(!switchdev_work->fdb_info.addr)) {2783 kfree(switchdev_work);2784 return NOTIFY_BAD;2785 }2786 2787 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,2788 fdb_info->addr);2789 /* Take a reference on the rocker device */2790 dev_hold(dev);2791 break;2792 default:2793 kfree(switchdev_work);2794 return NOTIFY_DONE;2795 }2796 2797 queue_work(rocker_port->rocker->rocker_owq,2798 &switchdev_work->work);2799 return NOTIFY_DONE;2800}2801 2802static int2803rocker_switchdev_port_obj_event(unsigned long event, struct net_device *netdev,2804 struct switchdev_notifier_port_obj_info *port_obj_info)2805{2806 int err = -EOPNOTSUPP;2807 2808 switch (event) {2809 case SWITCHDEV_PORT_OBJ_ADD:2810 err = rocker_port_obj_add(netdev, port_obj_info->obj);2811 break;2812 case SWITCHDEV_PORT_OBJ_DEL:2813 err = rocker_port_obj_del(netdev, port_obj_info->obj);2814 break;2815 }2816 2817 port_obj_info->handled = true;2818 return notifier_from_errno(err);2819}2820 2821static int rocker_switchdev_blocking_event(struct notifier_block *unused,2822 unsigned long event, void *ptr)2823{2824 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);2825 2826 if (!rocker_port_dev_check(dev))2827 return NOTIFY_DONE;2828 2829 switch (event) {2830 case SWITCHDEV_PORT_OBJ_ADD:2831 case SWITCHDEV_PORT_OBJ_DEL:2832 return rocker_switchdev_port_obj_event(event, dev, ptr);2833 case SWITCHDEV_PORT_ATTR_SET:2834 return rocker_switchdev_port_attr_set_event(dev, ptr);2835 }2836 2837 return NOTIFY_DONE;2838}2839 2840static struct notifier_block rocker_switchdev_notifier = {2841 .notifier_call = rocker_switchdev_event,2842};2843 2844static struct notifier_block rocker_switchdev_blocking_notifier = {2845 .notifier_call = rocker_switchdev_blocking_event,2846};2847 2848static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)2849{2850 struct notifier_block *nb;2851 struct rocker *rocker;2852 int err;2853 2854 rocker = kzalloc(sizeof(*rocker), GFP_KERNEL);2855 if (!rocker)2856 return -ENOMEM;2857 2858 err = pci_enable_device(pdev);2859 if (err) {2860 dev_err(&pdev->dev, "pci_enable_device failed\n");2861 goto err_pci_enable_device;2862 }2863 2864 err = pci_request_regions(pdev, rocker_driver_name);2865 if (err) {2866 dev_err(&pdev->dev, "pci_request_regions failed\n");2867 goto err_pci_request_regions;2868 }2869 2870 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));2871 if (err) {2872 dev_err(&pdev->dev, "dma_set_mask failed\n");2873 goto err_pci_set_dma_mask;2874 }2875 2876 if (pci_resource_len(pdev, 0) < ROCKER_PCI_BAR0_SIZE) {2877 dev_err(&pdev->dev, "invalid PCI region size\n");2878 err = -EINVAL;2879 goto err_pci_resource_len_check;2880 }2881 2882 rocker->hw_addr = ioremap(pci_resource_start(pdev, 0),2883 pci_resource_len(pdev, 0));2884 if (!rocker->hw_addr) {2885 dev_err(&pdev->dev, "ioremap failed\n");2886 err = -EIO;2887 goto err_ioremap;2888 }2889 pci_set_master(pdev);2890 2891 rocker->pdev = pdev;2892 pci_set_drvdata(pdev, rocker);2893 2894 rocker->port_count = rocker_read32(rocker, PORT_PHYS_COUNT);2895 2896 err = rocker_msix_init(rocker);2897 if (err) {2898 dev_err(&pdev->dev, "MSI-X init failed\n");2899 goto err_msix_init;2900 }2901 2902 err = rocker_basic_hw_test(rocker);2903 if (err) {2904 dev_err(&pdev->dev, "basic hw test failed\n");2905 goto err_basic_hw_test;2906 }2907 2908 rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);2909 2910 err = rocker_dma_rings_init(rocker);2911 if (err)2912 goto err_dma_rings_init;2913 2914 err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD),2915 rocker_cmd_irq_handler, 0,2916 rocker_driver_name, rocker);2917 if (err) {2918 dev_err(&pdev->dev, "cannot assign cmd irq\n");2919 goto err_request_cmd_irq;2920 }2921 2922 err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT),2923 rocker_event_irq_handler, 0,2924 rocker_driver_name, rocker);2925 if (err) {2926 dev_err(&pdev->dev, "cannot assign event irq\n");2927 goto err_request_event_irq;2928 }2929 2930 rocker->rocker_owq = alloc_ordered_workqueue(rocker_driver_name,2931 WQ_MEM_RECLAIM);2932 if (!rocker->rocker_owq) {2933 err = -ENOMEM;2934 goto err_alloc_ordered_workqueue;2935 }2936 2937 err = rocker_probe_ports(rocker);2938 if (err) {2939 dev_err(&pdev->dev, "failed to probe ports\n");2940 goto err_probe_ports;2941 }2942 2943 /* Only FIBs pointing to our own netdevs are programmed into2944 * the device, so no need to pass a callback.2945 */2946 rocker->fib_nb.notifier_call = rocker_router_fib_event;2947 err = register_fib_notifier(&init_net, &rocker->fib_nb, NULL, NULL);2948 if (err)2949 goto err_register_fib_notifier;2950 2951 err = register_switchdev_notifier(&rocker_switchdev_notifier);2952 if (err) {2953 dev_err(&pdev->dev, "Failed to register switchdev notifier\n");2954 goto err_register_switchdev_notifier;2955 }2956 2957 nb = &rocker_switchdev_blocking_notifier;2958 err = register_switchdev_blocking_notifier(nb);2959 if (err) {2960 dev_err(&pdev->dev, "Failed to register switchdev blocking notifier\n");2961 goto err_register_switchdev_blocking_notifier;2962 }2963 2964 rocker->hw.id = rocker_read64(rocker, SWITCH_ID);2965 2966 dev_info(&pdev->dev, "Rocker switch with id %*phN\n",2967 (int)sizeof(rocker->hw.id), &rocker->hw.id);2968 2969 return 0;2970 2971err_register_switchdev_blocking_notifier:2972 unregister_switchdev_notifier(&rocker_switchdev_notifier);2973err_register_switchdev_notifier:2974 unregister_fib_notifier(&init_net, &rocker->fib_nb);2975err_register_fib_notifier:2976 rocker_remove_ports(rocker);2977err_probe_ports:2978 destroy_workqueue(rocker->rocker_owq);2979err_alloc_ordered_workqueue:2980 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);2981err_request_event_irq:2982 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);2983err_request_cmd_irq:2984 rocker_dma_rings_fini(rocker);2985err_dma_rings_init:2986err_basic_hw_test:2987 rocker_msix_fini(rocker);2988err_msix_init:2989 iounmap(rocker->hw_addr);2990err_ioremap:2991err_pci_resource_len_check:2992err_pci_set_dma_mask:2993 pci_release_regions(pdev);2994err_pci_request_regions:2995 pci_disable_device(pdev);2996err_pci_enable_device:2997 kfree(rocker);2998 return err;2999}3000 3001static void rocker_remove(struct pci_dev *pdev)3002{3003 struct rocker *rocker = pci_get_drvdata(pdev);3004 struct notifier_block *nb;3005 3006 nb = &rocker_switchdev_blocking_notifier;3007 unregister_switchdev_blocking_notifier(nb);3008 3009 unregister_switchdev_notifier(&rocker_switchdev_notifier);3010 unregister_fib_notifier(&init_net, &rocker->fib_nb);3011 rocker_remove_ports(rocker);3012 rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);3013 destroy_workqueue(rocker->rocker_owq);3014 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);3015 free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);3016 rocker_dma_rings_fini(rocker);3017 rocker_msix_fini(rocker);3018 iounmap(rocker->hw_addr);3019 pci_release_regions(rocker->pdev);3020 pci_disable_device(rocker->pdev);3021 kfree(rocker);3022}3023 3024static struct pci_driver rocker_pci_driver = {3025 .name = rocker_driver_name,3026 .id_table = rocker_pci_id_table,3027 .probe = rocker_probe,3028 .remove = rocker_remove,3029};3030 3031/************************************3032 * Net device notifier event handler3033 ************************************/3034 3035static bool rocker_port_dev_check_under(const struct net_device *dev,3036 struct rocker *rocker)3037{3038 struct rocker_port *rocker_port;3039 3040 if (!rocker_port_dev_check(dev))3041 return false;3042 3043 rocker_port = netdev_priv(dev);3044 if (rocker_port->rocker != rocker)3045 return false;3046 3047 return true;3048}3049 3050struct rocker_walk_data {3051 struct rocker *rocker;3052 struct rocker_port *port;3053};3054 3055static int rocker_lower_dev_walk(struct net_device *lower_dev,3056 struct netdev_nested_priv *priv)3057{3058 struct rocker_walk_data *data = (struct rocker_walk_data *)priv->data;3059 int ret = 0;3060 3061 if (rocker_port_dev_check_under(lower_dev, data->rocker)) {3062 data->port = netdev_priv(lower_dev);3063 ret = 1;3064 }3065 3066 return ret;3067}3068 3069struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,3070 struct rocker *rocker)3071{3072 struct netdev_nested_priv priv;3073 struct rocker_walk_data data;3074 3075 if (rocker_port_dev_check_under(dev, rocker))3076 return netdev_priv(dev);3077 3078 data.rocker = rocker;3079 data.port = NULL;3080 priv.data = (void *)&data;3081 netdev_walk_all_lower_dev(dev, rocker_lower_dev_walk, &priv);3082 3083 return data.port;3084}3085 3086static int rocker_netdevice_event(struct notifier_block *unused,3087 unsigned long event, void *ptr)3088{3089 struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);3090 struct net_device *dev = netdev_notifier_info_to_dev(ptr);3091 struct netdev_notifier_changeupper_info *info;3092 struct rocker_port *rocker_port;3093 int err;3094 3095 if (!rocker_port_dev_check(dev))3096 return NOTIFY_DONE;3097 3098 switch (event) {3099 case NETDEV_CHANGEUPPER:3100 info = ptr;3101 if (!info->master)3102 goto out;3103 rocker_port = netdev_priv(dev);3104 if (info->linking) {3105 err = rocker_world_port_master_linked(rocker_port,3106 info->upper_dev,3107 extack);3108 if (err)3109 netdev_warn(dev, "failed to reflect master linked (err %d)\n",3110 err);3111 } else {3112 err = rocker_world_port_master_unlinked(rocker_port,3113 info->upper_dev);3114 if (err)3115 netdev_warn(dev, "failed to reflect master unlinked (err %d)\n",3116 err);3117 }3118 }3119out:3120 return NOTIFY_DONE;3121}3122 3123static struct notifier_block rocker_netdevice_nb __read_mostly = {3124 .notifier_call = rocker_netdevice_event,3125};3126 3127/************************************3128 * Net event notifier event handler3129 ************************************/3130 3131static int rocker_netevent_event(struct notifier_block *unused,3132 unsigned long event, void *ptr)3133{3134 struct rocker_port *rocker_port;3135 struct net_device *dev;3136 struct neighbour *n = ptr;3137 int err;3138 3139 switch (event) {3140 case NETEVENT_NEIGH_UPDATE:3141 if (n->tbl != &arp_tbl)3142 return NOTIFY_DONE;3143 dev = n->dev;3144 if (!rocker_port_dev_check(dev))3145 return NOTIFY_DONE;3146 rocker_port = netdev_priv(dev);3147 err = rocker_world_port_neigh_update(rocker_port, n);3148 if (err)3149 netdev_warn(dev, "failed to handle neigh update (err %d)\n",3150 err);3151 break;3152 }3153 3154 return NOTIFY_DONE;3155}3156 3157static struct notifier_block rocker_netevent_nb __read_mostly = {3158 .notifier_call = rocker_netevent_event,3159};3160 3161/***********************3162 * Module init and exit3163 ***********************/3164 3165static int __init rocker_module_init(void)3166{3167 int err;3168 3169 register_netdevice_notifier(&rocker_netdevice_nb);3170 register_netevent_notifier(&rocker_netevent_nb);3171 err = pci_register_driver(&rocker_pci_driver);3172 if (err)3173 goto err_pci_register_driver;3174 return 0;3175 3176err_pci_register_driver:3177 unregister_netevent_notifier(&rocker_netevent_nb);3178 unregister_netdevice_notifier(&rocker_netdevice_nb);3179 return err;3180}3181 3182static void __exit rocker_module_exit(void)3183{3184 unregister_netevent_notifier(&rocker_netevent_nb);3185 unregister_netdevice_notifier(&rocker_netdevice_nb);3186 pci_unregister_driver(&rocker_pci_driver);3187}3188 3189module_init(rocker_module_init);3190module_exit(rocker_module_exit);3191 3192MODULE_LICENSE("GPL v2");3193MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");3194MODULE_AUTHOR("Scott Feldman <sfeldma@gmail.com>");3195MODULE_DESCRIPTION("Rocker switch device driver");3196MODULE_DEVICE_TABLE(pci, rocker_pci_id_table);3197