solos: First attempt at DMA support
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
c0fe30265a
commit
909372317e
|
@ -55,6 +55,8 @@
|
||||||
#define FLASH_BUSY 0x60
|
#define FLASH_BUSY 0x60
|
||||||
#define FPGA_MODE 0x5C
|
#define FPGA_MODE 0x5C
|
||||||
#define FLASH_MODE 0x58
|
#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 DATA_RAM_SIZE 32768
|
||||||
#define BUF_SIZE 4096
|
#define BUF_SIZE 4096
|
||||||
|
@ -78,6 +80,14 @@ struct pkt_hdr {
|
||||||
__le16 type;
|
__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_DATA 0
|
||||||
#define PKT_COMMAND 1
|
#define PKT_COMMAND 1
|
||||||
#define PKT_POPEN 3
|
#define PKT_POPEN 3
|
||||||
|
@ -98,8 +108,11 @@ struct solos_card {
|
||||||
struct list_head param_queue;
|
struct list_head param_queue;
|
||||||
struct sk_buff_head tx_queue[4];
|
struct sk_buff_head tx_queue[4];
|
||||||
struct sk_buff_head cli_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 param_wq;
|
||||||
wait_queue_head_t fw_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++) {
|
for (port = 0; port < card->nr_ports; port++) {
|
||||||
if (card_flags & (0x10 << port)) {
|
if (card_flags & (0x10 << port)) {
|
||||||
struct pkt_hdr header;
|
struct pkt_hdr _hdr, *header;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct atm_vcc *vcc;
|
struct atm_vcc *vcc;
|
||||||
int size;
|
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;
|
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);
|
skb = alloc_skb(size + 1, GFP_ATOMIC);
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
|
@ -607,25 +640,25 @@ void solos_bh(unsigned long card_arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy_fromio(skb_put(skb, size),
|
memcpy_fromio(skb_put(skb, size),
|
||||||
RX_BUF(card, port) + sizeof(header),
|
RX_BUF(card, port) + sizeof(*header),
|
||||||
size);
|
size);
|
||||||
|
}
|
||||||
if (atmdebug) {
|
if (atmdebug) {
|
||||||
dev_info(&card->dev->dev, "Received: device %d\n", port);
|
dev_info(&card->dev->dev, "Received: device %d\n", port);
|
||||||
dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n",
|
dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n",
|
||||||
size, le16_to_cpu(header.vpi),
|
size, le16_to_cpu(header->vpi),
|
||||||
le16_to_cpu(header.vci));
|
le16_to_cpu(header->vci));
|
||||||
print_buffer(skb);
|
print_buffer(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (le16_to_cpu(header.type)) {
|
switch (le16_to_cpu(header->type)) {
|
||||||
case PKT_DATA:
|
case PKT_DATA:
|
||||||
vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi),
|
vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi),
|
||||||
le16_to_cpu(header.vci));
|
le16_to_cpu(header->vci));
|
||||||
if (!vcc) {
|
if (!vcc) {
|
||||||
if (net_ratelimit())
|
if (net_ratelimit())
|
||||||
dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n",
|
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);
|
port);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -839,7 +872,7 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
|
||||||
{
|
{
|
||||||
int old_len;
|
int old_len;
|
||||||
|
|
||||||
*(void **)skb->cb = vcc;
|
SKB_CB(skb)->vcc = vcc;
|
||||||
|
|
||||||
spin_lock(&card->tx_queue_lock);
|
spin_lock(&card->tx_queue_lock);
|
||||||
old_len = skb_queue_len(&card->tx_queue[port]);
|
old_len = skb_queue_len(&card->tx_queue[port]);
|
||||||
|
@ -881,17 +914,37 @@ static int fpga_tx(struct solos_card *card)
|
||||||
port);
|
port);
|
||||||
print_buffer(skb);
|
print_buffer(skb);
|
||||||
}
|
}
|
||||||
memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
|
if (card->using_dma) {
|
||||||
|
if (card->tx_skb[port]) {
|
||||||
|
struct sk_buff *oldskb = card->tx_skb[port];
|
||||||
|
|
||||||
vcc = *(void **)skb->cb;
|
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 = SKB_CB(skb)->vcc;
|
||||||
|
|
||||||
if (vcc) {
|
if (vcc) {
|
||||||
atomic_inc(&vcc->stats->tx);
|
atomic_inc(&vcc->stats->tx);
|
||||||
solos_pop(vcc, skb);
|
solos_pop(vcc, skb);
|
||||||
} else
|
} else
|
||||||
dev_kfree_skb_irq(skb);
|
dev_kfree_skb_irq(skb);
|
||||||
|
}
|
||||||
tx_started |= 1 << port; //Set TX full flag
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tx_started)
|
if (tx_started)
|
||||||
|
@ -999,6 +1052,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
goto out;
|
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");
|
err = pci_request_regions(dev, "solos");
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_warn(&dev->dev, "Failed to request regions\n");
|
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",
|
dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
|
||||||
major_ver, minor_ver, fpga_ver);
|
major_ver, minor_ver, fpga_ver);
|
||||||
|
|
||||||
|
if (fpga_ver > 27)
|
||||||
|
card->using_dma = 1;
|
||||||
|
|
||||||
card->nr_ports = 2; /* FIXME: Detect daughterboard */
|
card->nr_ports = 2; /* FIXME: Detect daughterboard */
|
||||||
|
|
||||||
pci_set_drvdata(dev, card);
|
pci_set_drvdata(dev, card);
|
||||||
|
|
Loading…
Reference in New Issue