#define RTL8169_TX_TIMEOUT (6*HZ)
#define RTL8169_PHY_TIMEOUT (10*HZ)
-#define RTL_EEPROM_SIG 0x8129
+#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
+#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
#define RTL_EEPROM_SIG_ADDR 0x0000
-#define RTL_EEPROM_MAC_ADDR 0x0007
/* write/read MMIO register */
#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
/* Cfg9346Bits */
Cfg9346_Lock = 0x00,
Cfg9346_Unlock = 0xc0,
- Cfg9346_Program = 0x80, /* Programming mode */
- Cfg9346_EECS = 0x08, /* Chip select */
- Cfg9346_EESK = 0x04, /* Serial data clock */
- Cfg9346_EEDI = 0x02, /* Data input */
- Cfg9346_EEDO = 0x01, /* Data output */
/* rx_mode_bits */
AcceptErr = 0x20,
/* RxConfigBits */
RxCfgFIFOShift = 13,
RxCfgDMAShift = 8,
- RxCfg9356SEL = 6, /* EEPROM type: 0 = 9346, 1 = 9356 */
/* TxConfigBits */
TxInterFrameGapShift = 24,
return;
RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
- cmd = (u64)paddr & DMA_32BIT_MASK;
+ cmd = (u64)paddr & DMA_BIT_MASK(32);
RTL_W32(CounterAddrLow, cmd);
RTL_W32(CounterAddrLow, cmd | CounterDump);
};
-/* Delay between EEPROM clock transitions. Force out buffered PCI writes. */
-#define RTL_EEPROM_DELAY() RTL_R8(Cfg9346)
-#define RTL_EEPROM_READ_CMD 6
-
-/* read 16bit word stored in EEPROM. EEPROM is addressed by words. */
-static u16 rtl_eeprom_read(void __iomem *ioaddr, int addr)
-{
- u16 result = 0;
- int cmd, cmd_len, i;
-
- /* check for EEPROM address size (in bits) */
- if (RTL_R32(RxConfig) & (1 << RxCfg9356SEL)) {
- /* EEPROM is 93C56 */
- cmd_len = 3 + 8; /* 3 bits for command id and 8 for address */
- cmd = (RTL_EEPROM_READ_CMD << 8) | (addr & 0xff);
- } else {
- /* EEPROM is 93C46 */
- cmd_len = 3 + 6; /* 3 bits for command id and 6 for address */
- cmd = (RTL_EEPROM_READ_CMD << 6) | (addr & 0x3f);
- }
-
- /* enter programming mode */
- RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS);
- RTL_EEPROM_DELAY();
-
- /* write command and requested address */
- while (cmd_len--) {
- u8 x = Cfg9346_Program | Cfg9346_EECS;
-
- x |= (cmd & (1 << cmd_len)) ? Cfg9346_EEDI : 0;
-
- /* write a bit */
- RTL_W8(Cfg9346, x);
- RTL_EEPROM_DELAY();
-
- /* raise clock */
- RTL_W8(Cfg9346, x | Cfg9346_EESK);
- RTL_EEPROM_DELAY();
- }
-
- /* lower clock */
- RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS);
- RTL_EEPROM_DELAY();
-
- /* read back 16bit value */
- for (i = 16; i > 0; i--) {
- /* raise clock */
- RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS | Cfg9346_EESK);
- RTL_EEPROM_DELAY();
-
- result <<= 1;
- result |= (RTL_R8(Cfg9346) & Cfg9346_EEDO) ? 1 : 0;
-
- /* lower clock */
- RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS);
- RTL_EEPROM_DELAY();
- }
-
- RTL_W8(Cfg9346, Cfg9346_Program);
- /* leave programming mode */
- RTL_W8(Cfg9346, Cfg9346_Lock);
-
- return result;
-}
-
-static void rtl_init_mac_address(struct rtl8169_private *tp,
- void __iomem *ioaddr)
-{
- struct pci_dev *pdev = tp->pci_dev;
- u16 x;
- u8 mac[8];
-
- /* read EEPROM signature */
- x = rtl_eeprom_read(ioaddr, RTL_EEPROM_SIG_ADDR);
-
- if (x != RTL_EEPROM_SIG) {
- dev_info(&pdev->dev, "Missing EEPROM signature: %04x\n", x);
- return;
- }
-
- /* read MAC address */
- x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR);
- mac[0] = x & 0xff;
- mac[1] = x >> 8;
- x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR + 1);
- mac[2] = x & 0xff;
- mac[3] = x >> 8;
- x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR + 2);
- mac[4] = x & 0xff;
- mac[5] = x >> 8;
-
- if (netif_msg_probe(tp)) {
- DECLARE_MAC_BUF(buf);
-
- dev_info(&pdev->dev, "MAC address found in EEPROM: %s\n",
- print_mac(buf, mac));
- }
-
- if (is_valid_ether_addr(mac))
- rtl_rar_set(tp, mac);
-}
-
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
tp->cp_cmd = PCIMulRW | RxChkSum;
if ((sizeof(dma_addr_t) > 4) &&
- !pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) {
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
tp->cp_cmd |= PCIDAC;
dev->features |= NETIF_F_HIGHDMA;
} else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc < 0) {
if (netif_msg_probe(tp)) {
dev_err(&pdev->dev,
if (!tp->pcie_cap && netif_msg_probe(tp))
dev_info(&pdev->dev, "no PCI Express capability\n");
- /* Unneeded ? Don't mess with Mrs. Murphy. */
- rtl8169_irq_mask_and_ack(ioaddr);
+ RTL_W16(IntrMask, 0x0000);
/* Soft reset the chip. */
RTL_W8(ChipCmd, CmdReset);
msleep_interruptible(1);
}
+ RTL_W16(IntrStatus, 0xffff);
+
/* Identify chip attached to board */
rtl8169_get_mac_version(tp, ioaddr);
tp->mmio_addr = ioaddr;
- rtl_init_mac_address(tp, ioaddr);
-
/* Get MAC address */
for (i = 0; i < MAC_ADDR_LEN; i++)
dev->dev_addr[i] = RTL_R8(MAC0 + i);
* Switching from MMIO to I/O access fixes the issue as well.
*/
RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
- RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);
+ RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
- RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);
+ RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
}
static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
int handled = 0;
int status;
+ /* loop handling interrupts until we have no new ones or
+ * we hit a invalid/hotplug case.
+ */
status = RTL_R16(IntrStatus);
+ while (status && status != 0xffff) {
+ handled = 1;
- /* hotplug/major error/no more work/shared irq */
- if ((status == 0xffff) || !status)
- goto out;
-
- handled = 1;
+ /* Handle all of the error cases first. These will reset
+ * the chip, so just exit the loop.
+ */
+ if (unlikely(!netif_running(dev))) {
+ rtl8169_asic_down(ioaddr);
+ break;
+ }
- if (unlikely(!netif_running(dev))) {
- rtl8169_asic_down(ioaddr);
- goto out;
- }
+ /* Work around for rx fifo overflow */
+ if (unlikely(status & RxFIFOOver) &&
+ (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+ netif_stop_queue(dev);
+ rtl8169_tx_timeout(dev);
+ break;
+ }
- status &= tp->intr_mask;
- RTL_W16(IntrStatus,
- (status & RxFIFOOver) ? (status | RxOverflow) : status);
+ if (unlikely(status & SYSErr)) {
+ rtl8169_pcierr_interrupt(dev);
+ break;
+ }
- if (!(status & tp->intr_event))
- goto out;
+ if (status & LinkChg)
+ rtl8169_check_link_status(dev, tp, ioaddr);
- /* Work around for rx fifo overflow */
- if (unlikely(status & RxFIFOOver) &&
- (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
- netif_stop_queue(dev);
- rtl8169_tx_timeout(dev);
- goto out;
- }
+ /* We need to see the lastest version of tp->intr_mask to
+ * avoid ignoring an MSI interrupt and having to wait for
+ * another event which may never come.
+ */
+ smp_rmb();
+ if (status & tp->intr_mask & tp->napi_event) {
+ RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+ tp->intr_mask = ~tp->napi_event;
+
+ if (likely(napi_schedule_prep(&tp->napi)))
+ __napi_schedule(&tp->napi);
+ else if (netif_msg_intr(tp)) {
+ printk(KERN_INFO "%s: interrupt %04x in poll\n",
+ dev->name, status);
+ }
+ }
- if (unlikely(status & SYSErr)) {
- rtl8169_pcierr_interrupt(dev);
- goto out;
+ /* We only get a new MSI interrupt when all active irq
+ * sources on the chip have been acknowledged. So, ack
+ * everything we've seen and check if new sources have become
+ * active to avoid blocking all interrupts from the chip.
+ */
+ RTL_W16(IntrStatus,
+ (status & RxFIFOOver) ? (status | RxOverflow) : status);
+ status = RTL_R16(IntrStatus);
}
- if (status & LinkChg)
- rtl8169_check_link_status(dev, tp, ioaddr);
-
- if (status & tp->napi_event) {
- RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
- tp->intr_mask = ~tp->napi_event;
-
- if (likely(netif_rx_schedule_prep(&tp->napi)))
- __netif_rx_schedule(&tp->napi);
- else if (netif_msg_intr(tp)) {
- printk(KERN_INFO "%s: interrupt %04x in poll\n",
- dev->name, status);
- }
- }
-out:
return IRQ_RETVAL(handled);
}
rtl8169_tx_interrupt(dev, tp, ioaddr);
if (work_done < budget) {
- netif_rx_complete(napi);
- tp->intr_mask = 0xffff;
- /*
- * 20040426: the barrier is not strictly required but the
- * behavior of the irq handler could be less predictable
- * without it. Btw, the lack of flush for the posted pci
- * write is safe - FR
+ napi_complete(napi);
+
+ /* We need for force the visibility of tp->intr_mask
+ * for other CPUs, as we can loose an MSI interrupt
+ * and potentially wait for a retransmit timeout if we don't.
+ * The posted write to IntrMask is safe, as it will
+ * eventually make it to the chip and we won't loose anything
+ * until it does.
*/
+ tp->intr_mask = 0xffff;
smp_wmb();
RTL_W16(IntrMask, tp->intr_event);
}