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