+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ /* Registering LSC interrupt handler */
+ rte_intr_callback_register(&pci_dev->intr_handle,
+ nfp_net_dev_interrupt_handler,
+ (void *)eth_dev);
+ /* Telling the firmware about the LSC interrupt entry */
+ nn_cfg_writeb(hw, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX);
+ /* Recording current stats counters values */
+ nfp_net_stats_reset(eth_dev);
+ }
+
+ return 0;
+
+dev_err_queues_map:
+ nfp_cpp_area_free(hw->hwqueues_area);
+dev_err_ctrl_map:
+ nfp_cpp_area_free(hw->ctrl_area);
+
+ return err;
+}
+
+#define NFP_CPP_MEMIO_BOUNDARY (1 << 20)
+
+/*
+ * Serving a write request to NFP from host programs. The request
+ * sends the write size and the CPP target. The bridge makes use
+ * of CPP interface handler configured by the PMD setup.
+ */
+static int
+nfp_cpp_bridge_serve_write(int sockfd, struct nfp_cpp *cpp)
+{
+ struct nfp_cpp_area *area;
+ off_t offset, nfp_offset;
+ uint32_t cpp_id, pos, len;
+ uint32_t tmpbuf[16];
+ size_t count, curlen, totlen = 0;
+ int err = 0;
+
+ PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu\n", __func__,
+ sizeof(off_t), sizeof(size_t));
+
+ /* Reading the count param */
+ err = recv(sockfd, &count, sizeof(off_t), 0);
+ if (err != sizeof(off_t))
+ return -EINVAL;
+
+ curlen = count;
+
+ /* Reading the offset param */
+ err = recv(sockfd, &offset, sizeof(off_t), 0);
+ if (err != sizeof(off_t))
+ return -EINVAL;
+
+ /* Obtain target's CPP ID and offset in target */
+ cpp_id = (offset >> 40) << 8;
+ nfp_offset = offset & ((1ull << 40) - 1);
+
+ PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd\n", __func__, count,
+ offset);
+ PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd\n", __func__,
+ cpp_id, nfp_offset);
+
+ /* Adjust length if not aligned */
+ if (((nfp_offset + (off_t)count - 1) & ~(NFP_CPP_MEMIO_BOUNDARY - 1)) !=
+ (nfp_offset & ~(NFP_CPP_MEMIO_BOUNDARY - 1))) {
+ curlen = NFP_CPP_MEMIO_BOUNDARY -
+ (nfp_offset & (NFP_CPP_MEMIO_BOUNDARY - 1));
+ }
+
+ while (count > 0) {
+ /* configure a CPP PCIe2CPP BAR for mapping the CPP target */
+ area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
+ nfp_offset, curlen);
+ if (!area) {
+ RTE_LOG(ERR, PMD, "%s: area alloc fail\n", __func__);
+ return -EIO;
+ }
+
+ /* mapping the target */
+ err = nfp_cpp_area_acquire(area);
+ if (err < 0) {
+ RTE_LOG(ERR, PMD, "area acquire failed\n");
+ nfp_cpp_area_free(area);
+ return -EIO;
+ }
+
+ for (pos = 0; pos < curlen; pos += len) {
+ len = curlen - pos;
+ if (len > sizeof(tmpbuf))
+ len = sizeof(tmpbuf);
+
+ PMD_CPP_LOG(DEBUG, "%s: Receive %u of %zu\n", __func__,
+ len, count);
+ err = recv(sockfd, tmpbuf, len, MSG_WAITALL);
+ if (err != (int)len) {
+ RTE_LOG(ERR, PMD,
+ "%s: error when receiving, %d of %zu\n",
+ __func__, err, count);
+ nfp_cpp_area_release(area);
+ nfp_cpp_area_free(area);
+ return -EIO;
+ }
+ err = nfp_cpp_area_write(area, pos, tmpbuf, len);
+ if (err < 0) {
+ RTE_LOG(ERR, PMD, "nfp_cpp_area_write error\n");
+ nfp_cpp_area_release(area);
+ nfp_cpp_area_free(area);
+ return -EIO;
+ }
+ }
+
+ nfp_offset += pos;
+ totlen += pos;
+ nfp_cpp_area_release(area);
+ nfp_cpp_area_free(area);
+
+ count -= pos;
+ curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
+ NFP_CPP_MEMIO_BOUNDARY : count;
+ }
+
+ return 0;
+}
+
+/*
+ * Serving a read request to NFP from host programs. The request
+ * sends the read size and the CPP target. The bridge makes use
+ * of CPP interface handler configured by the PMD setup. The read
+ * data is sent to the requester using the same socket.
+ */
+static int
+nfp_cpp_bridge_serve_read(int sockfd, struct nfp_cpp *cpp)
+{
+ struct nfp_cpp_area *area;
+ off_t offset, nfp_offset;
+ uint32_t cpp_id, pos, len;
+ uint32_t tmpbuf[16];
+ size_t count, curlen, totlen = 0;
+ int err = 0;
+
+ PMD_CPP_LOG(DEBUG, "%s: offset size %zu, count_size: %zu\n", __func__,
+ sizeof(off_t), sizeof(size_t));
+
+ /* Reading the count param */
+ err = recv(sockfd, &count, sizeof(off_t), 0);
+ if (err != sizeof(off_t))
+ return -EINVAL;
+
+ curlen = count;
+
+ /* Reading the offset param */
+ err = recv(sockfd, &offset, sizeof(off_t), 0);
+ if (err != sizeof(off_t))
+ return -EINVAL;
+
+ /* Obtain target's CPP ID and offset in target */
+ cpp_id = (offset >> 40) << 8;
+ nfp_offset = offset & ((1ull << 40) - 1);
+
+ PMD_CPP_LOG(DEBUG, "%s: count %zu and offset %jd\n", __func__, count,
+ offset);
+ PMD_CPP_LOG(DEBUG, "%s: cpp_id %08x and nfp_offset %jd\n", __func__,
+ cpp_id, nfp_offset);
+
+ /* Adjust length if not aligned */
+ if (((nfp_offset + (off_t)count - 1) & ~(NFP_CPP_MEMIO_BOUNDARY - 1)) !=
+ (nfp_offset & ~(NFP_CPP_MEMIO_BOUNDARY - 1))) {
+ curlen = NFP_CPP_MEMIO_BOUNDARY -
+ (nfp_offset & (NFP_CPP_MEMIO_BOUNDARY - 1));
+ }
+
+ while (count > 0) {
+ area = nfp_cpp_area_alloc_with_name(cpp, cpp_id, "nfp.cdev",
+ nfp_offset, curlen);
+ if (!area) {
+ RTE_LOG(ERR, PMD, "%s: area alloc failed\n", __func__);
+ return -EIO;
+ }
+
+ err = nfp_cpp_area_acquire(area);
+ if (err < 0) {
+ RTE_LOG(ERR, PMD, "area acquire failed\n");
+ nfp_cpp_area_free(area);
+ return -EIO;
+ }
+
+ for (pos = 0; pos < curlen; pos += len) {
+ len = curlen - pos;
+ if (len > sizeof(tmpbuf))
+ len = sizeof(tmpbuf);
+
+ err = nfp_cpp_area_read(area, pos, tmpbuf, len);
+ if (err < 0) {
+ RTE_LOG(ERR, PMD, "nfp_cpp_area_read error\n");
+ nfp_cpp_area_release(area);
+ nfp_cpp_area_free(area);
+ return -EIO;
+ }
+ PMD_CPP_LOG(DEBUG, "%s: sending %u of %zu\n", __func__,
+ len, count);
+
+ err = send(sockfd, tmpbuf, len, 0);
+ if (err != (int)len) {
+ RTE_LOG(ERR, PMD,
+ "%s: error when sending: %d of %zu\n",
+ __func__, err, count);
+ nfp_cpp_area_release(area);
+ nfp_cpp_area_free(area);
+ return -EIO;
+ }
+ }
+
+ nfp_offset += pos;
+ totlen += pos;
+ nfp_cpp_area_release(area);
+ nfp_cpp_area_free(area);
+
+ count -= pos;
+ curlen = (count > NFP_CPP_MEMIO_BOUNDARY) ?
+ NFP_CPP_MEMIO_BOUNDARY : count;
+ }
+ return 0;
+}
+
+#define NFP_IOCTL 'n'
+#define NFP_IOCTL_CPP_IDENTIFICATION _IOW(NFP_IOCTL, 0x8f, uint32_t)
+/*
+ * Serving a ioctl command from host NFP tools. This usually goes to
+ * a kernel driver char driver but it is not available when the PF is
+ * bound to the PMD. Currently just one ioctl command is served and it
+ * does not require any CPP access at all.
+ */
+static int
+nfp_cpp_bridge_serve_ioctl(int sockfd, struct nfp_cpp *cpp)
+{
+ uint32_t cmd, ident_size, tmp;
+ int err;
+
+ /* Reading now the IOCTL command */
+ err = recv(sockfd, &cmd, 4, 0);
+ if (err != 4) {
+ RTE_LOG(ERR, PMD, "%s: read error from socket\n", __func__);
+ return -EIO;
+ }
+
+ /* Only supporting NFP_IOCTL_CPP_IDENTIFICATION */
+ if (cmd != NFP_IOCTL_CPP_IDENTIFICATION) {
+ RTE_LOG(ERR, PMD, "%s: unknown cmd %d\n", __func__, cmd);
+ return -EINVAL;
+ }
+
+ err = recv(sockfd, &ident_size, 4, 0);
+ if (err != 4) {
+ RTE_LOG(ERR, PMD, "%s: read error from socket\n", __func__);
+ return -EIO;
+ }
+
+ tmp = nfp_cpp_model(cpp);
+
+ PMD_CPP_LOG(DEBUG, "%s: sending NFP model %08x\n", __func__, tmp);
+
+ err = send(sockfd, &tmp, 4, 0);
+ if (err != 4) {
+ RTE_LOG(ERR, PMD, "%s: error writing to socket\n", __func__);
+ return -EIO;
+ }