diff options
| -rw-r--r-- | drivers/net/ks8842.c | 464 | ||||
| -rw-r--r-- | include/linux/ks8842.h | 4 |
2 files changed, 447 insertions, 21 deletions
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 289b0bee3462..3fe38c787f29 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c | |||
| @@ -30,6 +30,9 @@ | |||
| 30 | #include <linux/etherdevice.h> | 30 | #include <linux/etherdevice.h> |
| 31 | #include <linux/ethtool.h> | 31 | #include <linux/ethtool.h> |
| 32 | #include <linux/ks8842.h> | 32 | #include <linux/ks8842.h> |
| 33 | #include <linux/dmaengine.h> | ||
| 34 | #include <linux/dma-mapping.h> | ||
| 35 | #include <linux/scatterlist.h> | ||
| 33 | 36 | ||
| 34 | #define DRV_NAME "ks8842" | 37 | #define DRV_NAME "ks8842" |
| 35 | 38 | ||
| @@ -82,6 +85,15 @@ | |||
| 82 | #define IRQ_RX_ERROR 0x0080 | 85 | #define IRQ_RX_ERROR 0x0080 |
| 83 | #define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \ | 86 | #define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \ |
| 84 | IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR) | 87 | IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR) |
| 88 | /* When running via timberdale in DMA mode, the RX interrupt should be | ||
| 89 | enabled in the KS8842, but not in the FPGA IP, since the IP handles | ||
| 90 | RX DMA internally. | ||
| 91 | TX interrupts are not needed it is handled by the FPGA the driver is | ||
| 92 | notified via DMA callbacks. | ||
| 93 | */ | ||
| 94 | #define ENABLED_IRQS_DMA_IP (IRQ_LINK_CHANGE | IRQ_RX_STOPPED | \ | ||
| 95 | IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR) | ||
| 96 | #define ENABLED_IRQS_DMA (ENABLED_IRQS_DMA_IP | IRQ_RX) | ||
| 85 | #define REG_ISR 0x02 | 97 | #define REG_ISR 0x02 |
| 86 | #define REG_RXSR 0x04 | 98 | #define REG_RXSR 0x04 |
| 87 | #define RXSR_VALID 0x8000 | 99 | #define RXSR_VALID 0x8000 |
| @@ -124,6 +136,28 @@ | |||
| 124 | #define MICREL_KS884X 0x01 /* 0=Timeberdale(FPGA), 1=Micrel */ | 136 | #define MICREL_KS884X 0x01 /* 0=Timeberdale(FPGA), 1=Micrel */ |
| 125 | #define KS884X_16BIT 0x02 /* 1=16bit, 0=32bit */ | 137 | #define KS884X_16BIT 0x02 /* 1=16bit, 0=32bit */ |
| 126 | 138 | ||
| 139 | #define DMA_BUFFER_SIZE 2048 | ||
| 140 | |||
| 141 | struct ks8842_tx_dma_ctl { | ||
| 142 | struct dma_chan *chan; | ||
| 143 | struct dma_async_tx_descriptor *adesc; | ||
| 144 | void *buf; | ||
| 145 | struct scatterlist sg; | ||
| 146 | int channel; | ||
| 147 | }; | ||
| 148 | |||
| 149 | struct ks8842_rx_dma_ctl { | ||
| 150 | struct dma_chan *chan; | ||
| 151 | struct dma_async_tx_descriptor *adesc; | ||
| 152 | struct sk_buff *skb; | ||
| 153 | struct scatterlist sg; | ||
| 154 | struct tasklet_struct tasklet; | ||
| 155 | int channel; | ||
| 156 | }; | ||
| 157 | |||
| 158 | #define KS8842_USE_DMA(adapter) (((adapter)->dma_tx.channel != -1) && \ | ||
| 159 | ((adapter)->dma_rx.channel != -1)) | ||
| 160 | |||
| 127 | struct ks8842_adapter { | 161 | struct ks8842_adapter { |
| 128 | void __iomem *hw_addr; | 162 | void __iomem *hw_addr; |
| 129 | int irq; | 163 | int irq; |
| @@ -132,8 +166,19 @@ struct ks8842_adapter { | |||
| 132 | spinlock_t lock; /* spinlock to be interrupt safe */ | 166 | spinlock_t lock; /* spinlock to be interrupt safe */ |
| 133 | struct work_struct timeout_work; | 167 | struct work_struct timeout_work; |
| 134 | struct net_device *netdev; | 168 | struct net_device *netdev; |
| 169 | struct device *dev; | ||
| 170 | struct ks8842_tx_dma_ctl dma_tx; | ||
| 171 | struct ks8842_rx_dma_ctl dma_rx; | ||
| 135 | }; | 172 | }; |
| 136 | 173 | ||
| 174 | static void ks8842_dma_rx_cb(void *data); | ||
| 175 | static void ks8842_dma_tx_cb(void *data); | ||
| 176 | |||
| 177 | static inline void ks8842_resume_dma(struct ks8842_adapter *adapter) | ||
| 178 | { | ||
| 179 | iowrite32(1, adapter->hw_addr + REQ_TIMB_DMA_RESUME); | ||
| 180 | } | ||
| 181 | |||
| 137 | static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank) | 182 | static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank) |
| 138 | { | 183 | { |
| 139 | iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK); | 184 | iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK); |
| @@ -297,8 +342,19 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter) | |||
| 297 | ks8842_write16(adapter, 18, 0xffff, REG_ISR); | 342 | ks8842_write16(adapter, 18, 0xffff, REG_ISR); |
| 298 | 343 | ||
| 299 | /* enable interrupts */ | 344 | /* enable interrupts */ |
| 300 | ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); | 345 | if (KS8842_USE_DMA(adapter)) { |
| 301 | 346 | /* When running in DMA Mode the RX interrupt is not enabled in | |
| 347 | timberdale because RX data is received by DMA callbacks | ||
| 348 | it must still be enabled in the KS8842 because it indicates | ||
| 349 | to timberdale when there is RX data for it's DMA FIFOs */ | ||
| 350 | iowrite16(ENABLED_IRQS_DMA_IP, adapter->hw_addr + REG_TIMB_IER); | ||
| 351 | ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER); | ||
| 352 | } else { | ||
| 353 | if (!(adapter->conf_flags & MICREL_KS884X)) | ||
| 354 | iowrite16(ENABLED_IRQS, | ||
| 355 | adapter->hw_addr + REG_TIMB_IER); | ||
| 356 | ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); | ||
| 357 | } | ||
| 302 | /* enable the switch */ | 358 | /* enable the switch */ |
| 303 | ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); | 359 | ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); |
| 304 | } | 360 | } |
| @@ -371,6 +427,53 @@ static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter) | |||
| 371 | return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff; | 427 | return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff; |
| 372 | } | 428 | } |
| 373 | 429 | ||
| 430 | static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev) | ||
| 431 | { | ||
| 432 | struct ks8842_adapter *adapter = netdev_priv(netdev); | ||
| 433 | struct ks8842_tx_dma_ctl *ctl = &adapter->dma_tx; | ||
| 434 | u8 *buf = ctl->buf; | ||
| 435 | |||
| 436 | if (ctl->adesc) { | ||
| 437 | netdev_dbg(netdev, "%s: TX ongoing\n", __func__); | ||
| 438 | /* transfer ongoing */ | ||
| 439 | return NETDEV_TX_BUSY; | ||
| 440 | } | ||
| 441 | |||
| 442 | sg_dma_len(&ctl->sg) = skb->len + sizeof(u32); | ||
| 443 | |||
| 444 | /* copy data to the TX buffer */ | ||
| 445 | /* the control word, enable IRQ, port 1 and the length */ | ||
| 446 | *buf++ = 0x00; | ||
| 447 | *buf++ = 0x01; /* Port 1 */ | ||
| 448 | *buf++ = skb->len & 0xff; | ||
| 449 | *buf++ = (skb->len >> 8) & 0xff; | ||
| 450 | skb_copy_from_linear_data(skb, buf, skb->len); | ||
| 451 | |||
| 452 | dma_sync_single_range_for_device(adapter->dev, | ||
| 453 | sg_dma_address(&ctl->sg), 0, sg_dma_len(&ctl->sg), | ||
| 454 | DMA_TO_DEVICE); | ||
| 455 | |||
| 456 | /* make sure the length is a multiple of 4 */ | ||
| 457 | if (sg_dma_len(&ctl->sg) % 4) | ||
| 458 | sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4; | ||
| 459 | |||
| 460 | ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan, | ||
| 461 | &ctl->sg, 1, DMA_TO_DEVICE, | ||
| 462 | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); | ||
| 463 | if (!ctl->adesc) | ||
| 464 | return NETDEV_TX_BUSY; | ||
| 465 | |||
| 466 | ctl->adesc->callback_param = netdev; | ||
| 467 | ctl->adesc->callback = ks8842_dma_tx_cb; | ||
| 468 | ctl->adesc->tx_submit(ctl->adesc); | ||
| 469 | |||
| 470 | netdev->stats.tx_bytes += skb->len; | ||
| 471 | |||
| 472 | dev_kfree_skb(skb); | ||
| 473 | |||
| 474 | return NETDEV_TX_OK; | ||
| 475 | } | ||
| 476 | |||
| 374 | static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) | 477 | static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) |
| 375 | { | 478 | { |
| 376 | struct ks8842_adapter *adapter = netdev_priv(netdev); | 479 | struct ks8842_adapter *adapter = netdev_priv(netdev); |
| @@ -422,6 +525,121 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) | |||
| 422 | return NETDEV_TX_OK; | 525 | return NETDEV_TX_OK; |
| 423 | } | 526 | } |
| 424 | 527 | ||
| 528 | static void ks8842_update_rx_err_counters(struct net_device *netdev, u32 status) | ||
| 529 | { | ||
| 530 | netdev_dbg(netdev, "RX error, status: %x\n", status); | ||
| 531 | |||
| 532 | netdev->stats.rx_errors++; | ||
| 533 | if (status & RXSR_TOO_LONG) | ||
| 534 | netdev->stats.rx_length_errors++; | ||
| 535 | if (status & RXSR_CRC_ERROR) | ||
| 536 | netdev->stats.rx_crc_errors++; | ||
| 537 | if (status & RXSR_RUNT) | ||
| 538 | netdev->stats.rx_frame_errors++; | ||
| 539 | } | ||
| 540 | |||
| 541 | static void ks8842_update_rx_counters(struct net_device *netdev, u32 status, | ||
| 542 | int len) | ||
| 543 | { | ||
| 544 | netdev_dbg(netdev, "RX packet, len: %d\n", len); | ||
| 545 | |||
| 546 | netdev->stats.rx_packets++; | ||
| 547 | netdev->stats.rx_bytes += len; | ||
| 548 | if (status & RXSR_MULTICAST) | ||
| 549 | netdev->stats.multicast++; | ||
| 550 | } | ||
| 551 | |||
| 552 | static int __ks8842_start_new_rx_dma(struct net_device *netdev) | ||
| 553 | { | ||
| 554 | struct ks8842_adapter *adapter = netdev_priv(netdev); | ||
| 555 | struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx; | ||
| 556 | struct scatterlist *sg = &ctl->sg; | ||
| 557 | int err; | ||
| 558 | |||
| 559 | ctl->skb = netd | ||
