1 /* 2 * QEMU rocker switch emulation - PCI device 3 * 4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> 5 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18 #include "qemu/osdep.h" 19 #include "hw/hw.h" 20 #include "hw/pci/pci.h" 21 #include "hw/pci/msix.h" 22 #include "net/net.h" 23 #include "net/eth.h" 24 #include "qemu/iov.h" 25 #include "qemu/bitops.h" 26 #include "qmp-commands.h" 27 28 #include "rocker.h" 29 #include "rocker_hw.h" 30 #include "rocker_fp.h" 31 #include "rocker_desc.h" 32 #include "rocker_tlv.h" 33 #include "rocker_world.h" 34 #include "rocker_of_dpa.h" 35 36 struct rocker { 37 /* private */ 38 PCIDevice parent_obj; 39 /* public */ 40 41 MemoryRegion mmio; 42 MemoryRegion msix_bar; 43 44 /* switch configuration */ 45 char *name; /* switch name */ 46 char *world_name; /* world name */ 47 uint32_t fp_ports; /* front-panel port count */ 48 NICPeers *fp_ports_peers; 49 MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */ 50 uint64_t switch_id; /* switch id */ 51 52 /* front-panel ports */ 53 FpPort *fp_port[ROCKER_FP_PORTS_MAX]; 54 55 /* register backings */ 56 uint32_t test_reg; 57 uint64_t test_reg64; 58 dma_addr_t test_dma_addr; 59 uint32_t test_dma_size; 60 uint64_t lower32; /* lower 32-bit val in 2-part 64-bit access */ 61 62 /* desc rings */ 63 DescRing **rings; 64 65 /* switch worlds */ 66 World *worlds[ROCKER_WORLD_TYPE_MAX]; 67 World *world_dflt; 68 69 QLIST_ENTRY(rocker) next; 70 }; 71 72 #define TYPE_ROCKER "rocker" 73 74 #define ROCKER(obj) \ 75 OBJECT_CHECK(Rocker, (obj), TYPE_ROCKER) 76 77 static QLIST_HEAD(, rocker) rockers; 78 79 Rocker *rocker_find(const char *name) 80 { 81 Rocker *r; 82 83 QLIST_FOREACH(r, &rockers, next) 84 if (strcmp(r->name, name) == 0) { 85 return r; 86 } 87 88 return NULL; 89 } 90 91 World *rocker_get_world(Rocker *r, enum rocker_world_type type) 92 { 93 if (type < ROCKER_WORLD_TYPE_MAX) { 94 return r->worlds[type]; 95 } 96 return NULL; 97 } 98 99 RockerSwitch *qmp_query_rocker(const char *name, Error **errp) 100 { 101 RockerSwitch *rocker; 102 Rocker *r; 103 104 r = rocker_find(name); 105 if (!r) { 106 error_setg(errp, "rocker %s not found", name); 107 return NULL; 108 } 109 110 rocker = g_new0(RockerSwitch, 1); 111 rocker->name = g_strdup(r->name); 112 rocker->id = r->switch_id; 113 rocker->ports = r->fp_ports; 114 115 return rocker; 116 } 117 118 RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) 119 { 120 RockerPortList *list = NULL; 121 Rocker *r; 122 int i; 123 124 r = rocker_find(name); 125 if (!r) { 126 error_setg(errp, "rocker %s not found", name); 127 return NULL; 128 } 129 130 for (i = r->fp_ports - 1; i >= 0; i--) { 131 RockerPortList *info = g_malloc0(sizeof(*info)); 132 info->value = g_malloc0(sizeof(*info->value)); 133 struct fp_port *port = r->fp_port[i]; 134 135 fp_port_get_info(port, info); 136 info->next = list; 137 list = info; 138 } 139 140 return list; 141 } 142 143 uint32_t rocker_fp_ports(Rocker *r) 144 { 145 return r->fp_ports; 146 } 147 148 static uint32_t rocker_get_pport_by_tx_ring(Rocker *r, 149 DescRing *ring) 150 { 151 return (desc_ring_index(ring) - 2) / 2 + 1; 152 } 153 154 static int tx_consume(Rocker *r, DescInfo *info) 155 { 156 PCIDevice *dev = PCI_DEVICE(r); 157 char *buf = desc_get_buf(info, true); 158 RockerTlv *tlv_frag; 159 RockerTlv *tlvs[ROCKER_TLV_TX_MAX + 1]; 160 struct iovec iov[ROCKER_TX_FRAGS_MAX] = { { 0, }, }; 161 uint32_t pport; 162 uint32_t port; 163 uint16_t tx_offload = ROCKER_TX_OFFLOAD_NONE; 164 uint16_t tx_l3_csum_off = 0; 165 uint16_t tx_tso_mss = 0; 166 uint16_t tx_tso_hdr_len = 0; 167 int iovcnt = 0; 168 int err = ROCKER_OK; 169 int rem; 170 int i; 171 172 if (!buf) { 173 return -ROCKER_ENXIO; 174 } 175 176 rocker_tlv_parse(tlvs, ROCKER_TLV_TX_MAX, buf, desc_tlv_size(info)); 177 178 if (!tlvs[ROCKER_TLV_TX_FRAGS]) { 179 return -ROCKER_EINVAL; 180 } 181 182 pport = rocker_get_pport_by_tx_ring(r, desc_get_ring(info)); 183 if (!fp_port_from_pport(pport, &port)) { 184 return -ROCKER_EINVAL; 185 } 186 187 if (tlvs[ROCKER_TLV_TX_OFFLOAD]) { 188 tx_offload = rocker_tlv_get_u8(tlvs[ROCKER_TLV_TX_OFFLOAD]); 189 } 190 191 switch (tx_offload) { 192 case ROCKER_TX_OFFLOAD_L3_CSUM: 193 if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) { 194 return -ROCKER_EINVAL; 195 } 196 break; 197 case ROCKER_TX_OFFLOAD_TSO: 198 if (!tlvs[ROCKER_TLV_TX_TSO_MSS] || 199 !tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) { 200 return -ROCKER_EINVAL; 201 } 202 break; 203 } 204 205 if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) { 206 tx_l3_csum_off = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]); 207 } 208 209 if (tlvs[ROCKER_TLV_TX_TSO_MSS]) { 210 tx_tso_mss = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_MSS]); 211 } 212 213 if (tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) { 214 tx_tso_hdr_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]); 215 } 216 217 rocker_tlv_for_each_nested(tlv_frag, tlvs[ROCKER_TLV_TX_FRAGS], rem) { 218 hwaddr frag_addr; 219 uint16_t frag_len; 220 221 if (rocker_tlv_type(tlv_frag) != ROCKER_TLV_TX_FRAG) { 222 err = -ROCKER_EINVAL; 223 goto err_bad_attr; 224 } 225 226 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_TX_FRAG_ATTR_MAX, tlv_frag); 227 228 if (!tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] || 229 !tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]) { 230 err = -ROCKER_EINVAL; 231 goto err_bad_attr; 232 } 233 234 frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]); 235 frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]); 236 237 if (iovcnt >= ROCKER_TX_FRAGS_MAX) { 238 goto err_too_many_frags; 239 } 240 iov[iovcnt].iov_len = frag_len; 241 iov[iovcnt].iov_base = g_malloc(frag_len); 242 243 pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base, 244 iov[iovcnt].iov_len); 245 246 iovcnt++; 247 } 248 249 if (iovcnt) { 250 /* XXX perform Tx offloads */ 251 /* XXX silence compiler for now */ 252 tx_l3_csum_off += tx_tso_mss = tx_tso_hdr_len = 0; 253 } 254 255 err = fp_port_eg(r->fp_port[port], iov, iovcnt); 256 257 err_too_many_frags: 258 err_bad_attr: 259 for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) { 260 g_free(iov[i].iov_base); 261 } 262 263 return err; 264 } 265 266 static int cmd_get_port_settings(Rocker *r, 267 DescInfo *info, char *buf, 268 RockerTlv *cmd_info_tlv) 269 { 270 RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1]; 271 RockerTlv *nest; 272 FpPort *fp_port; 273 uint32_t pport; 274 uint32_t port; 275 uint32_t speed; 276 uint8_t duplex; 277 uint8_t autoneg; 278 uint8_t learning; 279 char *phys_name; 280 MACAddr macaddr; 281 enum rocker_world_type mode; 282 size_t tlv_size; 283 int pos; 284 int err; 285 286 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX, 287 cmd_info_tlv); 288 289 if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) { 290 return -ROCKER_EINVAL; 291 } 292 293 pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]); 294 if (!fp_port_from_pport(pport, &port)) { 295 return -ROCKER_EINVAL; 296 } 297 fp_port = r->fp_port[port]; 298 299 err = fp_port_get_settings(fp_port, &speed, &duplex, &autoneg); 300 if (err) { 301 return err; 302 } 303 304 fp_port_get_macaddr(fp_port, &macaddr); 305 mode = world_type(fp_port_get_world(fp_port)); 306 learning = fp_port_get_learning(fp_port); 307 phys_name = fp_port_get_name(fp_port); 308 309 tlv_size = rocker_tlv_total_size(0) + /* nest */ 310 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ 311 rocker_tlv_total_size(sizeof(uint32_t)) + /* speed */ 312 rocker_tlv_total_size(sizeof(uint8_t)) + /* duplex */ 313 rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */ 314 rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */ 315 rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */ 316 rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */ 317 rocker_tlv_total_size(strlen(phys_name)); 318 319 if (tlv_size > desc_buf_size(info)) { 320 return -ROCKER_EMSGSIZE; 321 } 322 323 pos = 0; 324 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_CMD_INFO); 325 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, pport); 326 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, speed); 327 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, duplex); 328 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, autoneg); 329 rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, 330 sizeof(macaddr.a), macaddr.a); 331 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode); 332 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, 333 learning); 334 rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, 335 strlen(phys_name), phys_name); 336 rocker_tlv_nest_end(buf, &pos, nest); 337 338 return desc_set_buf(info, tlv_size); 339 } 340 341 static int cmd_set_port_settings(Rocker *r, 342 RockerTlv *cmd_info_tlv) 343 { 344 RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1]; 345 FpPort *fp_port; 346 uint32_t pport; 347 uint32_t port; 348 uint32_t speed; 349 uint8_t duplex; 350 uint8_t autoneg; 351 uint8_t learning; 352 MACAddr macaddr; 353 enum rocker_world_type mode; 354 int err; 355 356 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX, 357 cmd_info_tlv); 358 359 if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) { 360 return -ROCKER_EINVAL; 361 } 362 363 pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]); 364 if (!fp_port_from_pport(pport, &port)) { 365 return -ROCKER_EINVAL; 366 } 367 fp_port = r->fp_port[port]; 368 369 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] && 370 tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] && 371 tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]) { 372 373 speed = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]); 374 duplex = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]); 375 autoneg = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]); 376 377 err = fp_port_set_settings(fp_port, speed, duplex, autoneg); 378 if (err) { 379 return err; 380 } 381 } 382 383 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) { 384 if (rocker_tlv_len(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) != 385 sizeof(macaddr.a)) { 386 return -ROCKER_EINVAL; 387 } 388 memcpy(macaddr.a, 389 rocker_tlv_data(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]), 390 sizeof(macaddr.a)); 391 fp_port_set_macaddr(fp_port, &macaddr); 392 } 393 394 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) { 395 mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]); 396 if (mode >= ROCKER_WORLD_TYPE_MAX) { 397 return -ROCKER_EINVAL; 398 } 399 /* We don't support world change. */ 400 if (!fp_port_check_world(fp_port, r->worlds[mode])) { 401 return -ROCKER_EINVAL; 402 } 403 } 404 405 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) { 406 learning = 407 rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]); 408 fp_port_set_learning(fp_port, learning); 409 } 410 411 return ROCKER_OK; 412 } 413 414 static int cmd_consume(Rocker *r, DescInfo *info) 415 { 416 char *buf = desc_get_buf(info, false); 417 RockerTlv *tlvs[ROCKER_TLV_CMD_MAX + 1]; 418 RockerTlv *info_tlv; 419 World *world; 420 uint16_t cmd; 421 int err; 422 423 if (!buf) { 424 return -ROCKER_ENXIO; 425 } 426 427 rocker_tlv_parse(tlvs, ROCKER_TLV_CMD_MAX, buf, desc_tlv_size(info)); 428 429 if (!tlvs[ROCKER_TLV_CMD_TYPE] || !tlvs[ROCKER_TLV_CMD_INFO]) { 430 return -ROCKER_EINVAL; 431 } 432 433 cmd = rocker_tlv_get_le16(tlvs[ROCKER_TLV_CMD_TYPE]); 434 info_tlv = tlvs[ROCKER_TLV_CMD_INFO]; 435 436 /* This might be reworked to something like this: 437 * Every world will have an array of command handlers from 438 * ROCKER_TLV_CMD_TYPE_UNSPEC to ROCKER_TLV_CMD_TYPE_MAX. There is 439 * up to each world to implement whatever command it want. 440 * It can reference "generic" commands as cmd_set_port_settings or 441 * cmd_get_port_settings 442 */ 443 444 switch (cmd) { 445 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD: 446 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD: 447 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL: 448 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS: 449 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD: 450 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD: 451 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL: 452 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS: 453 world = r->worlds[ROCKER_WORLD_TYPE_OF_DPA]; 454 err = world_do_cmd(world, info, buf, cmd, info_tlv); 455 break; 456 case ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS: 457 err = cmd_get_port_settings(r, info, buf, info_tlv); 458 break; 459 case ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS: 460 err = cmd_set_port_settings(r, info_tlv); 461 break; 462 default: 463 err = -ROCKER_EINVAL; 464 break; 465 } 466 467 return err; 468 } 469 470 static void rocker_msix_irq(Rocker *r, unsigned vector) 471 { 472 PCIDevice *dev = PCI_DEVICE(r); 473 474 DPRINTF("MSI-X notify request for vector %d\n", vector); 475 if (vector >= ROCKER_MSIX_VEC_COUNT(r->fp_ports)) { 476 DPRINTF("incorrect vector %d\n", vector); 477 return; 478 } 479 msix_notify(dev, vector); 480 } 481 482 int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up) 483 { 484 DescRing *ring = r->rings[ROCKER_RING_EVENT]; 485 DescInfo *info = desc_ring_fetch_desc(ring); 486 RockerTlv *nest; 487 char *buf; 488 size_t tlv_size; 489 int pos; 490 int err; 491 492 if (!info) { 493 return -ROCKER_ENOBUFS; 494 } 495 496 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */ 497 rocker_tlv_total_size(0) + /* nest */ 498 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ 499 rocker_tlv_total_size(sizeof(uint8_t)); /* link up */ 500 501 if (tlv_size > desc_buf_size(info)) { 502 err = -ROCKER_EMSGSIZE; 503 goto err_too_big; 504 } 505 506 buf = desc_get_buf(info, false); 507 if (!buf) { 508 err = -ROCKER_ENOMEM; 509 goto err_no_mem; 510 } 511 512 pos = 0; 513 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE, 514 ROCKER_TLV_EVENT_TYPE_LINK_CHANGED); 515 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO); 516 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, pport); 517 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP, 518 link_up ? 1 : 0); 519 rocker_tlv_nest_end(buf, &pos, nest); 520 521 err = desc_set_buf(info, tlv_size); 522 523 err_too_big: 524 err_no_mem: 525 if (desc_ring_post_desc(ring, err)) { 526 rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT); 527 } 528 529 return err; 530 } 531 532 int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr, 533 uint16_t vlan_id) 534 { 535 DescRing *ring = r->rings[ROCKER_RING_EVENT]; 536 DescInfo *info; 537 FpPort *fp_port; 538 uint32_t port; 539 RockerTlv *nest; 540 char *buf; 541 size_t tlv_size; 542 int pos; 543 int err; 544 545 if (!fp_port_from_pport(pport, &port)) { 546 return -ROCKER_EINVAL; 547 } 548 fp_port = r->fp_port[port]; 549 if (!fp_port_get_learning(fp_port)) { 550 return ROCKER_OK; 551 } 552 553 info = desc_ring_fetch_desc(ring); 554 if (!info) { 555 return -ROCKER_ENOBUFS; 556 } 557 558 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */ 559 rocker_tlv_total_size(0) + /* nest */ 560 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ 561 rocker_tlv_total_size(ETH_ALEN) + /* mac addr */ 562 rocker_tlv_total_size(sizeof(uint16_t)); /* vlan_id */ 563 564 if (tlv_size > desc_buf_size(info)) { 565 err = -ROCKER_EMSGSIZE; 566 goto err_too_big; 567 } 568 569 buf = desc_get_buf(info, false); 570 if (!buf) { 571 err = -ROCKER_ENOMEM; 572 goto err_no_mem; 573 } 574 575 pos = 0; 576 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE, 577 ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN); 578 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO); 579 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_PPORT, pport); 580 rocker_tlv_put(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_MAC, ETH_ALEN, addr); 581 rocker_tlv_put_u16(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, vlan_id); 582 rocker_tlv_nest_end(buf, &pos, nest); 583 584 err = desc_set_buf(info, tlv_size); 585 586 err_too_big: 587 err_no_mem: 588 if (desc_ring_post_desc(ring, err)) { 589 rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT); 590 } 591 592 return err; 593 } 594 595 static DescRing *rocker_get_rx_ring_by_pport(Rocker *r, 596 uint32_t pport) 597 { 598 return r->rings[(pport - 1) * 2 + 3]; 599 } 600 601 int rx_produce(World *world, uint32_t pport, 602 const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu) 603 { 604 Rocker *r = world_rocker(world); 605 PCIDevice *dev = (PCIDevice *)r; 606 DescRing *ring = rocker_get_rx_ring_by_pport(r, pport); 607 DescInfo *info = desc_ring_fetch_desc(ring); 608 char *data; 609 size_t data_size = iov_size(iov, iovcnt); 610 char *buf; 611 uint16_t rx_flags = 0; 612 uint16_t rx_csum = 0; 613 size_t tlv_size; 614 RockerTlv *tlvs[ROCKER_TLV_RX_MAX + 1]; 615 hwaddr frag_addr; 616 uint16_t frag_max_len; 617 int pos; 618 int err; 619 620 if (!info) { 621 return -ROCKER_ENOBUFS; 622 } 623 624 buf = desc_get_buf(info, false); 625 if (!buf) { 626 err = -ROCKER_ENXIO; 627 goto out; 628 } 629 rocker_tlv_parse(tlvs, ROCKER_TLV_RX_MAX, buf, desc_tlv_size(info)); 630 631 if (!tlvs[ROCKER_TLV_RX_FRAG_ADDR] || 632 !tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]) { 633 err = -ROCKER_EINVAL; 634 goto out; 635 } 636 637 frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_RX_FRAG_ADDR]); 638 frag_max_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]); 639 640 if (data_size > frag_max_len) { 641 err = -ROCKER_EMSGSIZE; 642 goto out; 643 } 644 645 if (copy_to_cpu) { 646 rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD; 647 } 648 649 /* XXX calc rx flags/csum */ 650 651 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */ 652 rocker_tlv_total_size(sizeof(uint16_t)) + /* scum */ 653 rocker_tlv_total_size(sizeof(uint64_t)) + /* frag addr */ 654 rocker_tlv_total_size(sizeof(uint16_t)) + /* frag max len */ 655 rocker_tlv_total_size(sizeof(uint16_t)); /* frag len */ 656 657 if (tlv_size > desc_buf_size(info)) { 658 err = -ROCKER_EMSGSIZE; 659 goto out; 660 } 661 662 /* TODO: 663 * iov dma write can be optimized in similar way e1000 does it in 664 * e1000_receive_iov. But maybe if would make sense to introduce 665 * generic helper iov_dma_write. 666 */ 667 668 data = g_malloc(data_size); 669 670 iov_to_buf(iov, iovcnt, 0, data, data_size); 671 pci_dma_write(dev, frag_addr, data, data_size); 672 g_free(data); 673 674 pos = 0; 675 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FLAGS, rx_flags); 676 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_CSUM, rx_csum); 677 rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_RX_FRAG_ADDR, frag_addr); 678 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_MAX_LEN, frag_max_len); 679 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_LEN, data_size); 680 681 err = desc_set_buf(info, tlv_size); 682 683 out: 684 if (desc_ring_post_desc(ring, err)) { 685 rocker_msix_irq(r, ROCKER_MSIX_VEC_RX(pport - 1)); 686 } 687 688 return err; 689 } 690 691 int rocker_port_eg(Rocker *r, uint32_t pport, 692 const struct iovec *iov, int iovcnt) 693 { 694 FpPort *fp_port; 695 uint32_t port; 696 697 if (!fp_port_from_pport(pport, &port)) { 698 return -ROCKER_EINVAL; 699 } 700 701 fp_port = r->fp_port[port]; 702 703 return fp_port_eg(fp_port, iov, iovcnt); 704 } 705 706 static void rocker_test_dma_ctrl(Rocker *r, uint32_t val) 707 { 708 PCIDevice *dev = PCI_DEVICE(r); 709 char *buf; 710 int i; 711 712 buf = g_malloc(r->test_dma_size); 713 714 switch (val) { 715 case ROCKER_TEST_DMA_CTRL_CLEAR: 716 memset(buf, 0, r->test_dma_size); 717 break; 718 case ROCKER_TEST_DMA_CTRL_FILL: 719 memset(buf, 0x96, r->test_dma_size); 720 break; 721 case ROCKER_TEST_DMA_CTRL_INVERT: 722 pci_dma_read(dev, r->test_dma_addr, buf, r->test_dma_size); 723 for (i = 0; i < r->test_dma_size; i++) { 724 buf[i] = ~buf[i]; 725 } 726 break; 727 default: 728 DPRINTF("not test dma control val=0x%08x\n", val); 729 goto err_out; 730 } 731 pci_dma_write(dev, r->test_dma_addr, buf, r->test_dma_size); 732 733 rocker_msix_irq(r, ROCKER_MSIX_VEC_TEST); 734 735 err_out: 736 g_free(buf); 737 } 738 739 static void rocker_reset(DeviceState *dev); 740 741 static void rocker_control(Rocker *r, uint32_t val) 742 { 743 if (val & ROCKER_CONTROL_RESET) { 744 rocker_reset(DEVICE(r)); 745 } 746 } 747 748 static int rocker_pci_ring_count(Rocker *r) 749 { 750 /* There are: 751 * - command ring 752 * - event ring 753 * - tx and rx ring per each port 754 */ 755 return 2 + (2 * r->fp_ports); 756 } 757 758 static bool rocker_addr_is_desc_reg(Rocker *r, hwaddr addr) 759 { 760 hwaddr start = ROCKER_DMA_DESC_BASE; 761 hwaddr end = start + (ROCKER_DMA_DESC_SIZE * rocker_pci_ring_count(r)); 762 763 return addr >= start && addr < end; 764 } 765 766 static void rocker_port_phys_enable_write(Rocker *r, uint64_t new) 767 { 768 int i; 769 bool old_enabled; 770 bool new_enabled; 771 FpPort *fp_port; 772 773 for (i = 0; i < r->fp_ports; i++) { 774 fp_port = r->fp_port[i]; 775 old_enabled = fp_port_enabled(fp_port); 776 new_enabled = (new >> (i + 1)) & 0x1; 777 if (new_enabled == old_enabled) { 778 continue; 779 } 780 if (new_enabled) { 781 fp_port_enable(r->fp_port[i]); 782 } else { 783 fp_port_disable(r->fp_port[i]); 784 } 785 } 786 } 787 788 static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val) 789 { 790 Rocker *r = opaque; 791 792 if (rocker_addr_is_desc_reg(r, addr)) { 793 unsigned index = ROCKER_RING_INDEX(addr); 794 unsigned offset = addr & ROCKER_DMA_DESC_MASK; 795 796 switch (offset) { 797 case ROCKER_DMA_DESC_ADDR_OFFSET: 798 r->lower32 = (uint64_t)val; 799 break; 800 case ROCKER_DMA_DESC_ADDR_OFFSET + 4: 801 desc_ring_set_base_addr(r->rings[index], 802 ((uint64_t)val) << 32 | r->lower32); 803 r->lower32 = 0; 804 break; 805 case ROCKER_DMA_DESC_SIZE_OFFSET: 806 desc_ring_set_size(r->rings[index], val); 807 break; 808 case ROCKER_DMA_DESC_HEAD_OFFSET: 809 if (desc_ring_set_head(r->rings[index], val)) { 810 rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index])); 811 } 812 break; 813 case ROCKER_DMA_DESC_CTRL_OFFSET: 814 desc_ring_set_ctrl(r->rings[index], val); 815 break; 816 case ROCKER_DMA_DESC_CREDITS_OFFSET: 817 if (desc_ring_ret_credits(r->rings[index], val)) { 818 rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index])); 819 } 820 break; 821 default: 822 DPRINTF("not implemented dma reg write(l) addr=0x" TARGET_FMT_plx 823 " val=0x%08x (ring %d, addr=0x%02x)\n", 824 addr, val, index, offset); 825 break; 826 } 827 return; 828 } 829 830 switch (addr) { 831 case ROCKER_TEST_REG: 832 r->test_reg = val; 833 break; 834 case ROCKER_TEST_REG64: 835 case ROCKER_TEST_DMA_ADDR: 836 case ROCKER_PORT_PHYS_ENABLE: 837 r->lower32 = (uint64_t)val; 838 break; 839 case ROCKER_TEST_REG64 + 4: 840 r->test_reg64 = ((uint64_t)val) << 32 | r->lower32; 841 r->lower32 = 0; 842 break; 843 case ROCKER_TEST_IRQ: 844 rocker_msix_irq(r, val); 845 break; 846 case ROCKER_TEST_DMA_SIZE: 847 r->test_dma_size = val & 0xFFFF; 848 break; 849 case ROCKER_TEST_DMA_ADDR + 4: 850 r->test_dma_addr = ((uint64_t)val) << 32 | r->lower32; 851 r->lower32 = 0; 852 break; 853 case ROCKER_TEST_DMA_CTRL: 854 rocker_test_dma_ctrl(r, val); 855 break; 856 case ROCKER_CONTROL: 857 rocker_control(r, val); 858 break; 859 case ROCKER_PORT_PHYS_ENABLE + 4: 860 rocker_port_phys_enable_write(r, ((uint64_t)val) << 32 | r->lower32); 861 r->lower32 = 0; 862 break; 863 default: 864 DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx 865 " val=0x%08x\n", addr, val); 866 break; 867 } 868 } 869 870 static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val) 871 { 872 Rocker *r = opaque; 873 874 if (rocker_addr_is_desc_reg(r, addr)) { 875 unsigned index = ROCKER_RING_INDEX(addr); 876 unsigned offset = addr & ROCKER_DMA_DESC_MASK; 877 878 switch (offset) { 879 case ROCKER_DMA_DESC_ADDR_OFFSET: 880 desc_ring_set_base_addr(r->rings[index], val); 881 break; 882 default: 883 DPRINTF("not implemented dma reg write(q) addr=0x" TARGET_FMT_plx 884 " val=0x" TARGET_FMT_plx " (ring %d, offset=0x%02x)\n", 885 addr, val, index, offset); 886 break; 887 } 888 return; 889 } 890 891 switch (addr) { 892 case ROCKER_TEST_REG64: 893 r->test_reg64 = val; 894 break; 895 case ROCKER_TEST_DMA_ADDR: 896 r->test_dma_addr = val; 897 break; 898 case ROCKER_PORT_PHYS_ENABLE: 899 rocker_port_phys_enable_write(r, val); 900 break; 901 default: 902 DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx 903 " val=0x" TARGET_FMT_plx "\n", addr, val); 904 break; 905 } 906 } 907 908 #ifdef DEBUG_ROCKER 909 #define regname(reg) case (reg): return #reg 910 static const char *rocker_reg_name(void *opaque, hwaddr addr) 911 { 912 Rocker *r = opaque; 913 914 if (rocker_addr_is_desc_reg(r, addr)) { 915 unsigned index = ROCKER_RING_INDEX(addr); 916 unsigned offset = addr & ROCKER_DMA_DESC_MASK; 917 static char buf[100]; 918 char ring_name[10]; 919 920 switch (index) { 921 case 0: 922 sprintf(ring_name, "cmd"); 923 break; 924 case 1: 925 sprintf(ring_name, "event"); 926 break; 927 default: 928 sprintf(ring_name, "%s-%d", index % 2 ? "rx" : "tx", 929 (index - 2) / 2); 930 } 931 932 switch (offset) { 933 case ROCKER_DMA_DESC_ADDR_OFFSET: 934 sprintf(buf, "Ring[%s] ADDR", ring_name); 935 return buf; 936 case ROCKER_DMA_DESC_ADDR_OFFSET+4: 937 sprintf(buf, "Ring[%s] ADDR+4", ring_name); 938 return buf; 939 case ROCKER_DMA_DESC_SIZE_OFFSET: 940 sprintf(buf, "Ring[%s] SIZE", ring_name); 941 return buf; 942 case ROCKER_DMA_DESC_HEAD_OFFSET: 943 sprintf(buf, "Ring[%s] HEAD", ring_name); 944 return buf; 945 case ROCKER_DMA_DESC_TAIL_OFFSET: 946 sprintf(buf, "Ring[%s] TAIL", ring_name); 947 return buf; 948 case ROCKER_DMA_DESC_CTRL_OFFSET: 949 sprintf(buf, "Ring[%s] CTRL", ring_name); 950 return buf; 951 case ROCKER_DMA_DESC_CREDITS_OFFSET: 952 sprintf(buf, "Ring[%s] CREDITS", ring_name); 953 return buf; 954 default: 955 sprintf(buf, "Ring[%s] ???", ring_name); 956 return buf; 957 } 958 } else { 959 switch (addr) { 960 regname(ROCKER_BOGUS_REG0); 961 regname(ROCKER_BOGUS_REG1); 962 regname(ROCKER_BOGUS_REG2); 963 regname(ROCKER_BOGUS_REG3); 964 regname(ROCKER_TEST_REG); 965 regname(ROCKER_TEST_REG64); 966 regname(ROCKER_TEST_REG64+4); 967 regname(ROCKER_TEST_IRQ); 968 regname(ROCKER_TEST_DMA_ADDR); 969 regname(ROCKER_TEST_DMA_ADDR+4); 970 regname(ROCKER_TEST_DMA_SIZE); 971 regname(ROCKER_TEST_DMA_CTRL); 972 regname(ROCKER_CONTROL); 973 regname(ROCKER_PORT_PHYS_COUNT); 974 regname(ROCKER_PORT_PHYS_LINK_STATUS); 975 regname(ROCKER_PORT_PHYS_LINK_STATUS+4); 976 regname(ROCKER_PORT_PHYS_ENABLE); 977 regname(ROCKER_PORT_PHYS_ENABLE+4); 978 regname(ROCKER_SWITCH_ID); 979 regname(ROCKER_SWITCH_ID+4); 980 } 981 } 982 return "???"; 983 } 984 #else 985 static const char *rocker_reg_name(void *opaque, hwaddr addr) 986 { 987 return NULL; 988 } 989 #endif 990 991 static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val, 992 unsigned size) 993 { 994 DPRINTF("Write %s addr " TARGET_FMT_plx 995 ", size %u, val " TARGET_FMT_plx "\n", 996 rocker_reg_name(opaque, addr), addr, size, val); 997 998 switch (size) { 999 case 4: 1000 rocker_io_writel(opaque, addr, val); 1001 break; 1002 case 8: 1003 rocker_io_writeq(opaque, addr, val); 1004 break; 1005 } 1006 } 1007 1008 static uint64_t rocker_port_phys_link_status(Rocker *r) 1009 { 1010 int i; 1011 uint64_t status = 0; 1012 1013 for (i = 0; i < r->fp_ports; i++) { 1014 FpPort *port = r->fp_port[i]; 1015 1016 if (fp_port_get_link_up(port)) { 1017 status |= 1 << (i + 1); 1018 } 1019 } 1020 return status; 1021 } 1022 1023 static uint64_t rocker_port_phys_enable_read(Rocker *r) 1024 { 1025 int i; 1026 uint64_t ret = 0; 1027 1028 for (i = 0; i < r->fp_ports; i++) { 1029 FpPort *port = r->fp_port[i]; 1030 1031 if (fp_port_enabled(port)) { 1032 ret |= 1 << (i + 1); 1033 } 1034 } 1035 return ret; 1036 } 1037 1038 static uint32_t rocker_io_readl(void *opaque, hwaddr addr) 1039 { 1040 Rocker *r = opaque; 1041 uint32_t ret; 1042 1043 if (rocker_addr_is_desc_reg(r, addr)) { 1044 unsigned index = ROCKER_RING_INDEX(addr); 1045 unsigned offset = addr & ROCKER_DMA_DESC_MASK; 1046 1047 switch (offset) { 1048 case ROCKER_DMA_DESC_ADDR_OFFSET: 1049 ret = (uint32_t)desc_ring_get_base_addr(r->rings[index]); 1050 break; 1051 case ROCKER_DMA_DESC_ADDR_OFFSET + 4: 1052 ret = (uint32_t)(desc_ring_get_base_addr(r->rings[index]) >> 32); 1053 break; 1054 case ROCKER_DMA_DESC_SIZE_OFFSET: 1055 ret = desc_ring_get_size(r->rings[index]); 1056 break; 1057 case ROCKER_DMA_DESC_HEAD_OFFSET: 1058 ret = desc_ring_get_head(r->rings[index]); 1059 break; 1060 case ROCKER_DMA_DESC_TAIL_OFFSET: 1061 ret = desc_ring_get_tail(r->rings[index]); 1062 break; 1063 case ROCKER_DMA_DESC_CREDITS_OFFSET: 1064 ret = desc_ring_get_credits(r->rings[index]); 1065 break; 1066 default: 1067 DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx 1068 " (ring %d, addr=0x%02x)\n", addr, index, offset); 1069 ret = 0; 1070 break; 1071 } 1072 return ret; 1073 } 1074 1075 switch (addr) { 1076 case ROCKER_BOGUS_REG0: 1077 case ROCKER_BOGUS_REG1: 1078 case ROCKER_BOGUS_REG2: 1079 case ROCKER_BOGUS_REG3: 1080 ret = 0xDEADBABE; 1081 break; 1082 case ROCKER_TEST_REG: 1083 ret = r->test_reg * 2; 1084 break; 1085 case ROCKER_TEST_REG64: 1086 ret = (uint32_t)(r->test_reg64 * 2); 1087 break; 1088 case ROCKER_TEST_REG64 + 4: 1089 ret = (uint32_t)((r->test_reg64 * 2) >> 32); 1090 break; 1091 case ROCKER_TEST_DMA_SIZE: 1092 ret = r->test_dma_size; 1093 break; 1094 case ROCKER_TEST_DMA_ADDR: 1095 ret = (uint32_t)r->test_dma_addr; 1096 break; 1097 case ROCKER_TEST_DMA_ADDR + 4: 1098 ret = (uint32_t)(r->test_dma_addr >> 32); 1099 break; 1100 case ROCKER_PORT_PHYS_COUNT: 1101 ret = r->fp_ports; 1102 break; 1103 case ROCKER_PORT_PHYS_LINK_STATUS: 1104 ret = (uint32_t)rocker_port_phys_link_status(r); 1105 break; 1106 case ROCKER_PORT_PHYS_LINK_STATUS + 4: 1107 ret = (uint32_t)(rocker_port_phys_link_status(r) >> 32); 1108 break; 1109 case ROCKER_PORT_PHYS_ENABLE: 1110 ret = (uint32_t)rocker_port_phys_enable_read(r); 1111 break; 1112 case ROCKER_PORT_PHYS_ENABLE + 4: 1113 ret = (uint32_t)(rocker_port_phys_enable_read(r) >> 32); 1114 break; 1115 case ROCKER_SWITCH_ID: 1116 ret = (uint32_t)r->switch_id; 1117 break; 1118 case ROCKER_SWITCH_ID + 4: 1119 ret = (uint32_t)(r->switch_id >> 32); 1120 break; 1121 default: 1122 DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx "\n", addr); 1123 ret = 0; 1124 break; 1125 } 1126 return ret; 1127 } 1128 1129 static uint64_t rocker_io_readq(void *opaque, hwaddr addr) 1130 { 1131 Rocker *r = opaque; 1132 uint64_t ret; 1133 1134 if (rocker_addr_is_desc_reg(r, addr)) { 1135 unsigned index = ROCKER_RING_INDEX(addr); 1136 unsigned offset = addr & ROCKER_DMA_DESC_MASK; 1137 1138 switch (addr & ROCKER_DMA_DESC_MASK) { 1139 case ROCKER_DMA_DESC_ADDR_OFFSET: 1140 ret = desc_ring_get_base_addr(r->rings[index]); 1141 break; 1142 default: 1143 DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx 1144 " (ring %d, addr=0x%02x)\n", addr, index, offset); 1145 ret = 0; 1146 break; 1147 } 1148 return ret; 1149 } 1150 1151 switch (addr) { 1152 case ROCKER_BOGUS_REG0: 1153 case ROCKER_BOGUS_REG2: 1154 ret = 0xDEADBABEDEADBABEULL; 1155 break; 1156 case ROCKER_TEST_REG64: 1157 ret = r->test_reg64 * 2; 1158 break; 1159 case ROCKER_TEST_DMA_ADDR: 1160 ret = r->test_dma_addr; 1161 break; 1162 case ROCKER_PORT_PHYS_LINK_STATUS: 1163 ret = rocker_port_phys_link_status(r); 1164 break; 1165 case ROCKER_PORT_PHYS_ENABLE: 1166 ret = rocker_port_phys_enable_read(r); 1167 break; 1168 case ROCKER_SWITCH_ID: 1169 ret = r->switch_id; 1170 break; 1171 default: 1172 DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx "\n", addr); 1173 ret = 0; 1174 break; 1175 } 1176 return ret; 1177 } 1178 1179 static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size) 1180 { 1181 DPRINTF("Read %s addr " TARGET_FMT_plx ", size %u\n", 1182 rocker_reg_name(opaque, addr), addr, size); 1183 1184 switch (size) { 1185 case 4: 1186 return rocker_io_readl(opaque, addr); 1187 case 8: 1188 return rocker_io_readq(opaque, addr); 1189 } 1190 1191 return -1; 1192 } 1193 1194 static const MemoryRegionOps rocker_mmio_ops = { 1195 .read = rocker_mmio_read, 1196 .write = rocker_mmio_write, 1197 .endianness = DEVICE_LITTLE_ENDIAN, 1198 .valid = { 1199 .min_access_size = 4, 1200 .max_access_size = 8, 1201 }, 1202 .impl = { 1203 .min_access_size = 4, 1204 .max_access_size = 8, 1205 }, 1206 }; 1207 1208 static void rocker_msix_vectors_unuse(Rocker *r, 1209 unsigned int num_vectors) 1210 { 1211 PCIDevice *dev = PCI_DEVICE(r); 1212 int i; 1213 1214 for (i = 0; i < num_vectors; i++) { 1215 msix_vector_unuse(dev, i); 1216 } 1217 } 1218 1219 static int rocker_msix_vectors_use(Rocker *r, 1220 unsigned int num_vectors) 1221 { 1222 PCIDevice *dev = PCI_DEVICE(r); 1223 int err; 1224 int i; 1225 1226 for (i = 0; i < num_vectors; i++) { 1227 err = msix_vector_use(dev, i); 1228 if (err) { 1229 goto rollback; 1230 } 1231 } 1232 return 0; 1233 1234 rollback: 1235 rocker_msix_vectors_unuse(r, i); 1236 return err; 1237 } 1238 1239 static int rocker_msix_init(Rocker *r, Error **errp) 1240 { 1241 PCIDevice *dev = PCI_DEVICE(r); 1242 int err; 1243 1244 err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports), 1245 &r->msix_bar, 1246 ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET, 1247 &r->msix_bar, 1248 ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET, 1249 0, errp); 1250 if (err) { 1251 return err; 1252 } 1253 1254 err = rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports)); 1255 if (err) { 1256 goto err_msix_vectors_use; 1257 } 1258 1259 return 0; 1260 1261 err_msix_vectors_use: 1262 msix_uninit(dev, &r->msix_bar, &r->msix_bar); 1263 return err; 1264 } 1265 1266 static void rocker_msix_uninit(Rocker *r) 1267 { 1268 PCIDevice *dev = PCI_DEVICE(r); 1269 1270 msix_uninit(dev, &r->msix_bar, &r->msix_bar); 1271 rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports)); 1272 } 1273 1274 static World *rocker_world_type_by_name(Rocker *r, const char *name) 1275 { 1276 int i; 1277 1278 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { 1279 if (strcmp(name, world_name(r->worlds[i])) == 0) { 1280 return r->worlds[i]; 1281 } 1282 } 1283 return NULL; 1284 } 1285 1286 static void pci_rocker_realize(PCIDevice *dev, Error **errp) 1287 { 1288 Rocker *r = ROCKER(dev); 1289 const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } }; 1290 const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } }; 1291 static int sw_index; 1292 int i, err = 0; 1293 1294 /* allocate worlds */ 1295 1296 r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r); 1297 1298 if (!r->world_name) { 1299 r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA])); 1300 } 1301 1302 r->world_dflt = rocker_world_type_by_name(r, r->world_name); 1303 if (!r->world_dflt) { 1304 error_setg(errp, 1305 "invalid argument requested world %s does not exist", 1306 r->world_name); 1307 goto err_world_type_by_name; 1308 } 1309 1310 /* set up memory-mapped region at BAR0 */ 1311 1312 memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r, 1313 "rocker-mmio", ROCKER_PCI_BAR0_SIZE); 1314 pci_register_bar(dev, ROCKER_PCI_BAR0_IDX, 1315 PCI_BASE_ADDRESS_SPACE_MEMORY, &r->mmio); 1316 1317 /* set up memory-mapped region for MSI-X */ 1318 1319 memory_region_init(&r->msix_bar, OBJECT(r), "rocker-msix-bar", 1320 ROCKER_PCI_MSIX_BAR_SIZE); 1321 pci_register_bar(dev, ROCKER_PCI_MSIX_BAR_IDX, 1322 PCI_BASE_ADDRESS_SPACE_MEMORY, &r->msix_bar); 1323 1324 /* MSI-X init */ 1325 1326 err = rocker_msix_init(r, errp); 1327 if (err) { 1328 goto err_msix_init; 1329 } 1330 1331 /* validate switch properties */ 1332 1333 if (!r->name) { 1334 r->name = g_strdup(TYPE_ROCKER); 1335 } 1336 1337 if (rocker_find(r->name)) { 1338 error_setg(errp, "%s already exists", r->name); 1339 goto err_duplicate; 1340 } 1341 1342 /* Rocker name is passed in port name requests to OS with the intention 1343 * that the name is used in interface names. Limit the length of the 1344 * rocker name to avoid naming problems in the OS. Also, adding the 1345 * port number as p# and unganged breakout b#, where # is at most 2 1346 * digits, so leave room for it too (-1 for string terminator, -3 for 1347 * p# and -3 for b#) 1348 */ 1349 #define ROCKER_IFNAMSIZ 16 1350 #define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3) 1351 if (strlen(r->name) > MAX_ROCKER_NAME_LEN) { 1352 error_setg(errp, 1353 "name too long; please shorten to at most %d chars", 1354 MAX_ROCKER_NAME_LEN); 1355 goto err_name_too_long; 1356 } 1357 1358 if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) { 1359 memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt)); 1360 r->fp_start_macaddr.a[4] += (sw_index++); 1361 } 1362 1363 if (!r->switch_id) { 1364 memcpy(&r->switch_id, &r->fp_start_macaddr, 1365 sizeof(r->fp_start_macaddr)); 1366 } 1367 1368 if (r->fp_ports > ROCKER_FP_PORTS_MAX) { 1369 r->fp_ports = ROCKER_FP_PORTS_MAX; 1370 } 1371 1372 r->rings = g_new(DescRing *, rocker_pci_ring_count(r)); 1373 1374 /* Rings are ordered like this: 1375 * - command ring 1376 * - event ring 1377 * - port0 tx ring 1378 * - port0 rx ring 1379 * - port1 tx ring 1380 * - port1 rx ring 1381 * ..... 1382 */ 1383 1384 for (i = 0; i < rocker_pci_ring_count(r); i++) { 1385 DescRing *ring = desc_ring_alloc(r, i); 1386 1387 if (i == ROCKER_RING_CMD) { 1388 desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD); 1389 } else if (i == ROCKER_RING_EVENT) { 1390 desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_EVENT); 1391 } else if (i % 2 == 0) { 1392 desc_ring_set_consume(ring, tx_consume, 1393 ROCKER_MSIX_VEC_TX((i - 2) / 2)); 1394 } else if (i % 2 == 1) { 1395 desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_RX((i - 3) / 2)); 1396 } 1397 1398 r->rings[i] = ring; 1399 } 1400 1401 for (i = 0; i < r->fp_ports; i++) { 1402 FpPort *port = 1403 fp_port_alloc(r, r->name, &r->fp_start_macaddr, 1404 i, &r->fp_ports_peers[i]); 1405 1406 r->fp_port[i] = port; 1407 fp_port_set_world(port, r->world_dflt); 1408 } 1409 1410 QLIST_INSERT_HEAD(&rockers, r, next); 1411 1412 return; 1413 1414 err_name_too_long: 1415 err_duplicate: 1416 rocker_msix_uninit(r); 1417 err_msix_init: 1418 object_unparent(OBJECT(&r->msix_bar)); 1419 object_unparent(OBJECT(&r->mmio)); 1420 err_world_type_by_name: 1421 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { 1422 if (r->worlds[i]) { 1423 world_free(r->worlds[i]); 1424 } 1425 } 1426 } 1427 1428 static void pci_rocker_uninit(PCIDevice *dev) 1429 { 1430 Rocker *r = ROCKER(dev); 1431 int i; 1432 1433 QLIST_REMOVE(r, next); 1434 1435 for (i = 0; i < r->fp_ports; i++) { 1436 FpPort *port = r->fp_port[i]; 1437 1438 fp_port_free(port); 1439 r->fp_port[i] = NULL; 1440 } 1441 1442 for (i = 0; i < rocker_pci_ring_count(r); i++) { 1443 if (r->rings[i]) { 1444 desc_ring_free(r->rings[i]); 1445 } 1446 } 1447 g_free(r->rings); 1448 1449 rocker_msix_uninit(r); 1450 object_unparent(OBJECT(&r->msix_bar)); 1451 object_unparent(OBJECT(&r->mmio)); 1452 1453 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { 1454 if (r->worlds[i]) { 1455 world_free(r->worlds[i]); 1456 } 1457 } 1458 g_free(r->fp_ports_peers); 1459 } 1460 1461 static void rocker_reset(DeviceState *dev) 1462 { 1463 Rocker *r = ROCKER(dev); 1464 int i; 1465 1466 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { 1467 if (r->worlds[i]) { 1468 world_reset(r->worlds[i]); 1469 } 1470 } 1471 for (i = 0; i < r->fp_ports; i++) { 1472 fp_port_reset(r->fp_port[i]); 1473 fp_port_set_world(r->fp_port[i], r->world_dflt); 1474 } 1475 1476 r->test_reg = 0; 1477 r->test_reg64 = 0; 1478 r->test_dma_addr = 0; 1479 r->test_dma_size = 0; 1480 1481 for (i = 0; i < rocker_pci_ring_count(r); i++) { 1482 desc_ring_reset(r->rings[i]); 1483 } 1484 1485 DPRINTF("Reset done\n"); 1486 } 1487 1488 static Property rocker_properties[] = { 1489 DEFINE_PROP_STRING("name", Rocker, name), 1490 DEFINE_PROP_STRING("world", Rocker, world_name), 1491 DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker, 1492 fp_start_macaddr), 1493 DEFINE_PROP_UINT64("switch_id", Rocker, 1494 switch_id, 0), 1495 DEFINE_PROP_ARRAY("ports", Rocker, fp_ports, 1496 fp_ports_peers, qdev_prop_netdev, NICPeers), 1497 DEFINE_PROP_END_OF_LIST(), 1498 }; 1499 1500 static const VMStateDescription rocker_vmsd = { 1501 .name = TYPE_ROCKER, 1502 .unmigratable = 1, 1503 }; 1504 1505 static void rocker_class_init(ObjectClass *klass, void *data) 1506 { 1507 DeviceClass *dc = DEVICE_CLASS(klass); 1508 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 1509 1510 k->realize = pci_rocker_realize; 1511 k->exit = pci_rocker_uninit; 1512 k->vendor_id = PCI_VENDOR_ID_REDHAT; 1513 k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER; 1514 k->revision = ROCKER_PCI_REVISION; 1515 k->class_id = PCI_CLASS_NETWORK_OTHER; 1516 set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 1517 dc->desc = "Rocker Switch"; 1518 dc->reset = rocker_reset; 1519 dc->props = rocker_properties; 1520 dc->vmsd = &rocker_vmsd; 1521 } 1522 1523 static const TypeInfo rocker_info = { 1524 .name = TYPE_ROCKER, 1525 .parent = TYPE_PCI_DEVICE, 1526 .instance_size = sizeof(Rocker), 1527 .class_init = rocker_class_init, 1528 }; 1529 1530 static void rocker_register_types(void) 1531 { 1532 type_register_static(&rocker_info); 1533 } 1534 1535 type_init(rocker_register_types) 1536