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