static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac) { unsigned long flags; unsigned i; spin_lock_irqsave(&adapter->lock, flags); for (i = 0; i < ETH_ALEN; i++) { ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i); if (!(adapter->conf_flags & MICREL_KS884X)) ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1], REG_MACAR1 + i); } if (adapter->conf_flags & MICREL_KS884X) { /* the sequence of saving mac addr between MAC and Switch is different. */ u16 mac; mac = ks8842_read16(adapter, 2, REG_MARL); ks8842_write16(adapter, 39, mac, REG_MACAR3); mac = ks8842_read16(adapter, 2, REG_MARM); ks8842_write16(adapter, 39, mac, REG_MACAR2); mac = ks8842_read16(adapter, 2, REG_MARH); ks8842_write16(adapter, 39, mac, REG_MACAR1); } spin_unlock_irqrestore(&adapter->lock, flags); }
static void ks8842_reset_hw(struct ks8842_adapter *adapter) { /* reset the HW */ ks8842_reset(adapter); /* Enable QMU Transmit flow control / transmit padding / Transmit CRC */ ks8842_write16(adapter, 16, 0x000E, REG_TXCR); /* enable the receiver, uni + multi + broadcast + flow ctrl + crc strip */ ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400, REG_RXCR); /* TX frame pointer autoincrement */ ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR); /* RX frame pointer autoincrement */ ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR); /* RX 2 kb high watermark */ ks8842_write16(adapter, 0, 0x1000, REG_QRFCR); /* aggressive back off in half duplex */ ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1); /* enable no excessive collison drop */ ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2); /* Enable port 1 force flow control / back pressure / transmit / recv */ ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2); /* restart port auto-negotiation */ ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); /* Enable the transmitter */ ks8842_enable_tx(adapter); /* Enable the receiver */ ks8842_enable_rx(adapter); /* clear all interrupts */ ks8842_write16(adapter, 18, 0xffff, REG_ISR); /* enable interrupts */ if (KS8842_USE_DMA(adapter)) { /* When running in DMA Mode the RX interrupt is not enabled in timberdale because RX data is received by DMA callbacks it must still be enabled in the KS8842 because it indicates to timberdale when there is RX data for it's DMA FIFOs */ iowrite16(ENABLED_IRQS_DMA_IP, adapter->hw_addr + REG_TIMB_IER); ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER); } else { if (!(adapter->conf_flags & MICREL_KS884X)) iowrite16(ENABLED_IRQS, adapter->hw_addr + REG_TIMB_IER); ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); } /* enable the switch */ ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); }
static void ks8842_reset_hw(struct ks8842_adapter *adapter) { /* */ ks8842_reset(adapter); /* */ ks8842_write16(adapter, 16, 0x000E, REG_TXCR); /* */ ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400, REG_RXCR); /* */ ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR); /* */ ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR); /* */ ks8842_write16(adapter, 0, 0x1000, REG_QRFCR); /* */ ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1); /* */ ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2); /* */ ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2); /* */ ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); /* */ ks8842_enable_tx(adapter); /* */ ks8842_enable_rx(adapter); /* */ ks8842_write16(adapter, 18, 0xffff, REG_ISR); /* */ if (KS8842_USE_DMA(adapter)) { /* */ iowrite16(ENABLED_IRQS_DMA_IP, adapter->hw_addr + REG_TIMB_IER); ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER); } else { if (!(adapter->conf_flags & MICREL_KS884X)) iowrite16(ENABLED_IRQS, adapter->hw_addr + REG_TIMB_IER); ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); } /* */ ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); }
static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) { struct ks8842_adapter *adapter = netdev_priv(netdev); int len = skb->len; netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n", __func__, skb->len, skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb)); /* check FIFO buffer space, we need space for CRC and command bits */ if (ks8842_tx_fifo_space(adapter) < len + 8) return NETDEV_TX_BUSY; if (adapter->conf_flags & KS884X_16BIT) { u16 *ptr16 = (u16 *)skb->data; ks8842_write16(adapter, 17, 0x8000 | 0x100, REG_QMU_DATA_LO); ks8842_write16(adapter, 17, (u16)len, REG_QMU_DATA_HI); netdev->stats.tx_bytes += len; /* copy buffer */ while (len > 0) { iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_LO); iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_HI); len -= sizeof(u32); } } else { u32 *ptr = (u32 *)skb->data; u32 ctrl; /* the control word, enable IRQ, port 1 and the length */ ctrl = 0x8000 | 0x100 | (len << 16); ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO); netdev->stats.tx_bytes += len; /* copy buffer */ while (len > 0) { iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO); len -= sizeof(u32); ptr++; } } /* enqueue packet */ ks8842_write16(adapter, 17, 1, REG_TXQCR); dev_kfree_skb(skb); return NETDEV_TX_OK; }
void ks8842_tasklet(unsigned long arg) { struct net_device *netdev = (struct net_device *)arg; struct ks8842_adapter *adapter = netdev_priv(netdev); u16 isr; unsigned long flags; u16 entry_bank; /* read current bank to be able to set it back */ spin_lock_irqsave(&adapter->lock, flags); entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); spin_unlock_irqrestore(&adapter->lock, flags); isr = ks8842_read16(adapter, 18, REG_ISR); dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); /* Ack */ ks8842_write16(adapter, 18, isr, REG_ISR); if (!netif_running(netdev)) return; if (isr & IRQ_LINK_CHANGE) ks8842_update_link_status(netdev, adapter); if (isr & (IRQ_RX | IRQ_RX_ERROR)) ks8842_handle_rx(netdev, adapter); if (isr & IRQ_TX) ks8842_handle_tx(netdev, adapter); if (isr & IRQ_RX_OVERRUN) ks8842_handle_rx_overrun(netdev, adapter); if (isr & IRQ_TX_STOPPED) { ks8842_disable_tx(adapter); ks8842_enable_tx(adapter); } if (isr & IRQ_RX_STOPPED) { ks8842_disable_rx(adapter); ks8842_enable_rx(adapter); } /* re-enable interrupts, put back the bank selection register */ spin_lock_irqsave(&adapter->lock, flags); ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); spin_unlock_irqrestore(&adapter->lock, flags); }
static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest) { int i; u16 mac; for (i = 0; i < ETH_ALEN; i++) dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); /* make sure the switch port uses the same MAC as the QMU */ mac = ks8842_read16(adapter, 2, REG_MARL); ks8842_write16(adapter, 39, mac, REG_MACAR1); mac = ks8842_read16(adapter, 2, REG_MARM); ks8842_write16(adapter, 39, mac, REG_MACAR2); mac = ks8842_read16(adapter, 2, REG_MARH); ks8842_write16(adapter, 39, mac, REG_MACAR3); }
static void ks8842_tx_timeout(struct net_device *netdev) { struct ks8842_adapter *adapter = netdev_priv(netdev); unsigned long flags; dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); spin_lock_irqsave(&adapter->lock, flags); /* disable interrupts */ ks8842_write16(adapter, 18, 0, REG_IER); ks8842_write16(adapter, 18, 0xFFFF, REG_ISR); spin_unlock_irqrestore(&adapter->lock, flags); ks8842_reset_hw(adapter); ks8842_update_link_status(netdev, adapter); }
static void ks8842_reset_hw(struct ks8842_adapter *adapter) { /* reset the HW */ ks8842_reset(adapter); /* Enable QMU Transmit flow control / transmit padding / Transmit CRC */ ks8842_write16(adapter, 16, 0x000E, REG_TXCR); /* enable the receiver, uni + multi + broadcast + flow ctrl + crc strip */ ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400, REG_RXCR); /* TX frame pointer autoincrement */ ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR); /* RX frame pointer autoincrement */ ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR); /* RX 2 kb high watermark */ ks8842_write16(adapter, 0, 0x1000, REG_QRFCR); /* aggresive back off in half duplex */ ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1); /* enable no excessive collison drop */ ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2); /* Enable port 1 force flow control / back pressure / transmit / recv */ ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2); /* restart port auto-negotiation */ ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); /* only advertise 10Mbps */ ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4); /* Enable the transmitter */ ks8842_enable_tx(adapter); /* Enable the receiver */ ks8842_enable_rx(adapter); /* clear all interrupts */ ks8842_write16(adapter, 18, 0xffff, REG_ISR); /* enable interrupts */ ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); /* enable the switch */ ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); }
static void ks8842_rx_frame(struct net_device *netdev, struct ks8842_adapter *adapter) { u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO); int len = (status >> 16) & 0x7ff; status &= 0xffff; dev_dbg(&adapter->pdev->dev, "%s - rx_data: status: %x\n", __func__, status); /* check the status */ if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len); dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n", __func__, len); if (skb) { u32 *data; netdev->stats.rx_packets++; netdev->stats.rx_bytes += len; if (status & RXSR_MULTICAST) netdev->stats.multicast++; data = (u32 *)skb_put(skb, len); ks8842_select_bank(adapter, 17); while (len > 0) { *data++ = ioread32(adapter->hw_addr + REG_QMU_DATA_LO); len -= sizeof(u32); } skb->protocol = eth_type_trans(skb, netdev); netif_rx(skb); } else netdev->stats.rx_dropped++; } else { dev_dbg(&adapter->pdev->dev, "RX error, status: %x\n", status); netdev->stats.rx_errors++; if (status & RXSR_TOO_LONG) netdev->stats.rx_length_errors++; if (status & RXSR_CRC_ERROR) netdev->stats.rx_crc_errors++; if (status & RXSR_RUNT) netdev->stats.rx_frame_errors++; } /* set high watermark to 3K */ ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR); /* release the frame */ ks8842_write16(adapter, 17, 0x01, REG_RXQCR); /* set high watermark to 2K */ ks8842_enable_bits(adapter, 0, 1 << 12, REG_QRFCR); }
static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest) { int i; u16 mac; for (i = 0; i < ETH_ALEN; i++) dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); if (adapter->conf_flags & MICREL_KS884X) { /* the sequence of saving mac addr between MAC and Switch is different. */ mac = ks8842_read16(adapter, 2, REG_MARL); ks8842_write16(adapter, 39, mac, REG_MACAR3); mac = ks8842_read16(adapter, 2, REG_MARM); ks8842_write16(adapter, 39, mac, REG_MACAR2); mac = ks8842_read16(adapter, 2, REG_MARH); ks8842_write16(adapter, 39, mac, REG_MACAR1); } else { /* make sure the switch port uses the same MAC as the QMU */ mac = ks8842_read16(adapter, 2, REG_MARL); ks8842_write16(adapter, 39, mac, REG_MACAR1); mac = ks8842_read16(adapter, 2, REG_MARM); ks8842_write16(adapter, 39, mac, REG_MACAR2); mac = ks8842_read16(adapter, 2, REG_MARH); ks8842_write16(adapter, 39, mac, REG_MACAR3); } }
static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest) { int i; u16 mac; for (i = 0; i < ETH_ALEN; i++) dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); if (adapter->conf_flags & MICREL_KS884X) { /* */ mac = ks8842_read16(adapter, 2, REG_MARL); ks8842_write16(adapter, 39, mac, REG_MACAR3); mac = ks8842_read16(adapter, 2, REG_MARM); ks8842_write16(adapter, 39, mac, REG_MACAR2); mac = ks8842_read16(adapter, 2, REG_MARH); ks8842_write16(adapter, 39, mac, REG_MACAR1); } else { /* */ mac = ks8842_read16(adapter, 2, REG_MARL); ks8842_write16(adapter, 39, mac, REG_MACAR1); mac = ks8842_read16(adapter, 2, REG_MARM); ks8842_write16(adapter, 39, mac, REG_MACAR2); mac = ks8842_read16(adapter, 2, REG_MARH); ks8842_write16(adapter, 39, mac, REG_MACAR3); } }
static int ks8842_close(struct net_device *netdev) { struct ks8842_adapter *adapter = netdev_priv(netdev); dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__); /* free the irq */ free_irq(adapter->irq, adapter); /* disable the switch */ ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE); return 0; }
static void ks8842_reset(struct ks8842_adapter *adapter) { if (adapter->conf_flags & MICREL_KS884X) { ks8842_write16(adapter, 3, 1, REG_GRR); msleep(10); iowrite16(0, adapter->hw_addr + REG_GRR); } else { /* The KS8842 goes haywire when doing softare reset * a work around in the timberdale IP is implemented to * do a hardware reset instead ks8842_write16(adapter, 3, 1, REG_GRR); msleep(10); iowrite16(0, adapter->hw_addr + REG_GRR); */ iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST); msleep(20); } }
static void ks8842_reset(struct ks8842_adapter *adapter) { if (adapter->conf_flags & MICREL_KS884X) { ks8842_write16(adapter, 3, 1, REG_GRR); msleep(10); iowrite16(0, adapter->hw_addr + REG_GRR); } else { /* */ iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST); msleep(20); } }
static irqreturn_t ks8842_irq(int irq, void *devid) { struct ks8842_adapter *adapter = devid; u16 isr; u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); irqreturn_t ret = IRQ_NONE; isr = ks8842_read16(adapter, 18, REG_ISR); dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); if (isr) { /* disable IRQ */ ks8842_write16(adapter, 18, 0x00, REG_IER); /* schedule tasklet */ tasklet_schedule(&adapter->tasklet); ret = IRQ_HANDLED; } iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); return ret; }