diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2009-01-28 00:46:56 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-01-28 00:46:56 -0500 |
commit | 909372317e67bdbbfced5dab3ade3437e3f2b254 (patch) | |
tree | afb45c7a2537df688b1a56bec9b8d11591a4cdae /drivers/atm | |
parent | c0fe30265a1fe3a69e0ce0d08b49de1dda9c1190 (diff) |
solos: First attempt at DMA support
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/atm')
-rw-r--r-- | drivers/atm/solos-pci.c | 118 |
1 files changed, 90 insertions, 28 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index b7d4af3df2a6..63c9ad03aec8 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -55,6 +55,8 @@ | |||
55 | #define FLASH_BUSY 0x60 | 55 | #define FLASH_BUSY 0x60 |
56 | #define FPGA_MODE 0x5C | 56 | #define FPGA_MODE 0x5C |
57 | #define FLASH_MODE 0x58 | 57 | #define FLASH_MODE 0x58 |
58 | #define TX_DMA_ADDR(port) (0x40 + (4 * (port))) | ||
59 | #define RX_DMA_ADDR(port) (0x30 + (4 * (port))) | ||
58 | 60 | ||
59 | #define DATA_RAM_SIZE 32768 | 61 | #define DATA_RAM_SIZE 32768 |
60 | #define BUF_SIZE 4096 | 62 | #define BUF_SIZE 4096 |
@@ -78,6 +80,14 @@ struct pkt_hdr { | |||
78 | __le16 type; | 80 | __le16 type; |
79 | }; | 81 | }; |
80 | 82 | ||
83 | struct solos_skb_cb { | ||
84 | struct atm_vcc *vcc; | ||
85 | uint32_t dma_addr; | ||
86 | }; | ||
87 | |||
88 | |||
89 | #define SKB_CB(skb) ((struct solos_skb_cb *)skb->cb) | ||
90 | |||
81 | #define PKT_DATA 0 | 91 | #define PKT_DATA 0 |
82 | #define PKT_COMMAND 1 | 92 | #define PKT_COMMAND 1 |
83 | #define PKT_POPEN 3 | 93 | #define PKT_POPEN 3 |
@@ -98,8 +108,11 @@ struct solos_card { | |||
98 | struct list_head param_queue; | 108 | struct list_head param_queue; |
99 | struct sk_buff_head tx_queue[4]; | 109 | struct sk_buff_head tx_queue[4]; |
100 | struct sk_buff_head cli_queue[4]; | 110 | struct sk_buff_head cli_queue[4]; |
111 | struct sk_buff *tx_skb[4]; | ||
112 | struct sk_buff *rx_skb[4]; | ||
101 | wait_queue_head_t param_wq; | 113 | wait_queue_head_t param_wq; |
102 | wait_queue_head_t fw_wq; | 114 | wait_queue_head_t fw_wq; |
115 | int using_dma; | ||
103 | }; | 116 | }; |
104 | 117 | ||
105 | 118 | ||
@@ -588,44 +601,64 @@ void solos_bh(unsigned long card_arg) | |||
588 | 601 | ||
589 | for (port = 0; port < card->nr_ports; port++) { | 602 | for (port = 0; port < card->nr_ports; port++) { |
590 | if (card_flags & (0x10 << port)) { | 603 | if (card_flags & (0x10 << port)) { |
591 | struct pkt_hdr header; | 604 | struct pkt_hdr _hdr, *header; |
592 | struct sk_buff *skb; | 605 | struct sk_buff *skb; |
593 | struct atm_vcc *vcc; | 606 | struct atm_vcc *vcc; |
594 | int size; | 607 | int size; |
595 | 608 | ||
596 | rx_done |= 0x10 << port; | 609 | if (card->using_dma) { |
610 | skb = card->rx_skb[port]; | ||
611 | pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, skb->len, | ||
612 | PCI_DMA_FROMDEVICE); | ||
613 | |||
614 | card->rx_skb[port] = alloc_skb(2048, GFP_ATOMIC); | ||
615 | if (card->rx_skb[port]) { | ||
616 | SKB_CB(card->rx_skb[port])->dma_addr = | ||
617 | pci_map_single(card->dev, skb->data, skb->len, | ||
618 | PCI_DMA_FROMDEVICE); | ||
619 | iowrite32(SKB_CB(card->rx_skb[port])->dma_addr, | ||
620 | card->config_regs + RX_DMA_ADDR(port)); | ||
621 | } | ||
622 | header = (void *)skb->data; | ||
623 | size = le16_to_cpu(header->size); | ||
624 | skb_put(skb, size + sizeof(*header)); | ||
625 | skb_pull(skb, sizeof(*header)); | ||
626 | } else { | ||
627 | header = &_hdr; | ||
597 | 628 | ||
598 | memcpy_fromio(&header, RX_BUF(card, port), sizeof(header)); | 629 | rx_done |= 0x10 << port; |
599 | 630 | ||
600 | size = le16_to_cpu(header.size); | 631 | memcpy_fromio(header, RX_BUF(card, port), sizeof(*header)); |
601 | 632 | ||
602 | skb = alloc_skb(size + 1, GFP_ATOMIC); | 633 | size = le16_to_cpu(header->size); |
603 | if (!skb) { | ||
604 | if (net_ratelimit()) | ||
605 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); | ||
606 | continue; | ||
607 | } | ||
608 | 634 | ||
609 | memcpy_fromio(skb_put(skb, size), | 635 | skb = alloc_skb(size + 1, GFP_ATOMIC); |
610 | RX_BUF(card, port) + sizeof(header), | 636 | if (!skb) { |
611 | size); | 637 | if (net_ratelimit()) |
638 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); | ||
639 | continue; | ||
640 | } | ||
612 | 641 | ||
642 | memcpy_fromio(skb_put(skb, size), | ||
643 | RX_BUF(card, port) + sizeof(*header), | ||
644 | size); | ||
645 | } | ||
613 | if (atmdebug) { | 646 | if (atmdebug) { |
614 | dev_info(&card->dev->dev, "Received: device %d\n", port); | 647 | dev_info(&card->dev->dev, "Received: device %d\n", port); |
615 | dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", | 648 | dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", |
616 | size, le16_to_cpu(header.vpi), | 649 | size, le16_to_cpu(header->vpi), |
617 | le16_to_cpu(header.vci)); | 650 | le16_to_cpu(header->vci)); |
618 | print_buffer(skb); | 651 | print_buffer(skb); |
619 | } | 652 | } |
620 | 653 | ||
621 | switch (le16_to_cpu(header.type)) { | 654 | switch (le16_to_cpu(header->type)) { |
622 | case PKT_DATA: | 655 | case PKT_DATA: |
623 | vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi), | 656 | vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi), |
624 | le16_to_cpu(header.vci)); | 657 | le16_to_cpu(header->vci)); |
625 | if (!vcc) { | 658 | if (!vcc) { |
626 | if (net_ratelimit()) | 659 | if (net_ratelimit()) |
627 | dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n", | 660 | dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n", |
628 | le16_to_cpu(header.vci), le16_to_cpu(header.vpi), | 661 | le16_to_cpu(header->vci), le16_to_cpu(header->vpi), |
629 | port); | 662 | port); |
630 | continue; | 663 | continue; |
631 | } | 664 | } |
@@ -839,7 +872,7 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | |||
839 | { | 872 | { |
840 | int old_len; | 873 | int old_len; |
841 | 874 | ||
842 | *(void **)skb->cb = vcc; | 875 | SKB_CB(skb)->vcc = vcc; |
843 | 876 | ||
844 | spin_lock(&card->tx_queue_lock); | 877 | spin_lock(&card->tx_queue_lock); |
845 | old_len = skb_queue_len(&card->tx_queue[port]); | 878 | old_len = skb_queue_len(&card->tx_queue[port]); |
@@ -881,17 +914,37 @@ static int fpga_tx(struct solos_card *card) | |||
881 | port); | 914 | port); |
882 | print_buffer(skb); | 915 | print_buffer(skb); |
883 | } | 916 | } |
884 | memcpy_toio(TX_BUF(card, port), skb->data, skb->len); | 917 | if (card->using_dma) { |
918 | if (card->tx_skb[port]) { | ||
919 | struct sk_buff *oldskb = card->tx_skb[port]; | ||
885 | 920 | ||
886 | vcc = *(void **)skb->cb; | 921 | pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, |
922 | oldskb->len, PCI_DMA_TODEVICE); | ||
887 | 923 | ||
888 | if (vcc) { | 924 | vcc = SKB_CB(oldskb)->vcc; |
889 | atomic_inc(&vcc->stats->tx); | ||
890 | solos_pop(vcc, skb); | ||
891 | } else | ||
892 | dev_kfree_skb_irq(skb); | ||
893 | 925 | ||
894 | tx_started |= 1 << port; //Set TX full flag | 926 | if (vcc) { |
927 | atomic_inc(&vcc->stats->tx); | ||
928 | solos_pop(vcc, oldskb); | ||
929 | } else | ||
930 | dev_kfree_skb_irq(oldskb); | ||
931 | } | ||
932 | |||
933 | SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data, | ||
934 | skb->len, PCI_DMA_TODEVICE); | ||
935 | iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + TX_DMA_ADDR(port)); | ||
936 | } else { | ||
937 | memcpy_toio(TX_BUF(card, port), skb->data, skb->len); | ||
938 | tx_started |= 1 << port; //Set TX full flag | ||
939 | |||
940 | vcc = SKB_CB(skb)->vcc; | ||
941 | |||
942 | if (vcc) { | ||
943 | atomic_inc(&vcc->stats->tx); | ||
944 | solos_pop(vcc, skb); | ||
945 | } else | ||
946 | dev_kfree_skb_irq(skb); | ||
947 | } | ||
895 | } | 948 | } |
896 | } | 949 | } |
897 | if (tx_started) | 950 | if (tx_started) |
@@ -999,6 +1052,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
999 | goto out; | 1052 | goto out; |
1000 | } | 1053 | } |
1001 | 1054 | ||
1055 | err = pci_set_dma_mask(dev, DMA_32BIT_MASK); | ||
1056 | if (err) { | ||
1057 | dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n"); | ||
1058 | goto out; | ||
1059 | } | ||
1060 | |||
1002 | err = pci_request_regions(dev, "solos"); | 1061 | err = pci_request_regions(dev, "solos"); |
1003 | if (err) { | 1062 | if (err) { |
1004 | dev_warn(&dev->dev, "Failed to request regions\n"); | 1063 | dev_warn(&dev->dev, "Failed to request regions\n"); |
@@ -1035,6 +1094,9 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1035 | dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", | 1094 | dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", |
1036 | major_ver, minor_ver, fpga_ver); | 1095 | major_ver, minor_ver, fpga_ver); |
1037 | 1096 | ||
1097 | if (fpga_ver > 27) | ||
1098 | card->using_dma = 1; | ||
1099 | |||
1038 | card->nr_ports = 2; /* FIXME: Detect daughterboard */ | 1100 | card->nr_ports = 2; /* FIXME: Detect daughterboard */ |
1039 | 1101 | ||
1040 | pci_set_drvdata(dev, card); | 1102 | pci_set_drvdata(dev, card); |