Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd5a2569 authored by Taku Izumi's avatar Taku Izumi Committed by David S. Miller
Browse files

fjes: Introduce spinlock for rx_status



This patch introduces spinlock of rx_status for
proper excusive control.

Signed-off-by: default avatarTaku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 16bbec3a
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -216,6 +216,7 @@ static int fjes_hw_setup(struct fjes_hw *hw)
	u8 mac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
	struct fjes_device_command_param param;
	struct ep_share_mem_info *buf_pair;
	unsigned long flags;
	size_t mem_size;
	int result;
	int epidx;
@@ -264,10 +265,12 @@ static int fjes_hw_setup(struct fjes_hw *hw)
			if (result)
				return result;

			spin_lock_irqsave(&hw->rx_status_lock, flags);
			fjes_hw_setup_epbuf(&buf_pair->tx, mac,
					    fjes_support_mtu[0]);
			fjes_hw_setup_epbuf(&buf_pair->rx, mac,
					    fjes_support_mtu[0]);
			spin_unlock_irqrestore(&hw->rx_status_lock, flags);
		}
	}

@@ -329,6 +332,7 @@ int fjes_hw_init(struct fjes_hw *hw)
	INIT_WORK(&hw->epstop_task, fjes_hw_epstop_task);

	mutex_init(&hw->hw_info.lock);
	spin_lock_init(&hw->rx_status_lock);

	hw->max_epid = fjes_hw_get_max_epid(hw);
	hw->my_epid = fjes_hw_get_my_epid(hw);
@@ -736,6 +740,7 @@ fjes_hw_get_partner_ep_status(struct fjes_hw *hw, int epid)
void fjes_hw_raise_epstop(struct fjes_hw *hw)
{
	enum ep_partner_status status;
	unsigned long flags;
	int epidx;

	for (epidx = 0; epidx < hw->max_epid; epidx++) {
@@ -755,8 +760,10 @@ void fjes_hw_raise_epstop(struct fjes_hw *hw)
		set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);
		set_bit(epidx, &hw->txrx_stop_req_bit);

		spin_lock_irqsave(&hw->rx_status_lock, flags);
		hw->ep_shm_info[epidx].tx.info->v1i.rx_status |=
				FJES_RX_STOP_REQ_REQUEST;
		spin_unlock_irqrestore(&hw->rx_status_lock, flags);
	}
}

@@ -938,6 +945,7 @@ static void fjes_hw_update_zone_task(struct work_struct *work)

	struct fjes_adapter *adapter;
	struct net_device *netdev;
	unsigned long flags;

	ulong unshare_bit = 0;
	ulong share_bit = 0;
@@ -1030,8 +1038,10 @@ static void fjes_hw_update_zone_task(struct work_struct *work)
			continue;

		if (test_bit(epidx, &share_bit)) {
			spin_lock_irqsave(&hw->rx_status_lock, flags);
			fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,
					    netdev->dev_addr, netdev->mtu);
			spin_unlock_irqrestore(&hw->rx_status_lock, flags);

			mutex_lock(&hw->hw_info.lock);

@@ -1075,10 +1085,14 @@ static void fjes_hw_update_zone_task(struct work_struct *work)

			mutex_unlock(&hw->hw_info.lock);

			if (ret == 0)
			if (ret == 0) {
				spin_lock_irqsave(&hw->rx_status_lock, flags);
				fjes_hw_setup_epbuf(
					&hw->ep_shm_info[epidx].tx,
					netdev->dev_addr, netdev->mtu);
				spin_unlock_irqrestore(&hw->rx_status_lock,
						       flags);
			}
		}

		if (test_bit(epidx, &irq_bit)) {
@@ -1086,9 +1100,11 @@ static void fjes_hw_update_zone_task(struct work_struct *work)
						REG_ICTL_MASK_TXRX_STOP_REQ);

			set_bit(epidx, &hw->txrx_stop_req_bit);
			spin_lock_irqsave(&hw->rx_status_lock, flags);
			hw->ep_shm_info[epidx].tx.
				info->v1i.rx_status |=
					FJES_RX_STOP_REQ_REQUEST;
			spin_unlock_irqrestore(&hw->rx_status_lock, flags);
			set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);
		}
	}
