[<prev] [next>] [day] [month] [year] [list]
Message-ID: <C43529A246480145B0A6D0234BDB0F0D02129D@MELANITE.micrel.com>
Date: Fri, 9 Apr 2010 10:50:27 -0700
From: "Choi, David" <David.Choi@...rel.Com>
To: <davem@...emloft.net>
Cc: <netdev@...r.kernel.org>
Subject: [PATCH linux-2.6.34-rc3] drivers/net: ks8851 MLL ethernet network driver
Hello
>From : David J. Choi (david.choi@...rel.com)
Summary :
1.Support big Endian mode
2.Receive interrupt consolidation: a receive interrupt happens when 2 consecutive packets are
received continuously within a certain period of time in order to enhance performance.
3.Change a register name, which was caused by mis-type.
4.Disable the device interrupt by controlling a device register, instead of host register
,when packet transmit starts.
5.Display network interface name after the device registration for maintenance purpose.
6.Fix to unmap of memory when the device is removed.
Signed-off-by : David J. Choi
---
--- linux-2.6.34-rc3/drivers/net/ks8851_mll.c.orig 2010-04-09 10:23:35.000000000 -0700
+++ linux-2.6.34-rc3/drivers/net/ks8851_mll.c 2010-04-09 10:23:23.000000000 -0700
@@ -41,6 +41,7 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
#define RX_BUF_SIZE 2000
#define KS_CCR 0x08
+#define CCR_ENDIAN (1 << 10)
#define CCR_EEPROM (1 << 9)
#define CCR_SPI (1 << 8)
#define CCR_8BIT (1 << 7)
@@ -143,7 +144,7 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
#define RXCR1_RXAE (1 << 4)
#define RXCR1_RXINVF (1 << 1)
#define RXCR1_RXE (1 << 0)
-#define RXCR1_FILTER_MASK (RXCR1_RXINVF | RXCR1_RXAE | \
+#define RXCR1_FILTER_MASK (RXCR1_RXINVF | RXCR1_RXAE | \
RXCR1_RXMAFMA | RXCR1_RXPAFMA)
#define KS_RXCR2 0x76
@@ -199,7 +200,7 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
#define RXQCR_ADRFE (1 << 4)
#define RXQCR_SDA (1 << 3)
#define RXQCR_RRXEF (1 << 0)
-#define RXQCR_CMD_CNTL (RXQCR_RXFCTE|RXQCR_ADRFE)
+#define RXQCR_CMD_CNTL (RXQCR_RXFCTE|RXQCR_ADRFE|RXQCR_RXDTTE)
#define KS_TXFDPR 0x84
#define TXFDPR_TXFPAI (1 << 14)
@@ -208,6 +209,7 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
#define KS_RXFDPR 0x86
#define RXFDPR_RXFPAI (1 << 14)
+#define RXFDPR_ENDIAN (1 << 11)
#define KS_RXDTTR 0x8C
#define KS_RXDBCTR 0x8E
@@ -229,7 +231,7 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
#define IRQ_DEDI (1 << 0)
#define KS_RXFCTR 0x9C
-#define RXFCTR_THRESHOLD_MASK 0x00FF
+#define RXFCTR_THRESHOLD_MASK 0x00FF
#define KS_RXFC 0x9D
#define RXFCTR_RXFC_MASK (0xff << 8)
@@ -265,7 +267,7 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
#define IACR_ADDR_SHIFT (0)
#define KS_IADLR 0xD0
-#define KS_IAHDR 0xD2
+#define KS_IADHR 0xD2
#define KS_PMECR 0xD4
#define PMECR_PME_DELAY (1 << 14)
@@ -361,6 +363,10 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
#define MAX_MCAST_LST 32
#define HW_MCAST_SIZE 8
#define MAC_ADDR_LEN 6
+/* count to consolidate rx packets */
+#define CONSOLIDATE_INT_FIRE_CNT 2
+/* nsec to trigger an interrupt */
+#define CONSOLIDATE_INT_FIRE_DUR 100
/**
* union ks_tx_hdr - tx header data
@@ -378,34 +384,34 @@ union ks_tx_hdr {
/**
* struct ks_net - KS8851 driver private data
- * @net_device : The network device we're bound to
+ * @net_device : The network device we're bound to
* @hw_addr : start address of data register.
* @hw_addr_cmd : start address of command register.
- * @txh : temporaly buffer to save status/length.
+ * @txh : temporaly buffer to save status/length.
* @lock : Lock to ensure that the device is not accessed when busy.
* @pdev : Pointer to platform device.
* @mii : The MII state information for the mii calls.
- * @frame_head_info : frame header information for multi-pkt rx.
+ * @frame_head_info : frame header information for multi-pkt rx.
* @statelock : Lock on this structure for tx list.
* @msg_enable : The message flags controlling driver output (see ethtool).
- * @frame_cnt : number of frames received.
- * @bus_width : i/o bus width.
- * @irq : irq number assigned to this device.
+ * @frame_cnt : number of frames received.
+ * @bus_width : i/o bus width.
+ * @irq : irq number assigned to this device.
* @rc_rxqcr : Cached copy of KS_RXQCR.
* @rc_txcr : Cached copy of KS_TXCR.
* @rc_ier : Cached copy of KS_IER.
- * @sharedbus : Multipex(addr and data bus) mode indicator.
+ * @sharedbus : Multipex(addr and data bus) mode indicator.
* @cmd_reg_cache : command register cached.
* @cmd_reg_cache_int : command register cached. Used in the irq handler.
* @promiscuous : promiscuous mode indicator.
- * @all_mcast : mutlicast indicator.
- * @mcast_lst_size : size of multicast list.
- * @mcast_lst : multicast list.
- * @mcast_bits : multicast enabed.
- * @mac_addr : MAC address assigned to this device.
- * @fid : frame id.
- * @extra_byte : number of extra byte prepended rx pkt.
- * @enabled : indicator this device works.
+ * @all_mcast : mutlicast indicator.
+ * @mcast_lst_size : size of multicast list.
+ * @mcast_lst : multicast list.
+ * @mcast_bits : multicast enabed.
+ * @mac_addr : MAC address assigned to this device.
+ * @fid : frame id.
+ * @extra_byte : number of extra byte prepended rx pkt.
+ * @enabled : indicator this device works.
*
* The @lock ensures that the chip is protected when certain operations are
* in progress. When the read or write packet transfer is in progress, most
@@ -426,10 +432,10 @@ struct type_frame_head {
struct ks_net {
struct net_device *netdev;
- void __iomem *hw_addr;
- void __iomem *hw_addr_cmd;
+ void __iomem *hw_addr;
+ void __iomem *hw_addr_cmd;
union ks_tx_hdr txh ____cacheline_aligned;
- struct mutex lock; /* spinlock to be interrupt safe */
+ struct mutex lock; /* spinlock to be interrupt safe */
struct platform_device *pdev;
struct mii_if_info mii;
struct type_frame_head *frame_head_info;
@@ -437,7 +443,7 @@ struct ks_net {
u32 msg_enable;
u32 frame_cnt;
int bus_width;
- int irq;
+ int irq;
u16 rc_rxqcr;
u16 rc_txcr;
@@ -463,10 +469,27 @@ static int msg_enable;
#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->pdev->dev, _msg)
#define ks_err(_ks, _msg...) dev_err(&(_ks)->pdev->dev, _msg)
+#if defined(__LITTLE_ENDIAN)
#define BE3 0x8000 /* Byte Enable 3 */
#define BE2 0x4000 /* Byte Enable 2 */
#define BE1 0x2000 /* Byte Enable 1 */
#define BE0 0x1000 /* Byte Enable 0 */
+#define MAKE_ADDR16(offset) ((u16)offset | ((BE1 | BE0) << (offset & 0x02)))
+#define MAKE_ADDR8(offset, shift_bit) ((u16)offset | (BE0 << shift_bit))
+#define MAKE_SHIFT_INDEX(offset) ((offset & 1) << 3)
+#define MAKE_SHIFT_VALUE(offset) ((offset & 1) << 8)
+#define CONV_MAC_VALUE(u) (((u & 0xFF) << 8) | ((u >> 8) & 0xFF))
+#else
+#define BE3 0x1000 /* Byte Enable 3 */
+#define BE2 0x2000 /* Byte Enable 2 */
+#define BE1 0x4000 /* Byte Enable 1 */
+#define BE0 0x8000 /* Byte Enable 0 */
+#define MAKE_ADDR16(offset) ((u16)offset | ((BE1 | BE0) >> (offset & 0x02)))
+#define MAKE_ADDR8(offset, shift_bit) ((u16)offset | (BE0 >> shift_bit))
+#define MAKE_SHIFT_INDEX(offset) (!(offset & 1) << 3)
+#define MAKE_SHIFT_VALUE(offset) (!(offset & 1) << 8)
+#define CONV_MAC_VALUE(u) u
+#endif
/**
* register read/write calls.
@@ -487,8 +510,8 @@ static u8 ks_rdreg8(struct ks_net *ks, i
{
u16 data;
u8 shift_bit = offset & 0x03;
- u8 shift_data = (offset & 1) << 3;
- ks->cmd_reg_cache = (u16) offset | (u16)(BE0 << shift_bit);
+ u8 shift_data = MAKE_SHIFT_VALUE(offset);
+ ks->cmd_reg_cache = MAKE_ADDR8(offset, shift_bit);
iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
data = ioread16(ks->hw_addr);
return (u8)(data >> shift_data);
@@ -504,7 +527,7 @@ static u8 ks_rdreg8(struct ks_net *ks, i
static u16 ks_rdreg16(struct ks_net *ks, int offset)
{
- ks->cmd_reg_cache = (u16)offset | ((BE1 | BE0) << (offset & 0x02));
+ ks->cmd_reg_cache = MAKE_ADDR16(offset);
iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
return ioread16(ks->hw_addr);
}
@@ -519,8 +542,8 @@ static u16 ks_rdreg16(struct ks_net *ks,
static void ks_wrreg8(struct ks_net *ks, int offset, u8 value)
{
u8 shift_bit = (offset & 0x03);
- u16 value_write = (u16)(value << ((offset & 1) << 3));
- ks->cmd_reg_cache = (u16)offset | (BE0 << shift_bit);
+ u16 value_write = (u16)(value << (MAKE_SHIFT_INDEX(offset)));
+ ks->cmd_reg_cache = MAKE_ADDR8(offset, shift_bit);
iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
iowrite16(value_write, ks->hw_addr);
}
@@ -535,7 +558,7 @@ static void ks_wrreg8(struct ks_net *ks,
static void ks_wrreg16(struct ks_net *ks, int offset, u16 value)
{
- ks->cmd_reg_cache = (u16)offset | ((BE1 | BE0) << (offset & 0x02));
+ ks->cmd_reg_cache = MAKE_ADDR16(offset);
iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
iowrite16(value, ks->hw_addr);
}
@@ -571,6 +594,9 @@ static inline void ks_outblk(struct ks_n
static void ks_disable_int(struct ks_net *ks)
{
ks_wrreg16(ks, KS_IER, 0x0000);
+ /* guarantee that device interrupt is disabled. */
+ ks_rdreg16(ks, KS_IER);
+
} /* ks_disable_int */
static void ks_enable_int(struct ks_net *ks)
@@ -603,7 +629,7 @@ static inline void ks_save_cmd_reg(struc
/**
* ks_restore_cmd_reg - restore the command register from the cache and
- * write to hardware register.
+ * write to hardware register.
* @ks: The chip information
*
*/
@@ -639,8 +665,10 @@ static void ks_set_powermode(struct ks_n
* ks_read_config - read chip configuration of bus width.
* @ks: The chip information
*
+ * When Endianness does not match between hardware and softwae, return false.
+ *
*/
-static void ks_read_config(struct ks_net *ks)
+static bool ks_read_config(struct ks_net *ks)
{
u16 reg_data = 0;
@@ -648,6 +676,17 @@ static void ks_read_config(struct ks_net
reg_data = ks_rdreg8(ks, KS_CCR) & 0x00FF;
reg_data |= ks_rdreg8(ks, KS_CCR+1) << 8;
+#if defined(__LITTLE_ENDIAN)
+ if (!reg_data & CCR_ENDIAN) {
+ printk(KERN_ERR "%s: Endian mode error\n", __func__);
+ return false;
+ }
+#else
+ if (reg_data & CCR_ENDIAN) {
+ printk(KERN_ERR "%s: Endian mode error\n", __func__);
+ return false;
+ }
+#endif
/* addr/data bus are multiplexed */
ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED;
@@ -665,6 +704,7 @@ static void ks_read_config(struct ks_net
ks->bus_width = ENUM_BUS_32BIT;
ks->extra_byte = 4;
}
+ return true;
}
/**
@@ -809,7 +849,7 @@ static void ks_rcv(struct ks_net *ks, st
skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb);
} else {
- printk(KERN_ERR "%s: err:skb alloc\n", __func__);
+ printk(KERN_ERR "err:skb alloc or frame\n");
ks_wrreg16(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
if (skb)
dev_kfree_skb_irq(skb);
@@ -985,9 +1025,13 @@ static int ks_net_stop(struct net_device
static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len)
{
/* start header at txb[0] to align txw entries */
+#if defined(__LITTLE_ENDIAN)
ks->txh.txw[0] = 0;
ks->txh.txw[1] = cpu_to_le16(len);
-
+#else
+ ks->txh.txw[0] = 0;
+ ks->txh.txw[1] = cpu_to_be16(len);
+#endif
/* 1. set sudo-DMA mode */
ks_wrreg8(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
/* 2. write status/lenth info */
@@ -1017,7 +1061,6 @@ static int ks_start_xmit(struct sk_buff
int retv = NETDEV_TX_OK;
struct ks_net *ks = netdev_priv(netdev);
- disable_irq(netdev->irq);
ks_disable_int(ks);
spin_lock(&ks->statelock);
@@ -1032,7 +1075,6 @@ static int ks_start_xmit(struct sk_buff
retv = NETDEV_TX_BUSY;
spin_unlock(&ks->statelock);
ks_enable_int(ks);
- enable_irq(netdev->irq);
return retv;
}
@@ -1224,20 +1266,16 @@ static void ks_set_rx_mode(struct net_de
static void ks_set_mac(struct ks_net *ks, u8 *data)
{
u16 *pw = (u16 *)data;
- u16 w, u;
+ u16 w;
ks_stop_rx(ks); /* Stop receiving for reconfiguration */
-
- u = *pw++;
- w = ((u & 0xFF) << 8) | ((u >> 8) & 0xFF);
+ w = CONV_MAC_VALUE(*pw);
ks_wrreg16(ks, KS_MARH, w);
- u = *pw++;
- w = ((u & 0xFF) << 8) | ((u >> 8) & 0xFF);
+ w = CONV_MAC_VALUE(*(pw+1));
ks_wrreg16(ks, KS_MARM, w);
- u = *pw;
- w = ((u & 0xFF) << 8) | ((u >> 8) & 0xFF);
+ w = CONV_MAC_VALUE(*(pw+2));
ks_wrreg16(ks, KS_MARL, w);
memcpy(ks->mac_addr, data, 6);
@@ -1461,8 +1499,10 @@ static void ks_setup(struct ks_net *ks)
/* Setup Receive Frame Data Pointer Auto-Increment */
ks_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI);
- /* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */
- ks_wrreg16(ks, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK);
+
+ /* Setup Receive Frame Threshold */
+ ks_wrreg16(ks, KS_RXFCTR, CONSOLIDATE_INT_FIRE_CNT);
+ ks_wrreg16(ks, KS_RXDTTR, CONSOLIDATE_INT_FIRE_DUR);
/* Setup RxQ Command Control (RXQCR) */
ks->rc_rxqcr = RXQCR_CMD_CNTL;
@@ -1585,7 +1625,19 @@ static int __devinit ks8851_probe(struct
ks->msg_enable = netif_msg_init(msg_enable, (NETIF_MSG_DRV |
NETIF_MSG_PROBE |
NETIF_MSG_LINK));
- ks_read_config(ks);
+ /* set endian mode, which is write-only */
+ data = ks_rdreg16(ks, KS_RXFDPR);
+#if defined(__LITTLE_ENDIAN)
+ data &= ~RXFDPR_ENDIAN;
+#else
+ data |= RXFDPR_ENDIAN;
+#endif
+ ks_wrreg16(ks, KS_RXFDPR, data);
+
+ if (!ks_read_config(ks)) {
+ err = -ENODEV;
+ goto err_register;
+ }
/* simple check for a valid chip being connected to the bus */
if ((ks_rdreg16(ks, KS_CIDER) & ~CIDER_REV_MASK) != CIDER_ID) {
@@ -1604,6 +1656,7 @@ static int __devinit ks8851_probe(struct
if (err)
goto err_register;
+ printk(KERN_INFO "Network Interface of ks8851: %s\n", netdev->name);
platform_set_drvdata(pdev, netdev);
ks_soft_reset(ks, GRR_GSR);
@@ -1655,6 +1708,7 @@ static int __devexit ks8851_remove(struc
kfree(ks->frame_head_info);
unregister_netdev(netdev);
iounmap(ks->hw_addr);
+ iounmap(ks->hw_addr_cmd);
free_netdev(netdev);
release_mem_region(iomem->start, resource_size(iomem));
platform_set_drvdata(pdev, NULL);
---
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists