mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-11-01 09:13:37 +00:00 
			
		
		
		
	drivers/net: Add Micrel KS8841/42 support to ks8842 driver
Body of the explanation:
   -support 16bit and 32bit bus width.
   -add device reset for ks8842/8841 Micrel device.
   -set 100Mbps as a default for Micrel device.
   -set MAC address in both MAC/Switch layer with different sequence for Micrel
    device, as mentioned in data sheet.
   -use private data to set options both 16/32bit bus width and Micrel device/
    Timberdale(FPGA).
   -update Kconfig in order to put more information about ks8842 device.
Signed-off-by: David J. Choi <david.choi@micrel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									242647bcf8
								
							
						
					
					
						commit
						28bd620c7a
					
				
					 2 changed files with 132 additions and 47 deletions
				
			
		| 
						 | 
					@ -1750,11 +1750,12 @@ config TLAN
 | 
				
			||||||
	  Please email feedback to <torben.mathiasen@compaq.com>.
 | 
						  Please email feedback to <torben.mathiasen@compaq.com>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config KS8842
 | 
					config KS8842
 | 
				
			||||||
	tristate "Micrel KSZ8842"
 | 
						tristate "Micrel KSZ8841/42 with generic bus interface"
 | 
				
			||||||
	depends on HAS_IOMEM
 | 
						depends on HAS_IOMEM
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This platform driver is for Micrel KSZ8842 / KS8842
 | 
						 This platform driver is for KSZ8841(1-port) / KS8842(2-port)
 | 
				
			||||||
	  2-port ethernet switch chip (managed, VLAN, QoS).
 | 
						 ethernet switch chip (managed, VLAN, QoS) from Micrel or
 | 
				
			||||||
 | 
						 Timberdale(FPGA).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config KS8851
 | 
					config KS8851
 | 
				
			||||||
       tristate "Micrel KS8851 SPI"
 | 
					       tristate "Micrel KS8851 SPI"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Supports:
 | 
					/* Supports:
 | 
				
			||||||
 * The Micrel KS8842 behind the timberdale FPGA
 | 
					 * The Micrel KS8842 behind the timberdale FPGA
 | 
				
			||||||
 | 
					 * The genuine Micrel KS8841/42 device with ISA 16/32bit bus interface
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
					#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
				
			||||||
| 
						 | 
					@ -114,9 +115,14 @@
 | 
				
			||||||
#define REG_P1CR4		0x02
 | 
					#define REG_P1CR4		0x02
 | 
				
			||||||
#define REG_P1SR		0x04
 | 
					#define REG_P1SR		0x04
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* flags passed by platform_device for configuration */
 | 
				
			||||||
 | 
					#define	MICREL_KS884X		0x01	/* 0=Timeberdale(FPGA), 1=Micrel */
 | 
				
			||||||
 | 
					#define	KS884X_16BIT		0x02	/*  1=16bit, 0=32bit */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ks8842_adapter {
 | 
					struct ks8842_adapter {
 | 
				
			||||||
	void __iomem	*hw_addr;
 | 
						void __iomem	*hw_addr;
 | 
				
			||||||
	int		irq;
 | 
						int		irq;
 | 
				
			||||||
 | 
						unsigned long	conf_flags;	/* copy of platform_device config */
 | 
				
			||||||
	struct tasklet_struct	tasklet;
 | 
						struct tasklet_struct	tasklet;
 | 
				
			||||||
	spinlock_t	lock; /* spinlock to be interrupt safe */
 | 
						spinlock_t	lock; /* spinlock to be interrupt safe */
 | 
				
			||||||
	struct work_struct timeout_work;
 | 
						struct work_struct timeout_work;
 | 
				
			||||||
| 
						 | 
					@ -192,15 +198,21 @@ static inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ks8842_reset(struct ks8842_adapter *adapter)
 | 
					static void ks8842_reset(struct ks8842_adapter *adapter)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* The KS8842 goes haywire when doing softare reset
 | 
						if (adapter->conf_flags & MICREL_KS884X) {
 | 
				
			||||||
	 * a work around in the timberdale IP is implemented to
 | 
							ks8842_write16(adapter, 3, 1, REG_GRR);
 | 
				
			||||||
	 * do a hardware reset instead
 | 
							msleep(10);
 | 
				
			||||||
	ks8842_write16(adapter, 3, 1, REG_GRR);
 | 
							iowrite16(0, adapter->hw_addr + REG_GRR);
 | 
				
			||||||
	msleep(10);
 | 
						} else {
 | 
				
			||||||
	iowrite16(0, adapter->hw_addr + REG_GRR);
 | 
							/* The KS8842 goes haywire when doing softare reset
 | 
				
			||||||
	*/
 | 
							* a work around in the timberdale IP is implemented to
 | 
				
			||||||
	iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST);
 | 
							* do a hardware reset instead
 | 
				
			||||||
	msleep(20);
 | 
							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_update_link_status(struct net_device *netdev,
 | 
					static void ks8842_update_link_status(struct net_device *netdev,
 | 
				
			||||||
| 
						 | 
					@ -269,8 +281,10 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* restart port auto-negotiation */
 | 
						/* restart port auto-negotiation */
 | 
				
			||||||
	ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4);
 | 
						ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4);
 | 
				
			||||||
	/* only advertise 10Mbps */
 | 
					
 | 
				
			||||||
	ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4);
 | 
						if (!(adapter->conf_flags & MICREL_KS884X))
 | 
				
			||||||
 | 
							/* only advertise 10Mbps */
 | 
				
			||||||
 | 
							ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Enable the transmitter */
 | 
						/* Enable the transmitter */
 | 
				
			||||||
	ks8842_enable_tx(adapter);
 | 
						ks8842_enable_tx(adapter);
 | 
				
			||||||
| 
						 | 
					@ -296,13 +310,28 @@ static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest)
 | 
				
			||||||
	for (i = 0; i < ETH_ALEN; i++)
 | 
						for (i = 0; i < ETH_ALEN; i++)
 | 
				
			||||||
		dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + 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 */
 | 
						if (adapter->conf_flags & MICREL_KS884X) {
 | 
				
			||||||
	mac = ks8842_read16(adapter, 2, REG_MARL);
 | 
							/*
 | 
				
			||||||
	ks8842_write16(adapter, 39, mac, REG_MACAR1);
 | 
							the sequence of saving mac addr between MAC and Switch is
 | 
				
			||||||
	mac = ks8842_read16(adapter, 2, REG_MARM);
 | 
							different.
 | 
				
			||||||
	ks8842_write16(adapter, 39, mac, REG_MACAR2);
 | 
							*/
 | 
				
			||||||
	mac = ks8842_read16(adapter, 2, REG_MARH);
 | 
					
 | 
				
			||||||
	ks8842_write16(adapter, 39, mac, REG_MACAR3);
 | 
							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_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
 | 
					static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
 | 
				
			||||||
| 
						 | 
					@ -313,8 +342,25 @@ static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
 | 
				
			||||||
	spin_lock_irqsave(&adapter->lock, flags);
 | 
						spin_lock_irqsave(&adapter->lock, flags);
 | 
				
			||||||
	for (i = 0; i < ETH_ALEN; i++) {
 | 
						for (i = 0; i < ETH_ALEN; i++) {
 | 
				
			||||||
		ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
 | 
							ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
 | 
				
			||||||
		ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
 | 
							if (!(adapter->conf_flags & MICREL_KS884X))
 | 
				
			||||||
			REG_MACAR1 + i);
 | 
								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);
 | 
						spin_unlock_irqrestore(&adapter->lock, flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -328,8 +374,6 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ks8842_adapter *adapter = netdev_priv(netdev);
 | 
						struct ks8842_adapter *adapter = netdev_priv(netdev);
 | 
				
			||||||
	int len = skb->len;
 | 
						int len = skb->len;
 | 
				
			||||||
	u32 *ptr = (u32 *)skb->data;
 | 
					 | 
				
			||||||
	u32 ctrl;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n",
 | 
						netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n",
 | 
				
			||||||
		__func__, skb->len, skb->head, skb->data,
 | 
							__func__, skb->len, skb->head, skb->data,
 | 
				
			||||||
| 
						 | 
					@ -339,17 +383,34 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
 | 
				
			||||||
	if (ks8842_tx_fifo_space(adapter) < len + 8)
 | 
						if (ks8842_tx_fifo_space(adapter) < len + 8)
 | 
				
			||||||
		return NETDEV_TX_BUSY;
 | 
							return NETDEV_TX_BUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* the control word, enable IRQ, port 1 and the length */
 | 
						if (adapter->conf_flags & KS884X_16BIT) {
 | 
				
			||||||
	ctrl = 0x8000 | 0x100 | (len << 16);
 | 
							u16 *ptr16 = (u16 *)skb->data;
 | 
				
			||||||
	ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO);
 | 
							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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* copy buffer */
 | 
							u32 *ptr = (u32 *)skb->data;
 | 
				
			||||||
	while (len > 0) {
 | 
							u32 ctrl;
 | 
				
			||||||
		iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO);
 | 
							/* the control word, enable IRQ, port 1 and the length */
 | 
				
			||||||
		len -= sizeof(u32);
 | 
							ctrl = 0x8000 | 0x100 | (len << 16);
 | 
				
			||||||
		ptr++;
 | 
							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 */
 | 
						/* enqueue packet */
 | 
				
			||||||
| 
						 | 
					@ -363,12 +424,23 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
 | 
				
			||||||
static void ks8842_rx_frame(struct net_device *netdev,
 | 
					static void ks8842_rx_frame(struct net_device *netdev,
 | 
				
			||||||
	struct ks8842_adapter *adapter)
 | 
						struct ks8842_adapter *adapter)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
 | 
						u16 status16;
 | 
				
			||||||
	int len = (status >> 16) & 0x7ff;
 | 
						u32 status;
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status &= 0xffff;
 | 
						if (adapter->conf_flags & KS884X_16BIT) {
 | 
				
			||||||
 | 
							status16 = ks8842_read16(adapter, 17, REG_QMU_DATA_LO);
 | 
				
			||||||
	netdev_dbg(netdev, "%s - rx_data: status: %x\n", __func__, status);
 | 
							len  = (int)ks8842_read16(adapter, 17, REG_QMU_DATA_HI);
 | 
				
			||||||
 | 
							len &= 0xffff;
 | 
				
			||||||
 | 
							netdev_dbg(netdev, "%s - rx_data: status: %x\n",
 | 
				
			||||||
 | 
								   __func__, status16);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
 | 
				
			||||||
 | 
							len = (status >> 16) & 0x7ff;
 | 
				
			||||||
 | 
							status &= 0xffff;
 | 
				
			||||||
 | 
							netdev_dbg(netdev, "%s - rx_data: status: %x\n",
 | 
				
			||||||
 | 
								   __func__, status);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check the status */
 | 
						/* check the status */
 | 
				
			||||||
	if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
 | 
						if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
 | 
				
			||||||
| 
						 | 
					@ -376,22 +448,32 @@ static void ks8842_rx_frame(struct net_device *netdev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		netdev_dbg(netdev, "%s, got package, len: %d\n", __func__, len);
 | 
							netdev_dbg(netdev, "%s, got package, len: %d\n", __func__, len);
 | 
				
			||||||
		if (skb) {
 | 
							if (skb) {
 | 
				
			||||||
			u32 *data;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			netdev->stats.rx_packets++;
 | 
								netdev->stats.rx_packets++;
 | 
				
			||||||
			netdev->stats.rx_bytes += len;
 | 
								netdev->stats.rx_bytes += len;
 | 
				
			||||||
			if (status & RXSR_MULTICAST)
 | 
								if (status & RXSR_MULTICAST)
 | 
				
			||||||
				netdev->stats.multicast++;
 | 
									netdev->stats.multicast++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			data = (u32 *)skb_put(skb, len);
 | 
								if (adapter->conf_flags & KS884X_16BIT) {
 | 
				
			||||||
 | 
									u16 *data16 = (u16 *)skb_put(skb, len);
 | 
				
			||||||
 | 
									ks8842_select_bank(adapter, 17);
 | 
				
			||||||
 | 
									while (len > 0) {
 | 
				
			||||||
 | 
										*data16++ = ioread16(adapter->hw_addr +
 | 
				
			||||||
 | 
											REG_QMU_DATA_LO);
 | 
				
			||||||
 | 
										*data16++ = ioread16(adapter->hw_addr +
 | 
				
			||||||
 | 
											REG_QMU_DATA_HI);
 | 
				
			||||||
 | 
										len -= sizeof(u32);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									u32 *data = (u32 *)skb_put(skb, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ks8842_select_bank(adapter, 17);
 | 
									ks8842_select_bank(adapter, 17);
 | 
				
			||||||
			while (len > 0) {
 | 
									while (len > 0) {
 | 
				
			||||||
				*data++ = ioread32(adapter->hw_addr +
 | 
										*data++ = ioread32(adapter->hw_addr +
 | 
				
			||||||
					REG_QMU_DATA_LO);
 | 
											REG_QMU_DATA_LO);
 | 
				
			||||||
				len -= sizeof(u32);
 | 
										len -= sizeof(u32);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			skb->protocol = eth_type_trans(skb, netdev);
 | 
								skb->protocol = eth_type_trans(skb, netdev);
 | 
				
			||||||
			netif_rx(skb);
 | 
								netif_rx(skb);
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
| 
						 | 
					@ -669,6 +751,8 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
 | 
				
			||||||
	adapter->netdev = netdev;
 | 
						adapter->netdev = netdev;
 | 
				
			||||||
	INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work);
 | 
						INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work);
 | 
				
			||||||
	adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
 | 
						adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
 | 
				
			||||||
 | 
						adapter->conf_flags = iomem->flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!adapter->hw_addr)
 | 
						if (!adapter->hw_addr)
 | 
				
			||||||
		goto err_ioremap;
 | 
							goto err_ioremap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue