e100: fix dma error in direction for mapping

The e100 driver triggers BUG_ON(buf->direction != dir)
by doing pci_map_single(..., PCI_DMA_BIDIRECTIONAL)
and pci_dma_sync_single_for_device(..., PCI_DMA_TODEVICE).

Changing the DMA direction, especially with dmabounce will result
in unexpected behaviour.

Reported-by: Anders Grafstrom <grfstrm@users.sourceforge.net>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jesse Brandeburg 2008-11-14 13:51:54 +00:00 коммит произвёл David S. Miller
Родитель ac450208de
Коммит 773c9c1f77
1 изменённых файлов: 10 добавлений и 10 удалений

Просмотреть файл

@ -166,7 +166,7 @@
#define DRV_NAME "e100" #define DRV_NAME "e100"
#define DRV_EXT "-NAPI" #define DRV_EXT "-NAPI"
#define DRV_VERSION "3.5.23-k4"DRV_EXT #define DRV_VERSION "3.5.23-k6"DRV_EXT
#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" #define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
@ -1804,7 +1804,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
put_unaligned_le32(rx->dma_addr, &prev_rfd->link); put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
sizeof(struct rfd), PCI_DMA_TODEVICE); sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
} }
return 0; return 0;
@ -1823,7 +1823,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
/* Need to sync before taking a peek at cb_complete bit */ /* Need to sync before taking a peek at cb_complete bit */
pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr, pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,
sizeof(struct rfd), PCI_DMA_FROMDEVICE); sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
rfd_status = le16_to_cpu(rfd->status); rfd_status = le16_to_cpu(rfd->status);
DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
@ -1850,7 +1850,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
/* Get data */ /* Get data */
pci_unmap_single(nic->pdev, rx->dma_addr, pci_unmap_single(nic->pdev, rx->dma_addr,
RFD_BUF_LEN, PCI_DMA_FROMDEVICE); RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
/* If this buffer has the el bit, but we think the receiver /* If this buffer has the el bit, but we think the receiver
* is still running, check to see if it really stopped while * is still running, check to see if it really stopped while
@ -1943,7 +1943,7 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
new_before_last_rfd->command |= cpu_to_le16(cb_el); new_before_last_rfd->command |= cpu_to_le16(cb_el);
pci_dma_sync_single_for_device(nic->pdev, pci_dma_sync_single_for_device(nic->pdev,
new_before_last_rx->dma_addr, sizeof(struct rfd), new_before_last_rx->dma_addr, sizeof(struct rfd),
PCI_DMA_TODEVICE); PCI_DMA_BIDIRECTIONAL);
/* Now that we have a new stopping point, we can clear the old /* Now that we have a new stopping point, we can clear the old
* stopping point. We must sync twice to get the proper * stopping point. We must sync twice to get the proper
@ -1951,11 +1951,11 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
old_before_last_rfd->command &= ~cpu_to_le16(cb_el); old_before_last_rfd->command &= ~cpu_to_le16(cb_el);
pci_dma_sync_single_for_device(nic->pdev, pci_dma_sync_single_for_device(nic->pdev,
old_before_last_rx->dma_addr, sizeof(struct rfd), old_before_last_rx->dma_addr, sizeof(struct rfd),
PCI_DMA_TODEVICE); PCI_DMA_BIDIRECTIONAL);
old_before_last_rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN); old_before_last_rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
pci_dma_sync_single_for_device(nic->pdev, pci_dma_sync_single_for_device(nic->pdev,
old_before_last_rx->dma_addr, sizeof(struct rfd), old_before_last_rx->dma_addr, sizeof(struct rfd),
PCI_DMA_TODEVICE); PCI_DMA_BIDIRECTIONAL);
} }
if(restart_required) { if(restart_required) {
@ -1978,7 +1978,7 @@ static void e100_rx_clean_list(struct nic *nic)
for(rx = nic->rxs, i = 0; i < count; rx++, i++) { for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
if(rx->skb) { if(rx->skb) {
pci_unmap_single(nic->pdev, rx->dma_addr, pci_unmap_single(nic->pdev, rx->dma_addr,
RFD_BUF_LEN, PCI_DMA_FROMDEVICE); RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
dev_kfree_skb(rx->skb); dev_kfree_skb(rx->skb);
} }
} }
@ -2021,7 +2021,7 @@ static int e100_rx_alloc_list(struct nic *nic)
before_last->command |= cpu_to_le16(cb_el); before_last->command |= cpu_to_le16(cb_el);
before_last->size = 0; before_last->size = 0;
pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr, pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr,
sizeof(struct rfd), PCI_DMA_TODEVICE); sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
nic->rx_to_use = nic->rx_to_clean = nic->rxs; nic->rx_to_use = nic->rx_to_clean = nic->rxs;
nic->ru_running = RU_SUSPENDED; nic->ru_running = RU_SUSPENDED;
@ -2222,7 +2222,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
msleep(10); msleep(10);
pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr, pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr,
RFD_BUF_LEN, PCI_DMA_FROMDEVICE); RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd), if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
skb->data, ETH_DATA_LEN)) skb->data, ETH_DATA_LEN))