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

Commit 90937231 authored by David Woodhouse's avatar David Woodhouse
Browse files

solos: First attempt at DMA support

parent c0fe3026
Loading
Loading
Loading
Loading
+90 −28
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@
#define FLASH_BUSY	0x60
#define FPGA_MODE	0x5C
#define FLASH_MODE	0x58
#define TX_DMA_ADDR(port)	(0x40 + (4 * (port)))
#define RX_DMA_ADDR(port)	(0x30 + (4 * (port)))

#define DATA_RAM_SIZE	32768
#define BUF_SIZE	4096
@@ -78,6 +80,14 @@ struct pkt_hdr {
	__le16 type;
};

struct solos_skb_cb {
	struct atm_vcc *vcc;
	uint32_t dma_addr;
};


#define SKB_CB(skb)		((struct solos_skb_cb *)skb->cb)

#define PKT_DATA	0
#define PKT_COMMAND	1
#define PKT_POPEN	3
@@ -98,8 +108,11 @@ struct solos_card {
	struct list_head param_queue;
	struct sk_buff_head tx_queue[4];
	struct sk_buff_head cli_queue[4];
	struct sk_buff *tx_skb[4];
	struct sk_buff *rx_skb[4];
	wait_queue_head_t param_wq;
	wait_queue_head_t fw_wq;
	int using_dma;
};


@@ -588,16 +601,36 @@ void solos_bh(unsigned long card_arg)

	for (port = 0; port < card->nr_ports; port++) {
		if (card_flags & (0x10 << port)) {
			struct pkt_hdr header;
			struct pkt_hdr _hdr, *header;
			struct sk_buff *skb;
			struct atm_vcc *vcc;
			int size;

			if (card->using_dma) {
				skb = card->rx_skb[port];
				pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, skb->len,
						 PCI_DMA_FROMDEVICE);

				card->rx_skb[port] = alloc_skb(2048, GFP_ATOMIC);
				if (card->rx_skb[port]) {
					SKB_CB(card->rx_skb[port])->dma_addr =
						pci_map_single(card->dev, skb->data, skb->len,
							       PCI_DMA_FROMDEVICE);
					iowrite32(SKB_CB(card->rx_skb[port])->dma_addr,
						  card->config_regs + RX_DMA_ADDR(port));
				}
				header = (void *)skb->data;
				size = le16_to_cpu(header->size);
				skb_put(skb, size + sizeof(*header));
				skb_pull(skb, sizeof(*header));
			} else {
				header = &_hdr;

				rx_done |= 0x10 << port;

			memcpy_fromio(&header, RX_BUF(card, port), sizeof(header));
				memcpy_fromio(header, RX_BUF(card, port), sizeof(*header));

			size = le16_to_cpu(header.size);
				size = le16_to_cpu(header->size);

				skb = alloc_skb(size + 1, GFP_ATOMIC);
				if (!skb) {
@@ -607,25 +640,25 @@ void solos_bh(unsigned long card_arg)
				}

				memcpy_fromio(skb_put(skb, size),
				      RX_BUF(card, port) + sizeof(header),
					      RX_BUF(card, port) + sizeof(*header),
					      size);

			}
			if (atmdebug) {
				dev_info(&card->dev->dev, "Received: device %d\n", port);
				dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n",
					 size, le16_to_cpu(header.vpi),
					 le16_to_cpu(header.vci));
					 size, le16_to_cpu(header->vpi),
					 le16_to_cpu(header->vci));
				print_buffer(skb);
			}

			switch (le16_to_cpu(header.type)) {
			switch (le16_to_cpu(header->type)) {
			case PKT_DATA:
				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi),
					       le16_to_cpu(header.vci));
				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi),
					       le16_to_cpu(header->vci));
				if (!vcc) {
					if (net_ratelimit())
						dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n",
							 le16_to_cpu(header.vci), le16_to_cpu(header.vpi),
							 le16_to_cpu(header->vci), le16_to_cpu(header->vpi),
							 port);
					continue;
				}
@@ -839,7 +872,7 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
{
	int old_len;

	*(void **)skb->cb = vcc;
	SKB_CB(skb)->vcc = vcc;

	spin_lock(&card->tx_queue_lock);
	old_len = skb_queue_len(&card->tx_queue[port]);
@@ -881,17 +914,37 @@ static int fpga_tx(struct solos_card *card)
					 port);
				print_buffer(skb);
			}
			if (card->using_dma) {
				if (card->tx_skb[port]) {
					struct sk_buff *oldskb = card->tx_skb[port];

					pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
							 oldskb->len, PCI_DMA_TODEVICE);

					vcc = SKB_CB(oldskb)->vcc;

					if (vcc) {
						atomic_inc(&vcc->stats->tx);
						solos_pop(vcc, oldskb);
					} else
						dev_kfree_skb_irq(oldskb);
				}

				SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
							       skb->len, PCI_DMA_TODEVICE);
				iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + TX_DMA_ADDR(port));
			} else {
				memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
				tx_started |= 1 << port; //Set TX full flag

			vcc = *(void **)skb->cb;
				vcc = SKB_CB(skb)->vcc;

				if (vcc) {
					atomic_inc(&vcc->stats->tx);
					solos_pop(vcc, skb);
				} else
					dev_kfree_skb_irq(skb);

			tx_started |= 1 << port; //Set TX full flag
			}
		}
	}
	if (tx_started)
@@ -999,6 +1052,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
		goto out;
	}

	err = pci_set_dma_mask(dev, DMA_32BIT_MASK);
	if (err) {
		dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n");
		goto out;
	}

	err = pci_request_regions(dev, "solos");
	if (err) {
		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)
	dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
		 major_ver, minor_ver, fpga_ver);

	if (fpga_ver > 27)
		card->using_dma = 1;

	card->nr_ports = 2; /* FIXME: Detect daughterboard */

	pci_set_drvdata(dev, card);