fjes: update_zone_task
authorTaku Izumi <izumi.taku@jp.fujitsu.com>
Fri, 21 Aug 2015 08:29:35 +0000 (17:29 +0900)
committerDavid S. Miller <davem@davemloft.net>
Mon, 24 Aug 2015 21:06:36 +0000 (14:06 -0700)
This patch adds update_zone_task.
Zoning information can be changed by user.
This task is used to monitor if zoning information is
changed or not.

Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/fjes/fjes_hw.c
drivers/net/fjes/fjes_hw.h
drivers/net/fjes/fjes_main.c

index 4a4b750fdb9ccb283deeab70d409b649e953c138..4525d3664ccffdb3b25eb07055b47b6e4ed0e994 100644 (file)
@@ -22,6 +22,8 @@
 #include "fjes_hw.h"
 #include "fjes.h"
 
+static void fjes_hw_update_zone_task(struct work_struct *);
+
 /* supported MTU list */
 const u32 fjes_support_mtu[] = {
        FJES_MTU_DEFINE(8 * 1024),
@@ -322,6 +324,8 @@ int fjes_hw_init(struct fjes_hw *hw)
 
        fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true);
 
+       INIT_WORK(&hw->update_zone_task, fjes_hw_update_zone_task);
+
        mutex_init(&hw->hw_info.lock);
 
        hw->max_epid = fjes_hw_get_max_epid(hw);
@@ -349,6 +353,8 @@ void fjes_hw_exit(struct fjes_hw *hw)
        }
 
        fjes_hw_cleanup(hw);
+
+       cancel_work_sync(&hw->update_zone_task);
 }
 
 static enum fjes_dev_command_response_e
@@ -913,3 +919,176 @@ int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh,
 
        return 0;
 }
