brintos

brintos / linux-shallow public Read only

0
0
Text · 30.5 KiB · b9b5554 Raw
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(&param, 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, &param);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