1324 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * FUJITSU Extended Socket Network Device driver4 * Copyright (c) 2015 FUJITSU LIMITED5 */6 7#include "fjes_hw.h"8#include "fjes.h"9#include "fjes_trace.h"10 11static void fjes_hw_update_zone_task(struct work_struct *);12static void fjes_hw_epstop_task(struct work_struct *);13 14/* supported MTU list */15const u32 fjes_support_mtu[] = {16 FJES_MTU_DEFINE(8 * 1024),17 FJES_MTU_DEFINE(16 * 1024),18 FJES_MTU_DEFINE(32 * 1024),19 FJES_MTU_DEFINE(64 * 1024),20 021};22 23u32 fjes_hw_rd32(struct fjes_hw *hw, u32 reg)24{25 u8 *base = hw->base;26 u32 value = 0;27 28 value = readl(&base[reg]);29 30 return value;31}32 33static u8 *fjes_hw_iomap(struct fjes_hw *hw)34{35 u8 *base;36 37 if (!request_mem_region(hw->hw_res.start, hw->hw_res.size,38 fjes_driver_name)) {39 pr_err("request_mem_region failed\n");40 return NULL;41 }42 43 base = (u8 *)ioremap(hw->hw_res.start, hw->hw_res.size);44 45 return base;46}47 48static void fjes_hw_iounmap(struct fjes_hw *hw)49{50 iounmap(hw->base);51 release_mem_region(hw->hw_res.start, hw->hw_res.size);52}53 54int fjes_hw_reset(struct fjes_hw *hw)55{56 union REG_DCTL dctl;57 int timeout;58 59 dctl.reg = 0;60 dctl.bits.reset = 1;61 wr32(XSCT_DCTL, dctl.reg);62 63 timeout = FJES_DEVICE_RESET_TIMEOUT * 1000;64 dctl.reg = rd32(XSCT_DCTL);65 while ((dctl.bits.reset == 1) && (timeout > 0)) {66 msleep(1000);67 dctl.reg = rd32(XSCT_DCTL);68 timeout -= 1000;69 }70 71 return timeout > 0 ? 0 : -EIO;72}73 74static int fjes_hw_get_max_epid(struct fjes_hw *hw)75{76 union REG_MAX_EP info;77 78 info.reg = rd32(XSCT_MAX_EP);79 80 return info.bits.maxep;81}82 83static int fjes_hw_get_my_epid(struct fjes_hw *hw)84{85 union REG_OWNER_EPID info;86 87 info.reg = rd32(XSCT_OWNER_EPID);88 89 return info.bits.epid;90}91 92static int fjes_hw_alloc_shared_status_region(struct fjes_hw *hw)93{94 size_t size;95 96 size = sizeof(struct fjes_device_shared_info) +97 (sizeof(u8) * hw->max_epid);98 hw->hw_info.share = kzalloc(size, GFP_KERNEL);99 if (!hw->hw_info.share)100 return -ENOMEM;101 102 hw->hw_info.share->epnum = hw->max_epid;103 104 return 0;105}106 107static void fjes_hw_free_shared_status_region(struct fjes_hw *hw)108{109 kfree(hw->hw_info.share);110 hw->hw_info.share = NULL;111}112 113static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh)114{115 void *mem;116 117 mem = vzalloc(EP_BUFFER_SIZE);118 if (!mem)119 return -ENOMEM;120 121 epbh->buffer = mem;122 epbh->size = EP_BUFFER_SIZE;123 124 epbh->info = (union ep_buffer_info *)mem;125 epbh->ring = (u8 *)(mem + sizeof(union ep_buffer_info));126 127 return 0;128}129 130static void fjes_hw_free_epbuf(struct epbuf_handler *epbh)131{132 vfree(epbh->buffer);133 epbh->buffer = NULL;134 epbh->size = 0;135 136 epbh->info = NULL;137 epbh->ring = NULL;138}139 140void fjes_hw_setup_epbuf(struct epbuf_handler *epbh, const u8 *mac_addr,141 u32 mtu)142{143 union ep_buffer_info *info = epbh->info;144 u16 vlan_id[EP_BUFFER_SUPPORT_VLAN_MAX];145 int i;146 147 for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++)148 vlan_id[i] = info->v1i.vlan_id[i];149 150 memset(info, 0, sizeof(union ep_buffer_info));151 152 info->v1i.version = 0; /* version 0 */153 154 for (i = 0; i < ETH_ALEN; i++)155 info->v1i.mac_addr[i] = mac_addr[i];156 157 info->v1i.head = 0;158 info->v1i.tail = 1;159 160 info->v1i.info_size = sizeof(union ep_buffer_info);161 info->v1i.buffer_size = epbh->size - info->v1i.info_size;162 163 info->v1i.frame_max = FJES_MTU_TO_FRAME_SIZE(mtu);164 info->v1i.count_max =165 EP_RING_NUM(info->v1i.buffer_size, info->v1i.frame_max);166 167 for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++)168 info->v1i.vlan_id[i] = vlan_id[i];169 170 info->v1i.rx_status |= FJES_RX_MTU_CHANGING_DONE;171}172 173void174fjes_hw_init_command_registers(struct fjes_hw *hw,175 struct fjes_device_command_param *param)176{177 /* Request Buffer length */178 wr32(XSCT_REQBL, (__le32)(param->req_len));179 /* Response Buffer Length */180 wr32(XSCT_RESPBL, (__le32)(param->res_len));181 182 /* Request Buffer Address */183 wr32(XSCT_REQBAL,184 (__le32)(param->req_start & GENMASK_ULL(31, 0)));185 wr32(XSCT_REQBAH,186 (__le32)((param->req_start & GENMASK_ULL(63, 32)) >> 32));187 188 /* Response Buffer Address */189 wr32(XSCT_RESPBAL,190 (__le32)(param->res_start & GENMASK_ULL(31, 0)));191 wr32(XSCT_RESPBAH,192 (__le32)((param->res_start & GENMASK_ULL(63, 32)) >> 32));193 194 /* Share status address */195 wr32(XSCT_SHSTSAL,196 (__le32)(param->share_start & GENMASK_ULL(31, 0)));197 wr32(XSCT_SHSTSAH,198 (__le32)((param->share_start & GENMASK_ULL(63, 32)) >> 32));199}200 201static int fjes_hw_setup(struct fjes_hw *hw)202{203 u8 mac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };204 struct fjes_device_command_param param;205 struct ep_share_mem_info *buf_pair;206 unsigned long flags;207 size_t mem_size;208 int result;209 int epidx;210 void *buf;211 212 hw->hw_info.max_epid = &hw->max_epid;213 hw->hw_info.my_epid = &hw->my_epid;214 215 buf = kcalloc(hw->max_epid, sizeof(struct ep_share_mem_info),216 GFP_KERNEL);217 if (!buf)218 return -ENOMEM;219 220 hw->ep_shm_info = (struct ep_share_mem_info *)buf;221 222 mem_size = FJES_DEV_REQ_BUF_SIZE(hw->max_epid);223 hw->hw_info.req_buf = kzalloc(mem_size, GFP_KERNEL);224 if (!(hw->hw_info.req_buf)) {225 result = -ENOMEM;226 goto free_ep_info;227 }228 229 hw->hw_info.req_buf_size = mem_size;230 231 mem_size = FJES_DEV_RES_BUF_SIZE(hw->max_epid);232 hw->hw_info.res_buf = kzalloc(mem_size, GFP_KERNEL);233 if (!(hw->hw_info.res_buf)) {234 result = -ENOMEM;235 goto free_req_buf;236 }237 238 hw->hw_info.res_buf_size = mem_size;239 240 result = fjes_hw_alloc_shared_status_region(hw);241 if (result)242 goto free_res_buf;243 244 hw->hw_info.buffer_share_bit = 0;245 hw->hw_info.buffer_unshare_reserve_bit = 0;246 247 for (epidx = 0; epidx < hw->max_epid; epidx++) {248 if (epidx != hw->my_epid) {249 buf_pair = &hw->ep_shm_info[epidx];250 251 result = fjes_hw_alloc_epbuf(&buf_pair->tx);252 if (result)253 goto free_epbuf;254 255 result = fjes_hw_alloc_epbuf(&buf_pair->rx);256 if (result)257 goto free_epbuf;258 259 spin_lock_irqsave(&hw->rx_status_lock, flags);260 fjes_hw_setup_epbuf(&buf_pair->tx, mac,261 fjes_support_mtu[0]);262 fjes_hw_setup_epbuf(&buf_pair->rx, mac,263 fjes_support_mtu[0]);264 spin_unlock_irqrestore(&hw->rx_status_lock, flags);265 }266 }267 268 memset(¶m, 0, sizeof(param));269 270 param.req_len = hw->hw_info.req_buf_size;271 param.req_start = __pa(hw->hw_info.req_buf);272 param.res_len = hw->hw_info.res_buf_size;273 param.res_start = __pa(hw->hw_info.res_buf);274 275 param.share_start = __pa(hw->hw_info.share->ep_status);276 277 fjes_hw_init_command_registers(hw, ¶m);278 279 return 0;280 281free_epbuf:282 for (epidx = 0; epidx < hw->max_epid ; epidx++) {283 if (epidx == hw->my_epid)284 continue;285 fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].tx);286 fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].rx);287 }288 fjes_hw_free_shared_status_region(hw);289free_res_buf:290 kfree(hw->hw_info.res_buf);291 hw->hw_info.res_buf = NULL;292free_req_buf:293 kfree(hw->hw_info.req_buf);294 hw->hw_info.req_buf = NULL;295free_ep_info:296 kfree(hw->ep_shm_info);297 hw->ep_shm_info = NULL;298 return result;299}300 301static void fjes_hw_cleanup(struct fjes_hw *hw)302{303 int epidx;304 305 if (!hw->ep_shm_info)306 return;307 308 fjes_hw_free_shared_status_region(hw);309 310 kfree(hw->hw_info.req_buf);311 hw->hw_info.req_buf = NULL;312 313 kfree(hw->hw_info.res_buf);314 hw->hw_info.res_buf = NULL;315 316 for (epidx = 0; epidx < hw->max_epid ; epidx++) {317 if (epidx == hw->my_epid)318 continue;319 fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].tx);320 fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].rx);321 }322 323 kfree(hw->ep_shm_info);324 hw->ep_shm_info = NULL;325}326 327int fjes_hw_init(struct fjes_hw *hw)328{329 int ret;330 331 hw->base = fjes_hw_iomap(hw);332 if (!hw->base)333 return -EIO;334 335 ret = fjes_hw_reset(hw);336 if (ret)337 return ret;338 339 fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true);340 341 INIT_WORK(&hw->update_zone_task, fjes_hw_update_zone_task);342 INIT_WORK(&hw->epstop_task, fjes_hw_epstop_task);343 344 mutex_init(&hw->hw_info.lock);345 spin_lock_init(&hw->rx_status_lock);346 347 hw->max_epid = fjes_hw_get_max_epid(hw);348 hw->my_epid = fjes_hw_get_my_epid(hw);349 350 if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid))351 return -ENXIO;352 353 ret = fjes_hw_setup(hw);354 355 hw->hw_info.trace = vzalloc(FJES_DEBUG_BUFFER_SIZE);356 hw->hw_info.trace_size = FJES_DEBUG_BUFFER_SIZE;357 358 return ret;359}360 361void fjes_hw_exit(struct fjes_hw *hw)362{363 int ret;364 365 if (hw->base) {366 367 if (hw->debug_mode) {368 /* disable debug mode */369 mutex_lock(&hw->hw_info.lock);370 fjes_hw_stop_debug(hw);371 mutex_unlock(&hw->hw_info.lock);372 }373 vfree(hw->hw_info.trace);374 hw->hw_info.trace = NULL;375 hw->hw_info.trace_size = 0;376 hw->debug_mode = 0;377 378 ret = fjes_hw_reset(hw);379 if (ret)380 pr_err("%s: reset error", __func__);381 382 fjes_hw_iounmap(hw);383 hw->base = NULL;384 }385 386 fjes_hw_cleanup(hw);387 388 cancel_work_sync(&hw->update_zone_task);389 cancel_work_sync(&hw->epstop_task);390}391 392static enum fjes_dev_command_response_e393fjes_hw_issue_request_command(struct fjes_hw *hw,394 enum fjes_dev_command_request_type type)395{396 enum fjes_dev_command_response_e ret = FJES_CMD_STATUS_UNKNOWN;397 union REG_CR cr;398 union REG_CS cs;399 int timeout = FJES_COMMAND_REQ_TIMEOUT * 1000;400 401 cr.reg = 0;402 cr.bits.req_start = 1;403 cr.bits.req_code = type;404 wr32(XSCT_CR, cr.reg);405 cr.reg = rd32(XSCT_CR);406 407 if (cr.bits.error == 0) {408 timeout = FJES_COMMAND_REQ_TIMEOUT * 1000;409 cs.reg = rd32(XSCT_CS);410 411 while ((cs.bits.complete != 1) && timeout > 0) {412 msleep(1000);413 cs.reg = rd32(XSCT_CS);414 timeout -= 1000;415 }416 417 if (cs.bits.complete == 1)418 ret = FJES_CMD_STATUS_NORMAL;419 else if (timeout <= 0)420 ret = FJES_CMD_STATUS_TIMEOUT;421 422 } else {423 switch (cr.bits.err_info) {424 case FJES_CMD_REQ_ERR_INFO_PARAM:425 ret = FJES_CMD_STATUS_ERROR_PARAM;426 break;427 case FJES_CMD_REQ_ERR_INFO_STATUS:428 ret = FJES_CMD_STATUS_ERROR_STATUS;429 break;430 default:431 ret = FJES_CMD_STATUS_UNKNOWN;432 break;433 }434 }435 436 trace_fjes_hw_issue_request_command(&cr, &cs, timeout, ret);437 438 return ret;439}440 441int fjes_hw_request_info(struct fjes_hw *hw)442{443 union fjes_device_command_req *req_buf = hw->hw_info.req_buf;444 union fjes_device_command_res *res_buf = hw->hw_info.res_buf;445 enum fjes_dev_command_response_e ret;446 int result;447 448 memset(req_buf, 0, hw->hw_info.req_buf_size);449 memset(res_buf, 0, hw->hw_info.res_buf_size);450 451 req_buf->info.length = FJES_DEV_COMMAND_INFO_REQ_LEN;452 453 res_buf->info.length = 0;454 res_buf->info.code = 0;455 456 ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_INFO);457 trace_fjes_hw_request_info(hw, res_buf);458 459 result = 0;460 461 if (FJES_DEV_COMMAND_INFO_RES_LEN((*hw->hw_info.max_epid)) !=462 res_buf->info.length) {463 trace_fjes_hw_request_info_err("Invalid res_buf");464 result = -ENOMSG;465 } else if (ret == FJES_CMD_STATUS_NORMAL) {466 switch (res_buf->info.code) {467 case FJES_CMD_REQ_RES_CODE_NORMAL:468 result = 0;469 break;470 default:471 result = -EPERM;472 break;473 }474 } else {475 switch (ret) {476 case FJES_CMD_STATUS_UNKNOWN:477 result = -EPERM;478 break;479 case FJES_CMD_STATUS_TIMEOUT:480 trace_fjes_hw_request_info_err("Timeout");481 result = -EBUSY;482 break;483 case FJES_CMD_STATUS_ERROR_PARAM:484 result = -EPERM;485 break;486 case FJES_CMD_STATUS_ERROR_STATUS:487 result = -EPERM;488 break;489 default:490 result = -EPERM;491 break;492 }493 }494 495 return result;496}497 498int fjes_hw_register_buff_addr(struct fjes_hw *hw, int dest_epid,499 struct ep_share_mem_info *buf_pair)500{501 union fjes_device_command_req *req_buf = hw->hw_info.req_buf;502 union fjes_device_command_res *res_buf = hw->hw_info.res_buf;503 enum fjes_dev_command_response_e ret;504 int page_count;505 int timeout;506 int i, idx;507 void *addr;508 int result;509 510 if (test_bit(dest_epid, &hw->hw_info.buffer_share_bit))511 return 0;512 513 memset(req_buf, 0, hw->hw_info.req_buf_size);514 memset(res_buf, 0, hw->hw_info.res_buf_size);515 516 req_buf->share_buffer.length = FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(517 buf_pair->tx.size,518 buf_pair->rx.size);519 req_buf->share_buffer.epid = dest_epid;520 521 idx = 0;522 req_buf->share_buffer.buffer[idx++] = buf_pair->tx.size;523 page_count = buf_pair->tx.size / EP_BUFFER_INFO_SIZE;524 for (i = 0; i < page_count; i++) {525 addr = ((u8 *)(buf_pair->tx.buffer)) +526 (i * EP_BUFFER_INFO_SIZE);527 req_buf->share_buffer.buffer[idx++] =528 (__le64)(page_to_phys(vmalloc_to_page(addr)) +529 offset_in_page(addr));530 }531 532 req_buf->share_buffer.buffer[idx++] = buf_pair->rx.size;533 page_count = buf_pair->rx.size / EP_BUFFER_INFO_SIZE;534 for (i = 0; i < page_count; i++) {535 addr = ((u8 *)(buf_pair->rx.buffer)) +536 (i * EP_BUFFER_INFO_SIZE);537 req_buf->share_buffer.buffer[idx++] =538 (__le64)(page_to_phys(vmalloc_to_page(addr)) +539 offset_in_page(addr));540 }541 542 res_buf->share_buffer.length = 0;543 res_buf->share_buffer.code = 0;544 545 trace_fjes_hw_register_buff_addr_req(req_buf, buf_pair);546 547 ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_SHARE_BUFFER);548 549 timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000;550 while ((ret == FJES_CMD_STATUS_NORMAL) &&551 (res_buf->share_buffer.length ==552 FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN) &&553 (res_buf->share_buffer.code == FJES_CMD_REQ_RES_CODE_BUSY) &&554 (timeout > 0)) {555 msleep(200 + hw->my_epid * 20);556 timeout -= (200 + hw->my_epid * 20);557 558 res_buf->share_buffer.length = 0;559 res_buf->share_buffer.code = 0;560 561 ret = fjes_hw_issue_request_command(562 hw, FJES_CMD_REQ_SHARE_BUFFER);563 }564 565 result = 0;566 567 trace_fjes_hw_register_buff_addr(res_buf, timeout);568 569 if (res_buf->share_buffer.length !=570 FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN) {571 trace_fjes_hw_register_buff_addr_err("Invalid res_buf");572 result = -ENOMSG;573 } else if (ret == FJES_CMD_STATUS_NORMAL) {574 switch (res_buf->share_buffer.code) {575 case FJES_CMD_REQ_RES_CODE_NORMAL:576 result = 0;577 set_bit(dest_epid, &hw->hw_info.buffer_share_bit);578 break;579 case FJES_CMD_REQ_RES_CODE_BUSY:580 trace_fjes_hw_register_buff_addr_err("Busy Timeout");581 result = -EBUSY;582 break;583 default:584 result = -EPERM;585 break;586 }587 } else {588 switch (ret) {589 case FJES_CMD_STATUS_UNKNOWN:590 result = -EPERM;591 break;592 case FJES_CMD_STATUS_TIMEOUT:593 trace_fjes_hw_register_buff_addr_err("Timeout");594 result = -EBUSY;595 break;596 case FJES_CMD_STATUS_ERROR_PARAM:597 case FJES_CMD_STATUS_ERROR_STATUS:598 default:599 result = -EPERM;600 break;601 }602 }603 604 return result;605}606 607int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid)608{609 union fjes_device_command_req *req_buf = hw->hw_info.req_buf;610 union fjes_device_command_res *res_buf = hw->hw_info.res_buf;611 struct fjes_device_shared_info *share = hw->hw_info.share;612 enum fjes_dev_command_response_e ret;613 int timeout;614 int result;615 616 if (!hw->base)617 return -EPERM;618 619 if (!req_buf || !res_buf || !share)620 return -EPERM;621 622 if (!test_bit(dest_epid, &hw->hw_info.buffer_share_bit))623 return 0;624 625 memset(req_buf, 0, hw->hw_info.req_buf_size);626 memset(res_buf, 0, hw->hw_info.res_buf_size);627 628 req_buf->unshare_buffer.length =629 FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN;630 req_buf->unshare_buffer.epid = dest_epid;631 632 res_buf->unshare_buffer.length = 0;633 res_buf->unshare_buffer.code = 0;634 635 trace_fjes_hw_unregister_buff_addr_req(req_buf);636 ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_UNSHARE_BUFFER);637 638 timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000;639 while ((ret == FJES_CMD_STATUS_NORMAL) &&640 (res_buf->unshare_buffer.length ==641 FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN) &&642 (res_buf->unshare_buffer.code ==643 FJES_CMD_REQ_RES_CODE_BUSY) &&644 (timeout > 0)) {645 msleep(200 + hw->my_epid * 20);646 timeout -= (200 + hw->my_epid * 20);647 648 res_buf->unshare_buffer.length = 0;649 res_buf->unshare_buffer.code = 0;650 651 ret =652 fjes_hw_issue_request_command(hw, FJES_CMD_REQ_UNSHARE_BUFFER);653 }654 655 result = 0;656 657 trace_fjes_hw_unregister_buff_addr(res_buf, timeout);658 659 if (res_buf->unshare_buffer.length !=660 FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN) {661 trace_fjes_hw_unregister_buff_addr_err("Invalid res_buf");662 result = -ENOMSG;663 } else if (ret == FJES_CMD_STATUS_NORMAL) {664 switch (res_buf->unshare_buffer.code) {665 case FJES_CMD_REQ_RES_CODE_NORMAL:666 result = 0;667 clear_bit(dest_epid, &hw->hw_info.buffer_share_bit);668 break;669 case FJES_CMD_REQ_RES_CODE_BUSY:670 trace_fjes_hw_unregister_buff_addr_err("Busy Timeout");671 result = -EBUSY;672 break;673 default:674 result = -EPERM;675 break;676 }677 } else {678 switch (ret) {679 case FJES_CMD_STATUS_UNKNOWN:680 result = -EPERM;681 break;682 case FJES_CMD_STATUS_TIMEOUT:683 trace_fjes_hw_unregister_buff_addr_err("Timeout");684 result = -EBUSY;685 break;686 case FJES_CMD_STATUS_ERROR_PARAM:687 case FJES_CMD_STATUS_ERROR_STATUS:688 default:689 result = -EPERM;690 break;691 }692 }693 694 return result;695}696 697int fjes_hw_raise_interrupt(struct fjes_hw *hw, int dest_epid,698 enum REG_ICTL_MASK mask)699{700 u32 ig = mask | dest_epid;701 702 wr32(XSCT_IG, cpu_to_le32(ig));703 704 return 0;705}706 707u32 fjes_hw_capture_interrupt_status(struct fjes_hw *hw)708{709 u32 cur_is;710 711 cur_is = rd32(XSCT_IS);712 713 return cur_is;714}715 716void fjes_hw_set_irqmask(struct fjes_hw *hw,717 enum REG_ICTL_MASK intr_mask, bool mask)718{719 if (mask)720 wr32(XSCT_IMS, intr_mask);721 else722 wr32(XSCT_IMC, intr_mask);723}724 725bool fjes_hw_epid_is_same_zone(struct fjes_hw *hw, int epid)726{727 if (epid >= hw->max_epid)728 return false;729 730 if ((hw->ep_shm_info[epid].es_status !=731 FJES_ZONING_STATUS_ENABLE) ||732 (hw->ep_shm_info[hw->my_epid].zone ==733 FJES_ZONING_ZONE_TYPE_NONE))734 return false;735 else736 return (hw->ep_shm_info[epid].zone ==737 hw->ep_shm_info[hw->my_epid].zone);738}739 740int fjes_hw_epid_is_shared(struct fjes_device_shared_info *share,741 int dest_epid)742{743 int value = false;744 745 if (dest_epid < share->epnum)746 value = share->ep_status[dest_epid];747 748 return value;749}750 751static bool fjes_hw_epid_is_stop_requested(struct fjes_hw *hw, int src_epid)752{753 return test_bit(src_epid, &hw->txrx_stop_req_bit);754}755 756static bool fjes_hw_epid_is_stop_process_done(struct fjes_hw *hw, int src_epid)757{758 return (hw->ep_shm_info[src_epid].tx.info->v1i.rx_status &759 FJES_RX_STOP_REQ_DONE);760}761 762enum ep_partner_status763fjes_hw_get_partner_ep_status(struct fjes_hw *hw, int epid)764{765 enum ep_partner_status status;766 767 if (fjes_hw_epid_is_shared(hw->hw_info.share, epid)) {768 if (fjes_hw_epid_is_stop_requested(hw, epid)) {769 status = EP_PARTNER_WAITING;770 } else {771 if (fjes_hw_epid_is_stop_process_done(hw, epid))772 status = EP_PARTNER_COMPLETE;773 else774 status = EP_PARTNER_SHARED;775 }776 } else {777 status = EP_PARTNER_UNSHARE;778 }779 780 return status;781}782 783void fjes_hw_raise_epstop(struct fjes_hw *hw)784{785 enum ep_partner_status status;786 unsigned long flags;787 int epidx;788 789 for (epidx = 0; epidx < hw->max_epid; epidx++) {790 if (epidx == hw->my_epid)791 continue;792 793 status = fjes_hw_get_partner_ep_status(hw, epidx);794 switch (status) {795 case EP_PARTNER_SHARED:796 fjes_hw_raise_interrupt(hw, epidx,797 REG_ICTL_MASK_TXRX_STOP_REQ);798 hw->ep_shm_info[epidx].ep_stats.send_intr_unshare += 1;799 break;800 default:801 break;802 }803 804 set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);805 set_bit(epidx, &hw->txrx_stop_req_bit);806 807 spin_lock_irqsave(&hw->rx_status_lock, flags);808 hw->ep_shm_info[epidx].tx.info->v1i.rx_status |=809 FJES_RX_STOP_REQ_REQUEST;810 spin_unlock_irqrestore(&hw->rx_status_lock, flags);811 }812}813 814int fjes_hw_wait_epstop(struct fjes_hw *hw)815{816 enum ep_partner_status status;817 union ep_buffer_info *info;818 int wait_time = 0;819 int epidx;820 821 while (hw->hw_info.buffer_unshare_reserve_bit &&822 (wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000)) {823 for (epidx = 0; epidx < hw->max_epid; epidx++) {824 if (epidx == hw->my_epid)825 continue;826 status = fjes_hw_epid_is_shared(hw->hw_info.share,827 epidx);828 info = hw->ep_shm_info[epidx].rx.info;829 if ((!status ||830 (info->v1i.rx_status &831 FJES_RX_STOP_REQ_DONE)) &&832 test_bit(epidx,833 &hw->hw_info.buffer_unshare_reserve_bit)) {834 clear_bit(epidx,835 &hw->hw_info.buffer_unshare_reserve_bit);836 }837 }838 839 msleep(100);840 wait_time += 100;841 }842 843 for (epidx = 0; epidx < hw->max_epid; epidx++) {844 if (epidx == hw->my_epid)845 continue;846 if (test_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit))847 clear_bit(epidx,848 &hw->hw_info.buffer_unshare_reserve_bit);849 }850 851 return (wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000)852 ? 0 : -EBUSY;853}854 855bool fjes_hw_check_epbuf_version(struct epbuf_handler *epbh, u32 version)856{857 union ep_buffer_info *info = epbh->info;858 859 return (info->common.version == version);860}861 862bool fjes_hw_check_mtu(struct epbuf_handler *epbh, u32 mtu)863{864 union ep_buffer_info *info = epbh->info;865 866 return ((info->v1i.frame_max == FJES_MTU_TO_FRAME_SIZE(mtu)) &&867 info->v1i.rx_status & FJES_RX_MTU_CHANGING_DONE);868}869 870bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id)871{872 union ep_buffer_info *info = epbh->info;873 bool ret = false;874 int i;875 876 if (vlan_id == 0) {877 ret = true;878 } else {879 for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) {880 if (vlan_id == info->v1i.vlan_id[i]) {881 ret = true;882 break;883 }884 }885 }886 return ret;887}888 889bool fjes_hw_set_vlan_id(struct epbuf_handler *epbh, u16 vlan_id)890{891 union ep_buffer_info *info = epbh->info;892 int i;893 894 for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) {895 if (info->v1i.vlan_id[i] == 0) {896 info->v1i.vlan_id[i] = vlan_id;897 return true;898 }899 }900 return false;901}902 903void fjes_hw_del_vlan_id(struct epbuf_handler *epbh, u16 vlan_id)904{905 union ep_buffer_info *info = epbh->info;906 int i;907 908 if (0 != vlan_id) {909 for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) {910 if (vlan_id == info->v1i.vlan_id[i])911 info->v1i.vlan_id[i] = 0;912 }913 }914}915 916bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *epbh)917{918 union ep_buffer_info *info = epbh->info;919 920 if (!(info->v1i.rx_status & FJES_RX_MTU_CHANGING_DONE))921 return true;922 923 if (info->v1i.count_max == 0)924 return true;925 926 return EP_RING_EMPTY(info->v1i.head, info->v1i.tail,927 info->v1i.count_max);928}929 930void *fjes_hw_epbuf_rx_curpkt_get_addr(struct epbuf_handler *epbh,931 size_t *psize)932{933 union ep_buffer_info *info = epbh->info;934 struct esmem_frame *ring_frame;935 void *frame;936 937 ring_frame = (struct esmem_frame *)&(epbh->ring[EP_RING_INDEX938 (info->v1i.head,939 info->v1i.count_max) *940 info->v1i.frame_max]);941 942 *psize = (size_t)ring_frame->frame_size;943 944 frame = ring_frame->frame_data;945 946 return frame;947}948 949void fjes_hw_epbuf_rx_curpkt_drop(struct epbuf_handler *epbh)950{951 union ep_buffer_info *info = epbh->info;952 953 if (fjes_hw_epbuf_rx_is_empty(epbh))954 return;955 956 EP_RING_INDEX_INC(epbh->info->v1i.head, info->v1i.count_max);957}958 959int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh,960 void *frame, size_t size)961{962 union ep_buffer_info *info = epbh->info;963 struct esmem_frame *ring_frame;964 965 if (EP_RING_FULL(info->v1i.head, info->v1i.tail, info->v1i.count_max))966 return -ENOBUFS;967 968 ring_frame = (struct esmem_frame *)&(epbh->ring[EP_RING_INDEX969 (info->v1i.tail - 1,970 info->v1i.count_max) *971 info->v1i.frame_max]);972 973 ring_frame->frame_size = size;974 memcpy((void *)(ring_frame->frame_data), (void *)frame, size);975 976 EP_RING_INDEX_INC(epbh->info->v1i.tail, info->v1i.count_max);977 978 return 0;979}980 981static void fjes_hw_update_zone_task(struct work_struct *work)982{983 struct fjes_hw *hw = container_of(work,984 struct fjes_hw, update_zone_task);985 986 struct my_s {u8 es_status; u8 zone; } *info;987 union fjes_device_command_res *res_buf;988 enum ep_partner_status pstatus;989 990 struct fjes_adapter *adapter;991 struct net_device *netdev;992 unsigned long flags;993 994 ulong unshare_bit = 0;995 ulong share_bit = 0;996 ulong irq_bit = 0;997 998 int epidx;999 int ret;1000 1001 adapter = (struct fjes_adapter *)hw->back;1002 netdev = adapter->netdev;1003 res_buf = hw->hw_info.res_buf;1004 info = (struct my_s *)&res_buf->info.info;1005 1006 mutex_lock(&hw->hw_info.lock);1007 1008 ret = fjes_hw_request_info(hw);1009 switch (ret) {1010 case -ENOMSG:1011 case -EBUSY:1012 default:1013 if (!work_pending(&adapter->force_close_task)) {1014 adapter->force_reset = true;1015 schedule_work(&adapter->force_close_task);1016 }1017 break;1018 1019 case 0:1020 1021 for (epidx = 0; epidx < hw->max_epid; epidx++) {1022 if (epidx == hw->my_epid) {1023 hw->ep_shm_info[epidx].es_status =1024 info[epidx].es_status;1025 hw->ep_shm_info[epidx].zone =1026 info[epidx].zone;1027 continue;1028 }1029 1030 pstatus = fjes_hw_get_partner_ep_status(hw, epidx);1031 switch (pstatus) {1032 case EP_PARTNER_UNSHARE:1033 default:1034 if ((info[epidx].zone !=1035 FJES_ZONING_ZONE_TYPE_NONE) &&1036 (info[epidx].es_status ==1037 FJES_ZONING_STATUS_ENABLE) &&1038 (info[epidx].zone ==1039 info[hw->my_epid].zone))1040 set_bit(epidx, &share_bit);1041 else1042 set_bit(epidx, &unshare_bit);1043 break;1044 1045 case EP_PARTNER_COMPLETE:1046 case EP_PARTNER_WAITING:1047 if ((info[epidx].zone ==1048 FJES_ZONING_ZONE_TYPE_NONE) ||1049 (info[epidx].es_status !=1050 FJES_ZONING_STATUS_ENABLE) ||1051 (info[epidx].zone !=1052 info[hw->my_epid].zone)) {1053 set_bit(epidx,1054 &adapter->unshare_watch_bitmask);1055 set_bit(epidx,1056 &hw->hw_info.buffer_unshare_reserve_bit);1057 }1058 break;1059 1060 case EP_PARTNER_SHARED:1061 if ((info[epidx].zone ==1062 FJES_ZONING_ZONE_TYPE_NONE) ||1063 (info[epidx].es_status !=1064 FJES_ZONING_STATUS_ENABLE) ||1065 (info[epidx].zone !=1066 info[hw->my_epid].zone))1067 set_bit(epidx, &irq_bit);1068 break;1069 }1070 1071 hw->ep_shm_info[epidx].es_status =1072 info[epidx].es_status;1073 hw->ep_shm_info[epidx].zone = info[epidx].zone;1074 }1075 break;1076 }1077 1078 mutex_unlock(&hw->hw_info.lock);1079 1080 for (epidx = 0; epidx < hw->max_epid; epidx++) {1081 if (epidx == hw->my_epid)1082 continue;1083 1084 if (test_bit(epidx, &share_bit)) {1085 spin_lock_irqsave(&hw->rx_status_lock, flags);1086 fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,1087 netdev->dev_addr, netdev->mtu);1088 spin_unlock_irqrestore(&hw->rx_status_lock, flags);1089 1090 mutex_lock(&hw->hw_info.lock);1091 1092 ret = fjes_hw_register_buff_addr(1093 hw, epidx, &hw->ep_shm_info[epidx]);1094 1095 switch (ret) {1096 case 0:1097 break;1098 case -ENOMSG:1099 case -EBUSY:1100 default:1101 if (!work_pending(&adapter->force_close_task)) {1102 adapter->force_reset = true;1103 schedule_work(1104 &adapter->force_close_task);1105 }1106 break;1107 }1108 mutex_unlock(&hw->hw_info.lock);1109 1110 hw->ep_shm_info[epidx].ep_stats1111 .com_regist_buf_exec += 1;1112 }1113 1114 if (test_bit(epidx, &unshare_bit)) {1115 mutex_lock(&hw->hw_info.lock);1116 1117 ret = fjes_hw_unregister_buff_addr(hw, epidx);1118 1119 switch (ret) {1120 case 0:1121 break;1122 case -ENOMSG:1123 case -EBUSY:1124 default:1125 if (!work_pending(&adapter->force_close_task)) {1126 adapter->force_reset = true;1127 schedule_work(1128 &adapter->force_close_task);1129 }1130 break;1131 }1132 1133 mutex_unlock(&hw->hw_info.lock);1134 1135 hw->ep_shm_info[epidx].ep_stats1136 .com_unregist_buf_exec += 1;1137 1138 if (ret == 0) {1139 spin_lock_irqsave(&hw->rx_status_lock, flags);1140 fjes_hw_setup_epbuf(1141 &hw->ep_shm_info[epidx].tx,1142 netdev->dev_addr, netdev->mtu);1143 spin_unlock_irqrestore(&hw->rx_status_lock,1144 flags);1145 }1146 }1147 1148 if (test_bit(epidx, &irq_bit)) {1149 fjes_hw_raise_interrupt(hw, epidx,1150 REG_ICTL_MASK_TXRX_STOP_REQ);1151 1152 hw->ep_shm_info[epidx].ep_stats.send_intr_unshare += 1;1153 1154 set_bit(epidx, &hw->txrx_stop_req_bit);1155 spin_lock_irqsave(&hw->rx_status_lock, flags);1156 hw->ep_shm_info[epidx].tx.1157 info->v1i.rx_status |=1158 FJES_RX_STOP_REQ_REQUEST;1159 spin_unlock_irqrestore(&hw->rx_status_lock, flags);1160 set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);1161 }1162 }1163 1164 if (irq_bit || adapter->unshare_watch_bitmask) {1165 if (!work_pending(&adapter->unshare_watch_task))1166 queue_work(adapter->control_wq,1167 &adapter->unshare_watch_task);1168 }1169}1170 1171static void fjes_hw_epstop_task(struct work_struct *work)1172{1173 struct fjes_hw *hw = container_of(work, struct fjes_hw, epstop_task);1174 struct fjes_adapter *adapter = (struct fjes_adapter *)hw->back;1175 unsigned long flags;1176 1177 ulong remain_bit;1178 int epid_bit;1179 1180 while ((remain_bit = hw->epstop_req_bit)) {1181 for (epid_bit = 0; remain_bit; remain_bit >>= 1, epid_bit++) {1182 if (remain_bit & 1) {1183 spin_lock_irqsave(&hw->rx_status_lock, flags);1184 hw->ep_shm_info[epid_bit].1185 tx.info->v1i.rx_status |=1186 FJES_RX_STOP_REQ_DONE;1187 spin_unlock_irqrestore(&hw->rx_status_lock,1188 flags);1189 1190 clear_bit(epid_bit, &hw->epstop_req_bit);1191 set_bit(epid_bit,1192 &adapter->unshare_watch_bitmask);1193 1194 if (!work_pending(&adapter->unshare_watch_task))1195 queue_work(1196 adapter->control_wq,1197 &adapter->unshare_watch_task);1198 }1199 }1200 }1201}1202 1203int fjes_hw_start_debug(struct fjes_hw *hw)1204{1205 union fjes_device_command_req *req_buf = hw->hw_info.req_buf;1206 union fjes_device_command_res *res_buf = hw->hw_info.res_buf;1207 enum fjes_dev_command_response_e ret;1208 int page_count;1209 int result = 0;1210 void *addr;1211 int i;1212 1213 if (!hw->hw_info.trace)1214 return -EPERM;1215 memset(hw->hw_info.trace, 0, FJES_DEBUG_BUFFER_SIZE);1216 1217 memset(req_buf, 0, hw->hw_info.req_buf_size);1218 memset(res_buf, 0, hw->hw_info.res_buf_size);1219 1220 req_buf->start_trace.length =1221 FJES_DEV_COMMAND_START_DBG_REQ_LEN(hw->hw_info.trace_size);1222 req_buf->start_trace.mode = hw->debug_mode;1223 req_buf->start_trace.buffer_len = hw->hw_info.trace_size;1224 page_count = hw->hw_info.trace_size / FJES_DEBUG_PAGE_SIZE;1225 for (i = 0; i < page_count; i++) {1226 addr = ((u8 *)hw->hw_info.trace) + i * FJES_DEBUG_PAGE_SIZE;1227 req_buf->start_trace.buffer[i] =1228 (__le64)(page_to_phys(vmalloc_to_page(addr)) +1229 offset_in_page(addr));1230 }1231 1232 res_buf->start_trace.length = 0;1233 res_buf->start_trace.code = 0;1234 1235 trace_fjes_hw_start_debug_req(req_buf);1236 ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_START_DEBUG);1237 trace_fjes_hw_start_debug(res_buf);1238 1239 if (res_buf->start_trace.length !=1240 FJES_DEV_COMMAND_START_DBG_RES_LEN) {1241 result = -ENOMSG;1242 trace_fjes_hw_start_debug_err("Invalid res_buf");1243 } else if (ret == FJES_CMD_STATUS_NORMAL) {1244 switch (res_buf->start_trace.code) {1245 case FJES_CMD_REQ_RES_CODE_NORMAL:1246 result = 0;1247 break;1248 default:1249 result = -EPERM;1250 break;1251 }1252 } else {1253 switch (ret) {1254 case FJES_CMD_STATUS_UNKNOWN:1255 result = -EPERM;1256 break;1257 case FJES_CMD_STATUS_TIMEOUT:1258 trace_fjes_hw_start_debug_err("Busy Timeout");1259 result = -EBUSY;1260 break;1261 case FJES_CMD_STATUS_ERROR_PARAM:1262 case FJES_CMD_STATUS_ERROR_STATUS:1263 default:1264 result = -EPERM;1265 break;1266 }1267 }1268 1269 return result;1270}1271 1272int fjes_hw_stop_debug(struct fjes_hw *hw)1273{1274 union fjes_device_command_req *req_buf = hw->hw_info.req_buf;1275 union fjes_device_command_res *res_buf = hw->hw_info.res_buf;1276 enum fjes_dev_command_response_e ret;1277 int result = 0;1278 1279 if (!hw->hw_info.trace)1280 return -EPERM;1281 1282 memset(req_buf, 0, hw->hw_info.req_buf_size);1283 memset(res_buf, 0, hw->hw_info.res_buf_size);1284 req_buf->stop_trace.length = FJES_DEV_COMMAND_STOP_DBG_REQ_LEN;1285 1286 res_buf->stop_trace.length = 0;1287 res_buf->stop_trace.code = 0;1288 1289 ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_STOP_DEBUG);1290 trace_fjes_hw_stop_debug(res_buf);1291 1292 if (res_buf->stop_trace.length != FJES_DEV_COMMAND_STOP_DBG_RES_LEN) {1293 trace_fjes_hw_stop_debug_err("Invalid res_buf");1294 result = -ENOMSG;1295 } else if (ret == FJES_CMD_STATUS_NORMAL) {1296 switch (res_buf->stop_trace.code) {1297 case FJES_CMD_REQ_RES_CODE_NORMAL:1298 result = 0;1299 hw->debug_mode = 0;1300 break;1301 default:1302 result = -EPERM;1303 break;1304 }1305 } else {1306 switch (ret) {1307 case FJES_CMD_STATUS_UNKNOWN:1308 result = -EPERM;1309 break;1310 case FJES_CMD_STATUS_TIMEOUT:1311 result = -EBUSY;1312 trace_fjes_hw_stop_debug_err("Busy Timeout");1313 break;1314 case FJES_CMD_STATUS_ERROR_PARAM:1315 case FJES_CMD_STATUS_ERROR_STATUS:1316 default:1317 result = -EPERM;1318 break;1319 }1320 }1321 1322 return result;1323}1324