diff options
author | Taku Izumi <izumi.taku@jp.fujitsu.com> | 2015-08-21 04:29:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-24 17:06:35 -0400 |
commit | 265859309a761b4eec36620b324c9eb27a3cfee1 (patch) | |
tree | 9c730b9ae871fc56ec3e0ec418186c955336545a /drivers/net/fjes | |
parent | ac63b947085d8297bed10063cdf1ed6374d04b73 (diff) |
fjes: NAPI polling function
This patch adds NAPI polling function and receive related work.
Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/fjes')
-rw-r--r-- | drivers/net/fjes/fjes_hw.c | 40 | ||||
-rw-r--r-- | drivers/net/fjes/fjes_hw.h | 5 | ||||
-rw-r--r-- | drivers/net/fjes/fjes_main.c | 171 |
3 files changed, 214 insertions, 2 deletions
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 487dbc6b7c43..3c96d06d15cf 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c | |||
@@ -825,6 +825,46 @@ bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id) | |||
825 | return ret; | 825 | return ret; |
826 | } | 826 | } |
827 | 827 | ||
828 | bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *epbh) | ||
829 | { | ||
830 | union ep_buffer_info *info = epbh->info; | ||
831 | |||
832 | if (info->v1i.count_max == 0) | ||
833 | return true; | ||
834 | |||
835 | return EP_RING_EMPTY(info->v1i.head, info->v1i.tail, | ||
836 | info->v1i.count_max); | ||
837 | } | ||
838 | |||
839 | void *fjes_hw_epbuf_rx_curpkt_get_addr(struct epbuf_handler *epbh, | ||
840 | size_t *psize) | ||
841 | { | ||
842 | union ep_buffer_info *info = epbh->info; | ||
843 | struct esmem_frame *ring_frame; | ||
844 | void *frame; | ||
845 | |||
846 | ring_frame = (struct esmem_frame *)&(epbh->ring[EP_RING_INDEX | ||
847 | (info->v1i.head, | ||
848 | info->v1i.count_max) * | ||
849 | info->v1i.frame_max]); | ||
850 | |||
851 | *psize = (size_t)ring_frame->frame_size; | ||
852 | |||
853 | frame = ring_frame->frame_data; | ||
854 | |||
855 | return frame; | ||
856 | } | ||
857 | |||
858 | void fjes_hw_epbuf_rx_curpkt_drop(struct epbuf_handler *epbh) | ||
859 | { | ||
860 | union ep_buffer_info *info = epbh->info; | ||
861 | |||
862 | if (fjes_hw_epbuf_rx_is_empty(epbh)) | ||
863 | return; | ||
864 | |||
865 | EP_RING_INDEX_INC(epbh->info->v1i.head, info->v1i.count_max); | ||
866 | } | ||
867 | |||
828 | int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh, | 868 | int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh, |
829 | void *frame, size_t size) | 869 | void *frame, size_t size) |
830 | { | 870 | { |
diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 07e122614a76..3511db2f7eb0 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h | |||
@@ -69,6 +69,8 @@ struct fjes_hw; | |||
69 | ((_num) = EP_RING_INDEX((_num) + 1, (_max))) | 69 | ((_num) = EP_RING_INDEX((_num) + 1, (_max))) |
70 | #define EP_RING_FULL(_head, _tail, _max) \ | 70 | #define EP_RING_FULL(_head, _tail, _max) \ |
71 | (0 == EP_RING_INDEX(((_tail) - (_head)), (_max))) | 71 | (0 == EP_RING_INDEX(((_tail) - (_head)), (_max))) |
72 | #define EP_RING_EMPTY(_head, _tail, _max) \ | ||
73 | (1 == EP_RING_INDEX(((_tail) - (_head)), (_max))) | ||
72 | 74 | ||
73 | #define FJES_MTU_TO_BUFFER_SIZE(mtu) \ | 75 | #define FJES_MTU_TO_BUFFER_SIZE(mtu) \ |
74 | (ETH_HLEN + VLAN_HLEN + (mtu) + ETH_FCS_LEN) | 76 | (ETH_HLEN + VLAN_HLEN + (mtu) + ETH_FCS_LEN) |
@@ -320,6 +322,9 @@ int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int); | |||
320 | bool fjes_hw_check_epbuf_version(struct epbuf_handler *, u32); | 322 | bool fjes_hw_check_epbuf_version(struct epbuf_handler *, u32); |
321 | bool fjes_hw_check_mtu(struct epbuf_handler *, u32); | 323 | bool fjes_hw_check_mtu(struct epbuf_handler *, u32); |
322 | bool fjes_hw_check_vlan_id(struct epbuf_handler *, u16); | 324 | bool fjes_hw_check_vlan_id(struct epbuf_handler *, u16); |
325 | bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *); | ||
326 | void *fjes_hw_epbuf_rx_curpkt_get_addr(struct epbuf_handler *, size_t *); | ||
327 | void fjes_hw_epbuf_rx_curpkt_drop(struct epbuf_handler *); | ||
323 | int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *, void *, size_t); | 328 | int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *, void *, size_t); |
324 | 329 | ||
325 | #endif /* FJES_HW_H_ */ | 330 | #endif /* FJES_HW_H_ */ |
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index ac1e07636662..61949625176c 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c | |||
@@ -66,6 +66,9 @@ static int fjes_remove(struct platform_device *); | |||
66 | static int fjes_sw_init(struct fjes_adapter *); | 66 | static int fjes_sw_init(struct fjes_adapter *); |
67 | static void fjes_netdev_setup(struct net_device *); | 67 | static void fjes_netdev_setup(struct net_device *); |
68 | 68 | ||
69 | static void fjes_rx_irq(struct fjes_adapter *, int); | ||
70 | static int fjes_poll(struct napi_struct *, int); | ||
71 | |||
69 | static const struct acpi_device_id fjes_acpi_ids[] = { | 72 | static const struct acpi_device_id fjes_acpi_ids[] = { |
70 | {"PNP0C02", 0}, | 73 | {"PNP0C02", 0}, |
71 | {"", 0}, | 74 | {"", 0}, |
@@ -235,6 +238,8 @@ static int fjes_open(struct net_device *netdev) | |||
235 | hw->txrx_stop_req_bit = 0; | 238 | hw->txrx_stop_req_bit = 0; |
236 | hw->epstop_req_bit = 0; | 239 | hw->epstop_req_bit = 0; |
237 | 240 | ||
241 | napi_enable(&adapter->napi); | ||
242 | |||
238 | fjes_hw_capture_interrupt_status(hw); | 243 | fjes_hw_capture_interrupt_status(hw); |
239 | 244 | ||
240 | result = fjes_request_irq(adapter); | 245 | result = fjes_request_irq(adapter); |
@@ -250,6 +255,7 @@ static int fjes_open(struct net_device *netdev) | |||
250 | 255 | ||
251 | err_req_irq: | 256 | err_req_irq: |
252 | fjes_free_irq(adapter); | 257 | fjes_free_irq(adapter); |
258 | napi_disable(&adapter->napi); | ||
253 | 259 | ||
254 | err_setup_res: | 260 | err_setup_res: |
255 | fjes_free_resources(adapter); | 261 | fjes_free_resources(adapter); |
@@ -268,6 +274,8 @@ static int fjes_close(struct net_device *netdev) | |||
268 | 274 | ||
269 | fjes_hw_raise_epstop(hw); | 275 | fjes_hw_raise_epstop(hw); |
270 | 276 | ||
277 | napi_disable(&adapter->napi); | ||
278 | |||
271 | for (epidx = 0; epidx < hw->max_epid; epidx++) { | 279 | for (epidx = 0; epidx < hw->max_epid; epidx++) { |
272 | if (epidx == hw->my_epid) | 280 | if (epidx == hw->my_epid) |
273 | continue; | 281 | continue; |
@@ -701,14 +709,167 @@ static irqreturn_t fjes_intr(int irq, void *data) | |||
701 | 709 | ||
702 | icr = fjes_hw_capture_interrupt_status(hw); | 710 | icr = fjes_hw_capture_interrupt_status(hw); |
703 | 711 | ||
704 | if (icr & REG_IS_MASK_IS_ASSERT) | 712 | if (icr & REG_IS_MASK_IS_ASSERT) { |
713 | if (icr & REG_ICTL_MASK_RX_DATA) | ||
714 | fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID); | ||
715 | |||
705 | ret = IRQ_HANDLED; | 716 | ret = IRQ_HANDLED; |
706 | else | 717 | } else { |
707 | ret = IRQ_NONE; | 718 | ret = IRQ_NONE; |
719 | } | ||
708 | 720 | ||
709 | return ret; | 721 | return ret; |
710 | } | 722 | } |
711 | 723 | ||
724 | static int fjes_rxframe_search_exist(struct fjes_adapter *adapter, | ||
725 | int start_epid) | ||
726 | { | ||
727 | struct fjes_hw *hw = &adapter->hw; | ||
728 | enum ep_partner_status pstatus; | ||
729 | int max_epid, cur_epid; | ||
730 | int i; | ||
731 | |||
732 | max_epid = hw->max_epid; | ||
733 | start_epid = (start_epid + 1 + max_epid) % max_epid; | ||
734 | |||
735 | for (i = 0; i < max_epid; i++) { | ||
736 | cur_epid = (start_epid + i) % max_epid; | ||
737 | if (cur_epid == hw->my_epid) | ||
738 | continue; | ||
739 | |||
740 | pstatus = fjes_hw_get_partner_ep_status(hw, cur_epid); | ||
741 | if (pstatus == EP_PARTNER_SHARED) { | ||
742 | if (!fjes_hw_epbuf_rx_is_empty( | ||
743 | &hw->ep_shm_info[cur_epid].rx)) | ||
744 | return cur_epid; | ||
745 | } | ||
746 | } | ||
747 | return -1; | ||
748 | } | ||
749 | |||
750 | static void *fjes_rxframe_get(struct fjes_adapter *adapter, size_t *psize, | ||
751 | int *cur_epid) | ||
752 | { | ||
753 | void *frame; | ||
754 | |||
755 | *cur_epid = fjes_rxframe_search_exist(adapter, *cur_epid); | ||
756 | if (*cur_epid < 0) | ||
757 | return NULL; | ||
758 | |||
759 | frame = | ||
760 | fjes_hw_epbuf_rx_curpkt_get_addr( | ||
761 | &adapter->hw.ep_shm_info[*cur_epid].rx, psize); | ||
762 | |||
763 | return frame; | ||
764 | } | ||
765 | |||
766 | static void fjes_rxframe_release(struct fjes_adapter *adapter, int cur_epid) | ||
767 | { | ||
768 | fjes_hw_epbuf_rx_curpkt_drop(&adapter->hw.ep_shm_info[cur_epid].rx); | ||
769 | } | ||
770 | |||
771 | static void fjes_rx_irq(struct fjes_adapter *adapter, int src_epid) | ||
772 | { | ||
773 | struct fjes_hw *hw = &adapter->hw; | ||
774 | |||
775 | fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, true); | ||
776 | |||
777 | adapter->unset_rx_last = true; | ||
778 | napi_schedule(&adapter->napi); | ||
779 | } | ||
780 | |||
781 | static int fjes_poll(struct napi_struct *napi, int budget) | ||
782 | { | ||
783 | struct fjes_adapter *adapter = | ||
784 | container_of(napi, struct fjes_adapter, napi); | ||
785 | struct net_device *netdev = napi->dev; | ||
786 | struct fjes_hw *hw = &adapter->hw; | ||
787 | struct sk_buff *skb; | ||
788 | int work_done = 0; | ||
789 | int cur_epid = 0; | ||
790 | int epidx; | ||
791 | size_t frame_len; | ||
792 | void *frame; | ||
793 | |||
794 | for (epidx = 0; epidx < hw->max_epid; epidx++) { | ||
795 | if (epidx == hw->my_epid) | ||
796 | continue; | ||
797 | |||
798 | adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status |= | ||
799 | FJES_RX_POLL_WORK; | ||
800 | } | ||
801 | |||
802 | while (work_done < budget) { | ||
803 | prefetch(&adapter->hw); | ||
804 | frame = fjes_rxframe_get(adapter, &frame_len, &cur_epid); | ||
805 | |||
806 | if (frame) { | ||
807 | skb = napi_alloc_skb(napi, frame_len); | ||
808 | if (!skb) { | ||
809 | adapter->stats64.rx_dropped += 1; | ||
810 | hw->ep_shm_info[cur_epid].net_stats | ||
811 | .rx_dropped += 1; | ||
812 | adapter->stats64.rx_errors += 1; | ||
813 | hw->ep_shm_info[cur_epid].net_stats | ||
814 | .rx_errors += 1; | ||
815 | } else { | ||
816 | memcpy(skb_put(skb, frame_len), | ||
817 | frame, frame_len); | ||
818 | skb->protocol = eth_type_trans(skb, netdev); | ||
819 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
820 | |||
821 | netif_receive_skb(skb); | ||
822 | |||
823 | work_done++; | ||
824 | |||
825 | adapter->stats64.rx_packets += 1; | ||
826 | hw->ep_shm_info[cur_epid].net_stats | ||
827 | .rx_packets += 1; | ||
828 | adapter->stats64.rx_bytes += frame_len; | ||
829 | hw->ep_shm_info[cur_epid].net_stats | ||
830 | .rx_bytes += frame_len; | ||
831 | |||
832 | if (is_multicast_ether_addr( | ||
833 | ((struct ethhdr *)frame)->h_dest)) { | ||
834 | adapter->stats64.multicast += 1; | ||
835 | hw->ep_shm_info[cur_epid].net_stats | ||
836 | .multicast += 1; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | fjes_rxframe_release(adapter, cur_epid); | ||
841 | adapter->unset_rx_last = true; | ||
842 | } else { | ||
843 | break; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | if (work_done < budget) { | ||
848 | napi_complete(napi); | ||
849 | |||
850 | if (adapter->unset_rx_last) { | ||
851 | adapter->rx_last_jiffies = jiffies; | ||
852 | adapter->unset_rx_last = false; | ||
853 | } | ||
854 | |||
855 | if (((long)jiffies - (long)adapter->rx_last_jiffies) < 3) { | ||
856 | napi_reschedule(napi); | ||
857 | } else { | ||
858 | for (epidx = 0; epidx < hw->max_epid; epidx++) { | ||
859 | if (epidx == hw->my_epid) | ||
860 | continue; | ||
861 | adapter->hw.ep_shm_info[epidx] | ||
862 | .tx.info->v1i.rx_status &= | ||
863 | ~FJES_RX_POLL_WORK; | ||
864 | } | ||
865 | |||
866 | fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, false); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | return work_done; | ||
871 | } | ||
872 | |||
712 | /* fjes_probe - Device Initialization Routine */ | 873 | /* fjes_probe - Device Initialization Routine */ |
713 | static int fjes_probe(struct platform_device *plat_dev) | 874 | static int fjes_probe(struct platform_device *plat_dev) |
714 | { | 875 | { |
@@ -797,6 +958,8 @@ static int fjes_remove(struct platform_device *plat_dev) | |||
797 | 958 | ||
798 | fjes_hw_exit(hw); | 959 | fjes_hw_exit(hw); |
799 | 960 | ||
961 | netif_napi_del(&adapter->napi); | ||
962 | |||
800 | free_netdev(netdev); | 963 | free_netdev(netdev); |
801 | 964 | ||
802 | return 0; | 965 | return 0; |
@@ -804,6 +967,10 @@ static int fjes_remove(struct platform_device *plat_dev) | |||
804 | 967 | ||
805 | static int fjes_sw_init(struct fjes_adapter *adapter) | 968 | static int fjes_sw_init(struct fjes_adapter *adapter) |
806 | { | 969 | { |
970 | struct net_device *netdev = adapter->netdev; | ||
971 | |||
972 | netif_napi_add(netdev, &adapter->napi, fjes_poll, 64); | ||
973 | |||
807 | return 0; | 974 | return 0; |
808 | } | 975 | } |
809 | 976 | ||