Skip to content

Commit

Permalink
fjes: Introduce spinlock for rx_status
Browse files Browse the repository at this point in the history
This patch introduces spinlock of rx_status for
proper excusive control.

Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Taku Izumi authored and David S. Miller committed Apr 17, 2016
1 parent 16bbec3 commit bd5a256
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 9 deletions.
22 changes: 21 additions & 1 deletion drivers/net/fjes/fjes_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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++) {
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -1075,20 +1085,26 @@ 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)) {
fjes_hw_raise_interrupt(hw, epidx,
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);
}
}
Expand All @@ -1104,16 +1120,20 @@ 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;

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,
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/fjes/fjes_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
57 changes: 49 additions & 8 deletions drivers/net/fjes/fjes_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 &=
~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_irqrestore(&hw->rx_status_lock, flags);

fjes_free_irq(adapter);

Expand All @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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);
}
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand All @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1372,18 +1407,24 @@ 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);
clear_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);
}

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);
}
}
}
Expand Down

0 comments on commit bd5a256

Please sign in to comment.