diff options
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r-- | drivers/net/r8169.c | 113 |
1 files changed, 62 insertions, 51 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0b6e8c89683..3b19e0ce290 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -66,7 +66,6 @@ static const int multicast_filter_limit = 32; | |||
66 | #define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ | 66 | #define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ |
67 | #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ | 67 | #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ |
68 | #define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ | 68 | #define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ |
69 | #define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */ | ||
70 | #define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */ | 69 | #define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */ |
71 | #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ | 70 | #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ |
72 | 71 | ||
@@ -2357,10 +2356,10 @@ static u16 rtl_rw_cpluscmd(void __iomem *ioaddr) | |||
2357 | return cmd; | 2356 | return cmd; |
2358 | } | 2357 | } |
2359 | 2358 | ||
2360 | static void rtl_set_rx_max_size(void __iomem *ioaddr) | 2359 | static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz) |
2361 | { | 2360 | { |
2362 | /* Low hurts. Let's disable the filtering. */ | 2361 | /* Low hurts. Let's disable the filtering. */ |
2363 | RTL_W16(RxMaxSize, 16383); | 2362 | RTL_W16(RxMaxSize, rx_buf_sz); |
2364 | } | 2363 | } |
2365 | 2364 | ||
2366 | static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version) | 2365 | static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version) |
@@ -2407,7 +2406,7 @@ static void rtl_hw_start_8169(struct net_device *dev) | |||
2407 | 2406 | ||
2408 | RTL_W8(EarlyTxThres, EarlyTxThld); | 2407 | RTL_W8(EarlyTxThres, EarlyTxThld); |
2409 | 2408 | ||
2410 | rtl_set_rx_max_size(ioaddr); | 2409 | rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz); |
2411 | 2410 | ||
2412 | if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || | 2411 | if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || |
2413 | (tp->mac_version == RTL_GIGA_MAC_VER_02) || | 2412 | (tp->mac_version == RTL_GIGA_MAC_VER_02) || |
@@ -2668,7 +2667,7 @@ static void rtl_hw_start_8168(struct net_device *dev) | |||
2668 | 2667 | ||
2669 | RTL_W8(EarlyTxThres, EarlyTxThld); | 2668 | RTL_W8(EarlyTxThres, EarlyTxThld); |
2670 | 2669 | ||
2671 | rtl_set_rx_max_size(ioaddr); | 2670 | rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz); |
2672 | 2671 | ||
2673 | tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1; | 2672 | tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1; |
2674 | 2673 | ||
@@ -2846,7 +2845,7 @@ static void rtl_hw_start_8101(struct net_device *dev) | |||
2846 | 2845 | ||
2847 | RTL_W8(EarlyTxThres, EarlyTxThld); | 2846 | RTL_W8(EarlyTxThres, EarlyTxThld); |
2848 | 2847 | ||
2849 | rtl_set_rx_max_size(ioaddr); | 2848 | rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz); |
2850 | 2849 | ||
2851 | tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; | 2850 | tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; |
2852 | 2851 | ||
@@ -3554,54 +3553,64 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) | |||
3554 | int handled = 0; | 3553 | int handled = 0; |
3555 | int status; | 3554 | int status; |
3556 | 3555 | ||
3556 | /* loop handling interrupts until we have no new ones or | ||
3557 | * we hit a invalid/hotplug case. | ||
3558 | */ | ||
3557 | status = RTL_R16(IntrStatus); | 3559 | status = RTL_R16(IntrStatus); |
3560 | while (status && status != 0xffff) { | ||
3561 | handled = 1; | ||
3558 | 3562 | ||
3559 | /* hotplug/major error/no more work/shared irq */ | 3563 | /* Handle all of the error cases first. These will reset |
3560 | if ((status == 0xffff) || !status) | 3564 | * the chip, so just exit the loop. |
3561 | goto out; | 3565 | */ |
3562 | 3566 | if (unlikely(!netif_running(dev))) { | |
3563 | handled = 1; | 3567 | rtl8169_asic_down(ioaddr); |
3568 | break; | ||
3569 | } | ||
3564 | 3570 | ||
3565 | if (unlikely(!netif_running(dev))) { | 3571 | /* Work around for rx fifo overflow */ |
3566 | rtl8169_asic_down(ioaddr); | 3572 | if (unlikely(status & RxFIFOOver) && |
3567 | goto out; | 3573 | (tp->mac_version == RTL_GIGA_MAC_VER_11)) { |
3568 | } | 3574 | netif_stop_queue(dev); |
3575 | rtl8169_tx_timeout(dev); | ||
3576 | break; | ||
3577 | } | ||
3569 | 3578 | ||
3570 | status &= tp->intr_mask; | 3579 | if (unlikely(status & SYSErr)) { |
3571 | RTL_W16(IntrStatus, | 3580 | rtl8169_pcierr_interrupt(dev); |
3572 | (status & RxFIFOOver) ? (status | RxOverflow) : status); | 3581 | break; |
3582 | } | ||
3573 | 3583 | ||
3574 | if (!(status & tp->intr_event)) | 3584 | if (status & LinkChg) |
3575 | goto out; | 3585 | rtl8169_check_link_status(dev, tp, ioaddr); |
3576 | 3586 | ||
3577 | /* Work around for rx fifo overflow */ | 3587 | /* We need to see the lastest version of tp->intr_mask to |
3578 | if (unlikely(status & RxFIFOOver) && | 3588 | * avoid ignoring an MSI interrupt and having to wait for |
3579 | (tp->mac_version == RTL_GIGA_MAC_VER_11)) { | 3589 | * another event which may never come. |
3580 | netif_stop_queue(dev); | 3590 | */ |
3581 | rtl8169_tx_timeout(dev); | 3591 | smp_rmb(); |
3582 | goto out; | 3592 | if (status & tp->intr_mask & tp->napi_event) { |
3583 | } | 3593 | RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); |
3594 | tp->intr_mask = ~tp->napi_event; | ||
3595 | |||
3596 | if (likely(napi_schedule_prep(&tp->napi))) | ||
3597 | __napi_schedule(&tp->napi); | ||
3598 | else if (netif_msg_intr(tp)) { | ||
3599 | printk(KERN_INFO "%s: interrupt %04x in poll\n", | ||
3600 | dev->name, status); | ||
3601 | } | ||
3602 | } | ||
3584 | 3603 | ||
3585 | if (unlikely(status & SYSErr)) { | 3604 | /* We only get a new MSI interrupt when all active irq |
3586 | rtl8169_pcierr_interrupt(dev); | 3605 | * sources on the chip have been acknowledged. So, ack |
3587 | goto out; | 3606 | * everything we've seen and check if new sources have become |
3607 | * active to avoid blocking all interrupts from the chip. | ||
3608 | */ | ||
3609 | RTL_W16(IntrStatus, | ||
3610 | (status & RxFIFOOver) ? (status | RxOverflow) : status); | ||
3611 | status = RTL_R16(IntrStatus); | ||
3588 | } | 3612 | } |
3589 | 3613 | ||
3590 | if (status & LinkChg) | ||
3591 | rtl8169_check_link_status(dev, tp, ioaddr); | ||
3592 | |||
3593 | if (status & tp->napi_event) { | ||
3594 | RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); | ||
3595 | tp->intr_mask = ~tp->napi_event; | ||
3596 | |||
3597 | if (likely(napi_schedule_prep(&tp->napi))) | ||
3598 | __napi_schedule(&tp->napi); | ||
3599 | else if (netif_msg_intr(tp)) { | ||
3600 | printk(KERN_INFO "%s: interrupt %04x in poll\n", | ||
3601 | dev->name, status); | ||
3602 | } | ||
3603 | } | ||
3604 | out: | ||
3605 | return IRQ_RETVAL(handled); | 3614 | return IRQ_RETVAL(handled); |
3606 | } | 3615 | } |
3607 | 3616 | ||
@@ -3617,13 +3626,15 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) | |||
3617 | 3626 | ||
3618 | if (work_done < budget) { | 3627 | if (work_done < budget) { |
3619 | napi_complete(napi); | 3628 | napi_complete(napi); |
3620 | tp->intr_mask = 0xffff; | 3629 | |
3621 | /* | 3630 | /* We need for force the visibility of tp->intr_mask |
3622 | * 20040426: the barrier is not strictly required but the | 3631 | * for other CPUs, as we can loose an MSI interrupt |
3623 | * behavior of the irq handler could be less predictable | 3632 | * and potentially wait for a retransmit timeout if we don't. |
3624 | * without it. Btw, the lack of flush for the posted pci | 3633 | * The posted write to IntrMask is safe, as it will |
3625 | * write is safe - FR | 3634 | * eventually make it to the chip and we won't loose anything |
3635 | * until it does. | ||
3626 | */ | 3636 | */ |
3637 | tp->intr_mask = 0xffff; | ||
3627 | smp_wmb(); | 3638 | smp_wmb(); |
3628 | RTL_W16(IntrMask, tp->intr_event); | 3639 | RTL_W16(IntrMask, tp->intr_event); |
3629 | } | 3640 | } |