+
+static void fjes_hw_update_zone_task(struct work_struct *work)
+{
+       struct fjes_hw *hw = container_of(work,
+                       struct fjes_hw, update_zone_task);
+
+       struct my_s {u8 es_status; u8 zone; } *info;
+       union fjes_device_command_res *res_buf;
+       enum ep_partner_status pstatus;
+
+       struct fjes_adapter *adapter;
+       struct net_device *netdev;
+
+       ulong unshare_bit = 0;
+       ulong share_bit = 0;
+       ulong irq_bit = 0;
+
+       int epidx;
+       int ret;
+
+       adapter = (struct fjes_adapter *)hw->back;
+       netdev = adapter->netdev;
+       res_buf = hw->hw_info.res_buf;
+       info = (struct my_s *)&res_buf->info.info;
+
+       mutex_lock(&hw->hw_info.lock);
+
+       ret = fjes_hw_request_info(hw);
+       switch (ret) {
+       case -ENOMSG:
+       case -EBUSY:
+       default:
+               if (!work_pending(&adapter->force_close_task)) {
+                       adapter->force_reset = true;
+                       schedule_work(&adapter->force_close_task);
+               }
+               break;
+
+       case 0:
+
+               for (epidx = 0; epidx < hw->max_epid; epidx++) {
+                       if (epidx == hw->my_epid) {
+                               hw->ep_shm_info[epidx].es_status =
+                                       info[epidx].es_status;
+                               hw->ep_shm_info[epidx].zone =
+                                       info[epidx].zone;
+                               continue;
+                       }
+
+                       pstatus = fjes_hw_get_partner_ep_status(hw, epidx);
+                       switch (pstatus) {
+                       case EP_PARTNER_UNSHARE:
+                       default:
+                               if ((info[epidx].zone !=
+                                       FJES_ZONING_ZONE_TYPE_NONE) &&
+                                   (info[epidx].es_status ==
+                                       FJES_ZONING_STATUS_ENABLE) &&
+                                   (info[epidx].zone ==
+                                       info[hw->my_epid].zone))
+                                       set_bit(epidx, &share_bit);
+                               else
+                                       set_bit(epidx, &unshare_bit);
+                               break;
+
+                       case EP_PARTNER_COMPLETE:
+                       case EP_PARTNER_WAITING:
+                               if ((info[epidx].zone ==
+                                       FJES_ZONING_ZONE_TYPE_NONE) ||
+                                   (info[epidx].es_status !=
+                                       FJES_ZONING_STATUS_ENABLE) ||
+                                   (info[epidx].zone !=
+                                       info[hw->my_epid].zone)) {
+                                       set_bit(epidx,
+                                               &adapter->unshare_watch_bitmask);
+                                       set_bit(epidx,
+                                               &hw->hw_info.buffer_unshare_reserve_bit);
+                               }
+                               break;
+
+                       case EP_PARTNER_SHARED:
+                               if ((info[epidx].zone ==
+                                       FJES_ZONING_ZONE_TYPE_NONE) ||
+                                   (info[epidx].es_status !=
+                                       FJES_ZONING_STATUS_ENABLE) ||
+                                   (info[epidx].zone !=
+                                       info[hw->my_epid].zone))
+                                       set_bit(epidx, &irq_bit);
+                               break;
+                       }
+               }
+
+               hw->ep_shm_info[epidx].es_status = info[epidx].es_status;
+               hw->ep_shm_info[epidx].zone = info[epidx].zone;
+
+               break;
+       }
+
+       mutex_unlock(&hw->hw_info.lock);
+
+       for (epidx = 0; epidx < hw->max_epid; epidx++) {
+               if (epidx == hw->my_epid)
+                       continue;
+
+               if (test_bit(epidx, &share_bit)) {
+                       fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,
+                                           netdev->dev_addr, netdev->mtu);
+
+                       mutex_lock(&hw->hw_info.lock);
+
+                       ret = fjes_hw_register_buff_addr(
+                               hw, epidx, &hw->ep_shm_info[epidx]);
+
+                       switch (ret) {
+                       case 0:
+                               break;
+                       case -ENOMSG:
+                       case -EBUSY:
+                       default:
+                               if (!work_pending(&adapter->force_close_task)) {
+                                       adapter->force_reset = true;
+                                       schedule_work(
+                                         &adapter->force_close_task);
+                               }
+                               break;
+                       }
+                       mutex_unlock(&hw->hw_info.lock);
+               }
+
+               if (test_bit(epidx, &unshare_bit)) {
+                       mutex_lock(&hw->hw_info.lock);
+
+                       ret = fjes_hw_unregister_buff_addr(hw, epidx);
+
+                       switch (ret) {
+                       case 0:
+                               break;
+                       case -ENOMSG:
+                       case -EBUSY:
+                       default:
+                               if (!work_pending(&adapter->force_close_task)) {
+                                       adapter->force_reset = true;
+                                       schedule_work(
+                                         &adapter->force_close_task);
+                               }
+                               break;
+                       }
+
+                       mutex_unlock(&hw->hw_info.lock);
+
+                       if (ret == 0)
+                               fjes_hw_setup_epbuf(
+                                       &hw->ep_shm_info[epidx].tx,
+                                       netdev->dev_addr, netdev->mtu);
+               }
+
+               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);
+                       hw->ep_shm_info[epidx].tx.
+                               info->v1i.rx_status |=
+                                       FJES_RX_STOP_REQ_REQUEST;
+                       set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);
+               }
+       }
+
+       if (irq_bit || adapter->unshare_watch_bitmask) {
+               if (!work_pending(&adapter->unshare_watch_task))
+                       queue_work(adapter->control_wq,
+                                  &adapter->unshare_watch_task);
+       }
+}
index 95e632b363c1a60b7438e1623fba080f14df7bd4..e59b737b45e738646ffc61310493e135fd0cd217 100644 (file)
@@ -282,6 +282,7 @@ struct fjes_hw {
 
        unsigned long txrx_stop_req_bit;
        unsigned long epstop_req_bit;
+       struct work_struct update_zone_task;
 
        int my_epid;
        int max_epid;
index c47ecf35d0058a56102f40011ca343618f6aab6d..8e3a084277c007041361c4ffd2d04ff4b513dbc9 100644 (file)
@@ -315,6 +315,8 @@ static int fjes_close(struct net_device *netdev)
        cancel_work_sync(&adapter->raise_intr_rxdata_task);
        cancel_work_sync(&adapter->tx_stall_task);
 
+       cancel_work_sync(&hw->update_zone_task);
+
        fjes_hw_wait_epstop(hw);
 
        fjes_free_resources(adapter);
@@ -817,6 +819,15 @@ static int fjes_vlan_rx_kill_vid(struct net_device *netdev,
        return 0;
 }
 
+static void fjes_update_zone_irq(struct fjes_adapter *adapter,
+                                int src_epid)
+{
+       struct fjes_hw *hw = &adapter->hw;
+
+       if (!work_pending(&hw->update_zone_task))
+               queue_work(adapter->control_wq, &hw->update_zone_task);
+}
+
 static irqreturn_t fjes_intr(int irq, void *data)
 {
        struct fjes_adapter *adapter = data;
@@ -830,6 +841,9 @@ static irqreturn_t fjes_intr(int irq, void *data)
                if (icr & REG_ICTL_MASK_RX_DATA)
                        fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID);
 
+               if (icr & REG_ICTL_MASK_INFO_UPDATE)
+                       fjes_update_zone_irq(adapter, icr & REG_IS_MASK_EPID);
+
                ret = IRQ_HANDLED;
        } else {
                ret = IRQ_NONE;