@@ -1104,6 +1120,7 @@ static void fjes_hw_epstop_task(struct work_struct *work)
{
	struct fjes_hw *hw = container_of(work, struct fjes_hw, epstop_task);
	struct fjes_adapter *adapter = (struct fjes_adapter *)hw->back;
	unsigned long flags;

	ulong remain_bit;
	int epid_bit;
@@ -1111,9 +1128,12 @@ static void fjes_hw_epstop_task(struct work_struct *work)
	while ((remain_bit = hw->epstop_req_bit)) {
		for (epid_bit = 0; remain_bit; remain_bit >>= 1, epid_bit++) {
			if (remain_bit & 1) {
				spin_lock_irqsave(&hw->rx_status_lock, flags);
				hw->ep_shm_info[epid_bit].
					tx.info->v1i.rx_status |=
						FJES_RX_STOP_REQ_DONE;
				spin_unlock_irqrestore(&hw->rx_status_lock,
						       flags);

				clear_bit(epid_bit, &hw->epstop_req_bit);
				set_bit(epid_bit,
+2 −0
Original line number Diff line number Diff line
@@ -300,6 +300,8 @@ struct fjes_hw {
	u8 *base;

	struct fjes_hw_info hw_info;

	spinlock_t rx_status_lock; /* spinlock for rx_status */
};

int fjes_hw_init(struct fjes_hw *);
+49 −8
Original line number Diff line number Diff line
@@ -290,6 +290,7 @@ static int fjes_close(struct net_device *netdev)
{
	struct fjes_adapter *adapter = netdev_priv(netdev);
	struct fjes_hw *hw = &adapter->hw;
	unsigned long flags;
	int epidx;

	netif_tx_stop_all_queues(netdev);
@@ -299,13 +300,18 @@ static int fjes_close(struct net_device *netdev)

	napi_disable(&adapter->napi);

	spin_lock_irqsave(&hw->rx_status_lock, flags);
	for (epidx = 0; epidx < hw->max_epid; epidx++) {
		if (epidx == hw->my_epid)
			continue;

		adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status &=
		if (fjes_hw_get_partner_ep_status(hw, epidx) ==
		    EP_PARTNER_SHARED)
			adapter->hw.ep_shm_info[epidx]
				   .tx.info->v1i.rx_status &=
				~FJES_RX_POLL_WORK;
	}
	spin_unlock_irqrestore(&hw->rx_status_lock, flags);

	fjes_free_irq(adapter);

@@ -330,6 +336,7 @@ static int fjes_setup_resources(struct fjes_adapter *adapter)
	struct net_device *netdev = adapter->netdev;
	struct ep_share_mem_info *buf_pair;
	struct fjes_hw *hw = &adapter->hw;
	unsigned long flags;
	int result;
	int epidx;

@@ -371,8 +378,10 @@ static int fjes_setup_resources(struct fjes_adapter *adapter)

		buf_pair = &hw->ep_shm_info[epidx];

		spin_lock_irqsave(&hw->rx_status_lock, flags);
		fjes_hw_setup_epbuf(&buf_pair->tx, netdev->dev_addr,
				    netdev->mtu);
		spin_unlock_irqrestore(&hw->rx_status_lock, flags);

		if (fjes_hw_epid_is_same_zone(hw, epidx)) {
			mutex_lock(&hw->hw_info.lock);
@@ -402,6 +411,7 @@ static void fjes_free_resources(struct fjes_adapter *adapter)
	struct ep_share_mem_info *buf_pair;
	struct fjes_hw *hw = &adapter->hw;
	bool reset_flag = false;
	unsigned long flags;
	int result;
	int epidx;

@@ -418,8 +428,10 @@ static void fjes_free_resources(struct fjes_adapter *adapter)

		buf_pair = &hw->ep_shm_info[epidx];

		spin_lock_irqsave(&hw->rx_status_lock, flags);
		fjes_hw_setup_epbuf(&buf_pair->tx,
				    netdev->dev_addr, netdev->mtu);
		spin_unlock_irqrestore(&hw->rx_status_lock, flags);

		clear_bit(epidx, &hw->txrx_stop_req_bit);
	}
@@ -766,6 +778,7 @@ static int fjes_change_mtu(struct net_device *netdev, int new_mtu)
	struct fjes_adapter *adapter = netdev_priv(netdev);
	bool running = netif_running(netdev);
	struct fjes_hw *hw = &adapter->hw;
	unsigned long flags;
	int ret = -EINVAL;
	int idx, epidx;

@@ -784,12 +797,15 @@ static int fjes_change_mtu(struct net_device *netdev, int new_mtu)
		return ret;

	if (running) {
		spin_lock_irqsave(&hw->rx_status_lock, flags);
		for (epidx = 0; epidx < hw->max_epid; epidx++) {
			if (epidx == hw->my_epid)
				continue;
			hw->ep_shm_info[epidx].tx.info->v1i.rx_status &=
				~FJES_RX_MTU_CHANGING_DONE;
		}
		spin_unlock_irqrestore(&hw->rx_status_lock, flags);

		netif_tx_stop_all_queues(netdev);
		netif_carrier_off(netdev);
		cancel_work_sync(&adapter->tx_stall_task);
@@ -803,23 +819,25 @@ static int fjes_change_mtu(struct net_device *netdev, int new_mtu)
	netdev->mtu = new_mtu;

	if (running) {
		spin_lock_irqsave(&hw->rx_status_lock, flags);
		for (epidx = 0; epidx < hw->max_epid; epidx++) {
			if (epidx == hw->my_epid)
				continue;

			local_irq_disable();
			spin_lock_irqsave(&hw->rx_status_lock, flags);
			fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,
					    netdev->dev_addr,
					    netdev->mtu);
			local_irq_enable();

			hw->ep_shm_info[epidx].tx.info->v1i.rx_status |=
				FJES_RX_MTU_CHANGING_DONE;
			spin_unlock_irqrestore(&hw->rx_status_lock, flags);
		}

		netif_tx_wake_all_queues(netdev);
		netif_carrier_on(netdev);
		napi_enable(&adapter->napi);
		napi_schedule(&adapter->napi);
	}

	return ret;
@@ -866,6 +884,7 @@ static void fjes_txrx_stop_req_irq(struct fjes_adapter *adapter,
{
	struct fjes_hw *hw = &adapter->hw;
	enum ep_partner_status status;
	unsigned long flags;

	status = fjes_hw_get_partner_ep_status(hw, src_epid);
	switch (status) {
@@ -875,8 +894,10 @@ static void fjes_txrx_stop_req_irq(struct fjes_adapter *adapter,
		break;
	case EP_PARTNER_WAITING:
		if (src_epid < hw->my_epid) {
			spin_lock_irqsave(&hw->rx_status_lock, flags);
			hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |=
				FJES_RX_STOP_REQ_DONE;
			spin_unlock_irqrestore(&hw->rx_status_lock, flags);

			clear_bit(src_epid, &hw->txrx_stop_req_bit);
			set_bit(src_epid, &adapter->unshare_watch_bitmask);
@@ -902,14 +923,17 @@ static void fjes_stop_req_irq(struct fjes_adapter *adapter, int src_epid)
{
	struct fjes_hw *hw = &adapter->hw;
	enum ep_partner_status status;
	unsigned long flags;

	set_bit(src_epid, &hw->hw_info.buffer_unshare_reserve_bit);

	status = fjes_hw_get_partner_ep_status(hw, src_epid);
	switch (status) {
	case EP_PARTNER_WAITING:
		spin_lock_irqsave(&hw->rx_status_lock, flags);
		hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |=
				FJES_RX_STOP_REQ_DONE;
		spin_unlock_irqrestore(&hw->rx_status_lock, flags);
		clear_bit(src_epid, &hw->txrx_stop_req_bit);
		/* fall through */
	case EP_PARTNER_UNSHARE:
@@ -1042,13 +1066,17 @@ static int fjes_poll(struct napi_struct *napi, int budget)
	size_t frame_len;
	void *frame;

	spin_lock(&hw->rx_status_lock);
	for (epidx = 0; epidx < hw->max_epid; epidx++) {
		if (epidx == hw->my_epid)
			continue;

		adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status |=
			FJES_RX_POLL_WORK;
		if (fjes_hw_get_partner_ep_status(hw, epidx) ==
		    EP_PARTNER_SHARED)
			adapter->hw.ep_shm_info[epidx]
				   .tx.info->v1i.rx_status |= FJES_RX_POLL_WORK;
	}
	spin_unlock(&hw->rx_status_lock);

	while (work_done < budget) {
		prefetch(&adapter->hw);
@@ -1106,13 +1134,17 @@ static int fjes_poll(struct napi_struct *napi, int budget)
		if (((long)jiffies - (long)adapter->rx_last_jiffies) < 3) {
			napi_reschedule(napi);
		} else {
			spin_lock(&hw->rx_status_lock);
			for (epidx = 0; epidx < hw->max_epid; epidx++) {
				if (epidx == hw->my_epid)
					continue;
				adapter->hw.ep_shm_info[epidx]
					   .tx.info->v1i.rx_status &=
				if (fjes_hw_get_partner_ep_status(hw, epidx) ==
				    EP_PARTNER_SHARED)
					adapter->hw.ep_shm_info[epidx].tx
						   .info->v1i.rx_status &=
						~FJES_RX_POLL_WORK;
			}
			spin_unlock(&hw->rx_status_lock);

			fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, false);
		}
@@ -1281,6 +1313,7 @@ static void fjes_watch_unshare_task(struct work_struct *work)
	int max_epid, my_epid, epidx;
	int stop_req, stop_req_done;
	ulong unshare_watch_bitmask;
	unsigned long flags;
	int wait_time = 0;
	int is_shared;
	int ret;
@@ -1333,8 +1366,10 @@ static void fjes_watch_unshare_task(struct work_struct *work)
			}
			mutex_unlock(&hw->hw_info.lock);

			spin_lock_irqsave(&hw->rx_status_lock, flags);
			fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,
					    netdev->dev_addr, netdev->mtu);
			spin_unlock_irqrestore(&hw->rx_status_lock, flags);

			clear_bit(epidx, &hw->txrx_stop_req_bit);
			clear_bit(epidx, &unshare_watch_bitmask);
@@ -1372,9 +1407,12 @@ static void fjes_watch_unshare_task(struct work_struct *work)
				}
				mutex_unlock(&hw->hw_info.lock);

				spin_lock_irqsave(&hw->rx_status_lock, flags);
				fjes_hw_setup_epbuf(
					&hw->ep_shm_info[epidx].tx,
					netdev->dev_addr, netdev->mtu);
				spin_unlock_irqrestore(&hw->rx_status_lock,
						       flags);

				clear_bit(epidx, &hw->txrx_stop_req_bit);
				clear_bit(epidx, &unshare_watch_bitmask);
@@ -1382,8 +1420,11 @@ static void fjes_watch_unshare_task(struct work_struct *work)
			}

			if (test_bit(epidx, &unshare_watch_bitmask)) {
				spin_lock_irqsave(&hw->rx_status_lock, flags);
				hw->ep_shm_info[epidx].tx.info->v1i.rx_status &=
						~FJES_RX_STOP_REQ_DONE;
				spin_unlock_irqrestore(&hw->rx_status_lock,
						       flags);
			}
		}
	}