#include <linux/if_vlan.h>
#include <linux/ctype.h>
#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
#include <asm/system.h>
#include <asm/io.h>
MODULE_AUTHOR("Advanced Micro Devices, Inc.");
MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.3");
MODULE_LICENSE("GPL");
-MODULE_PARM(speed_duplex, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl);
+module_param_array(speed_duplex, int, NULL, 0);
MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
-MODULE_PARM(coalesce, "1-" __MODULE_STRING(MAX_UNITS) "i");
+module_param_array(coalesce, bool, NULL, 0);
MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable");
-MODULE_PARM(dynamic_ipg, "1-" __MODULE_STRING(MAX_UNITS) "i");
+module_param_array(dynamic_ipg, bool, NULL, 0);
MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable");
static struct pci_device_id amd8111e_pci_tbl[] = {
*/
static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
{
- void * mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
unsigned int reg_val;
unsigned int repeat= REPEAT_CNT;
static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
{
unsigned int repeat = REPEAT_CNT
- void * mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
unsigned int reg_val;
reg_val = readl(mmio + PHY_ACCESS);
u32 bmcr,advert,tmp;
/* Determine mii register values to set the speed */
- advert = amd8111e_mdio_read(dev, PHY_ID, MII_ADVERTISE);
+ advert = amd8111e_mdio_read(dev, lp->ext_phy_addr, MII_ADVERTISE);
tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
switch (lp->ext_phy_option){
}
if(advert != tmp)
- amd8111e_mdio_write(dev, PHY_ID, MII_ADVERTISE, tmp);
+ amd8111e_mdio_write(dev, lp->ext_phy_addr, MII_ADVERTISE, tmp);
/* Restart auto negotiation */
- bmcr = amd8111e_mdio_read(dev, PHY_ID, MII_BMCR);
+ bmcr = amd8111e_mdio_read(dev, lp->ext_phy_addr, MII_BMCR);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
- amd8111e_mdio_write(dev, PHY_ID, MII_BMCR, bmcr);
+ amd8111e_mdio_write(dev, lp->ext_phy_addr, MII_BMCR, bmcr);
}
lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]);
lp->rx_ring[i].buff_count = cpu_to_le16(lp->rx_buff_len-2);
+ wmb();
lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
}
unsigned int event_count;
struct amd8111e_priv *lp = netdev_priv(dev);
- void* mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf;
static int amd8111e_restart(struct net_device *dev)
{
struct amd8111e_priv *lp = netdev_priv(dev);
- void * mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
int i,reg_val;
/* stop the chip */
{
unsigned int reg_val;
unsigned int logic_filter[2] ={0,};
- void * mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
/* stop the chip */
writel(RUN, mmio + CMD0);
/* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
- writew( 0x8101, mmio + AUTOPOLL0);
+ writew( 0x8100 | lp->ext_phy_addr, mmio + AUTOPOLL0);
/* Clear RCV_RING_BASE_ADDR */
writel(0, mmio + RCV_RING_BASE_ADDR0);
/* This function handles the driver receive operation in polling mode */
static int amd8111e_rx_poll(struct net_device *dev, int * budget)
{
- struct amd8111e_priv *lp = dev->priv;
+ struct amd8111e_priv *lp = netdev_priv(dev);
int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
- void * mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
struct sk_buff *skb,*new_skb;
int min_pkt_len, status;
unsigned int intr0;
short vtag;
#endif
int rx_pkt_limit = dev->quota;
+ unsigned long flags;
do{
/* process receive packets until we use the quota*/
/* If we own the next entry, it's a new packet. Send it up. */
- while(!(lp->rx_ring[rx_index].rx_flags & OWN_BIT)){
-
- /* check if err summary bit is set */
- if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags)
- & ERR_BIT){
+ while(1) {
+ status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
+ if (status & OWN_BIT)
+ break;
+
/*
* There is a tricky error noted by John Murphy,
* <murf@perftech.com> to Russ Nelson: Even with
* the last correctly noting the error.
*/
- /* reseting flags */
- lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS;
- goto err_next_pkt;
-
+ if(status & ERR_BIT) {
+ /* reseting flags */
+ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+ goto err_next_pkt;
}
/* check for STP and ENP */
- status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
- if(!((status & STP_BIT) && (status & ENP_BIT))){
- /* reseting flags */
- lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS;
- goto err_next_pkt;
- }
- pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
+ if(!((status & STP_BIT) && (status & ENP_BIT))){
+ /* reseting flags */
+ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+ goto err_next_pkt;
+ }
+ pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
#if AMD8111E_VLAN_TAG_USED
- vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK;
- /*MAC will strip vlan tag*/
- if(lp->vlgrp != NULL && vtag !=0)
- min_pkt_len =MIN_PKT_LEN - 4;
- else
+ vtag = status & TT_MASK;
+ /*MAC will strip vlan tag*/
+ if(lp->vlgrp != NULL && vtag !=0)
+ min_pkt_len =MIN_PKT_LEN - 4;
+ else
#endif
- min_pkt_len =MIN_PKT_LEN;
+ min_pkt_len =MIN_PKT_LEN;
- if (pkt_len < min_pkt_len) {
- lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
- lp->drv_rx_errors++;
- goto err_next_pkt;
- }
- if(--rx_pkt_limit < 0)
- goto rx_not_empty;
- if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
- /* if allocation fail,
- ignore that pkt and go to next one */
- lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
- lp->drv_rx_errors++;
- goto err_next_pkt;
- }
+ if (pkt_len < min_pkt_len) {
+ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+ lp->drv_rx_errors++;
+ goto err_next_pkt;
+ }
+ if(--rx_pkt_limit < 0)
+ goto rx_not_empty;
+ if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
+ /* if allocation fail,
+ ignore that pkt and go to next one */
+ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+ lp->drv_rx_errors++;
+ goto err_next_pkt;
+ }
- skb_reserve(new_skb, 2);
- skb = lp->rx_skbuff[rx_index];
- pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
- lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
- skb_put(skb, pkt_len);
- skb->dev = dev;
- lp->rx_skbuff[rx_index] = new_skb;
- new_skb->dev = dev;
- lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
- new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE);
-
- skb->protocol = eth_type_trans(skb, dev);
+ skb_reserve(new_skb, 2);
+ skb = lp->rx_skbuff[rx_index];
+ pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
+ lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
+ skb_put(skb, pkt_len);
+ skb->dev = dev;
+ lp->rx_skbuff[rx_index] = new_skb;
+ new_skb->dev = dev;
+ lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
+ new_skb->data,
+ lp->rx_buff_len-2,
+ PCI_DMA_FROMDEVICE);
+
+ skb->protocol = eth_type_trans(skb, dev);
#if AMD8111E_VLAN_TAG_USED
-
- vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK;
- if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
- amd8111e_vlan_rx(lp, skb,
- lp->rx_ring[rx_index].tag_ctrl_info);
- } else
+ if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
+ amd8111e_vlan_rx(lp, skb,
+ le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
+ } else
#endif
-
- netif_receive_skb(skb);
- /*COAL update rx coalescing parameters*/
- lp->coal_conf.rx_packets++;
- lp->coal_conf.rx_bytes += pkt_len;
- num_rx_pkt++;
- dev->last_rx = jiffies;
+ netif_receive_skb(skb);
+ /*COAL update rx coalescing parameters*/
+ lp->coal_conf.rx_packets++;
+ lp->coal_conf.rx_bytes += pkt_len;
+ num_rx_pkt++;
+ dev->last_rx = jiffies;
-err_next_pkt:
- lp->rx_ring[rx_index].buff_phy_addr
- = cpu_to_le32(lp->rx_dma_addr[rx_index]);
- lp->rx_ring[rx_index].buff_count =
+ err_next_pkt:
+ lp->rx_ring[rx_index].buff_phy_addr
+ = cpu_to_le32(lp->rx_dma_addr[rx_index]);
+ lp->rx_ring[rx_index].buff_count =
cpu_to_le16(lp->rx_buff_len-2);
- lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
- rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
- }
- /* Check the interrupt status register for more packets in the
- mean time. Process them since we have not used up our quota.*/
+ wmb();
+ lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
+ rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
+ }
+ /* Check the interrupt status register for more packets in the
+ mean time. Process them since we have not used up our quota.*/
- intr0 = readl(mmio + INT0);
- /*Ack receive packets */
- writel(intr0 & RINT0,mmio + INT0);
+ intr0 = readl(mmio + INT0);
+ /*Ack receive packets */
+ writel(intr0 & RINT0,mmio + INT0);
- }while(intr0 & RINT0);
+ } while(intr0 & RINT0);
/* Receive descriptor is empty now */
dev->quota -= num_rx_pkt;
*budget -= num_rx_pkt;
+
+ spin_lock_irqsave(&lp->lock, flags);
netif_rx_complete(dev);
- /* enable receive interrupt */
writel(VAL0|RINTEN0, mmio + INTEN0);
writel(VAL2 | RDMD0, mmio + CMD0);
+ spin_unlock_irqrestore(&lp->lock, flags);
return 0;
+
rx_not_empty:
/* Do not call a netif_rx_complete */
dev->quota -= num_rx_pkt;
*budget -= num_rx_pkt;
return 1;
-
-
}
#else
/* If we own the next entry, it's a new packet. Send it up. */
while(++num_rx_pkt <= max_rx_pkt){
- if(lp->rx_ring[rx_index].rx_flags & OWN_BIT)
+ status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
+ if(status & OWN_BIT)
return 0;
/* check if err summary bit is set */
- if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & ERR_BIT){
+ if(status & ERR_BIT){
/*
* There is a tricky error noted by John Murphy,
* <murf@perftech.com> to Russ Nelson: Even with full-sized
goto err_next_pkt;
}
/* check for STP and ENP */
- status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
if(!((status & STP_BIT) && (status & ENP_BIT))){
/* reseting flags */
lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
#if AMD8111E_VLAN_TAG_USED
- vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK;
+ vtag = status & TT_MASK;
/*MAC will strip vlan tag*/
if(lp->vlgrp != NULL && vtag !=0)
min_pkt_len =MIN_PKT_LEN - 4;
skb->protocol = eth_type_trans(skb, dev);
-#if AMD8111E_VLAN_TAG_USED
-
- vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK;
+#if AMD8111E_VLAN_TAG_USED
if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
amd8111e_vlan_rx(lp, skb,
- lp->rx_ring[rx_index].tag_ctrl_info);
+ le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
} else
#endif
= cpu_to_le32(lp->rx_dma_addr[rx_index]);
lp->rx_ring[rx_index].buff_count =
cpu_to_le16(lp->rx_buff_len-2);
+ wmb();
lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
}
/*
This function reads the mib counters.
*/
-static int amd8111e_read_mib(void* mmio, u8 MIB_COUNTER)
+static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER)
{
unsigned int status;
unsigned int data;
static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
{
struct amd8111e_priv *lp = netdev_priv(dev);
- void * mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
unsigned long flags;
/* struct net_device_stats *prev_stats = &lp->prev_stats; */
struct net_device_stats* new_stats = &lp->stats;
struct net_device * dev = (struct net_device *) dev_id;
struct amd8111e_priv *lp = netdev_priv(dev);
- void * mmio = lp->mmio;
- unsigned int intr0;
+ void __iomem *mmio = lp->mmio;
+ unsigned int intr0, intren0;
unsigned int handled = 1;
- if(dev == NULL)
+ if(unlikely(dev == NULL))
return IRQ_NONE;
- if (regs) spin_lock (&lp->lock);
+ spin_lock(&lp->lock);
+
/* disabling interrupt */
writel(INTREN, mmio + CMD0);
/* Read interrupt status */
intr0 = readl(mmio + INT0);
+ intren0 = readl(mmio + INTEN0);
/* Process all the INT event until INTR bit is clear. */
writel(intr0, mmio + INT0);
/* Check if Receive Interrupt has occurred. */
-#if CONFIG_AMD8111E_NAPI
+#ifdef CONFIG_AMD8111E_NAPI
if(intr0 & RINT0){
if(netif_rx_schedule_prep(dev)){
/* Disable receive interupts */
/* Schedule a polling routine */
__netif_rx_schedule(dev);
}
- else {
+ else if (intren0 & RINTEN0) {
printk("************Driver bug! \
interrupt while in poll\n");
- /* Fix by disabling interrupts */
- writel(RINT0, mmio + INT0);
+ /* Fix by disable receive interrupts */
+ writel(RINTEN0, mmio + INTEN0);
}
}
#else
err_no_interrupt:
writel( VAL0 | INTREN,mmio + CMD0);
- if (regs) spin_unlock(&lp->lock);
+ spin_unlock(&lp->lock);
return IRQ_RETVAL(handled);
}
if(amd8111e_restart(dev)){
spin_unlock_irq(&lp->lock);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
return -ENOMEM;
}
/* Start ipg timer */
#if AMD8111E_VLAN_TAG_USED
if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){
lp->tx_ring[tx_index].tag_ctrl_cmd |=
- cpu_to_le32(TCC_VLAN_INSERT);
+ cpu_to_le16(TCC_VLAN_INSERT);
lp->tx_ring[tx_index].tag_ctrl_info =
cpu_to_le16(vlan_tx_tag_get(skb));
(u32) cpu_to_le32(lp->tx_dma_addr[tx_index]);
/* Set FCS and LTINT bits */
+ wmb();
lp->tx_ring[tx_index].tx_flags |=
cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT|ADD_FCS_BIT|LTINT_BIT);
/*
This function returns all the memory mapped registers of the device.
*/
-static char* amd8111e_read_regs(struct amd8111e_priv* lp)
-{
- void * mmio = lp->mmio;
- u32 * reg_buff;
-
- reg_buff = kmalloc( AMD8111E_REG_DUMP_LEN,GFP_KERNEL);
- if(NULL == reg_buff)
- return NULL;
-
+static void amd8111e_read_regs(struct amd8111e_priv *lp, u32 *buf)
+{
+ void __iomem *mmio = lp->mmio;
/* Read only necessary registers */
- reg_buff[0] = readl(mmio + XMT_RING_BASE_ADDR0);
- reg_buff[1] = readl(mmio + XMT_RING_LEN0);
- reg_buff[2] = readl(mmio + RCV_RING_BASE_ADDR0);
- reg_buff[3] = readl(mmio + RCV_RING_LEN0);
- reg_buff[4] = readl(mmio + CMD0);
- reg_buff[5] = readl(mmio + CMD2);
- reg_buff[6] = readl(mmio + CMD3);
- reg_buff[7] = readl(mmio + CMD7);
- reg_buff[8] = readl(mmio + INT0);
- reg_buff[9] = readl(mmio + INTEN0);
- reg_buff[10] = readl(mmio + LADRF);
- reg_buff[11] = readl(mmio + LADRF+4);
- reg_buff[12] = readl(mmio + STAT0);
-
- return (char *)reg_buff;
+ buf[0] = readl(mmio + XMT_RING_BASE_ADDR0);
+ buf[1] = readl(mmio + XMT_RING_LEN0);
+ buf[2] = readl(mmio + RCV_RING_BASE_ADDR0);
+ buf[3] = readl(mmio + RCV_RING_LEN0);
+ buf[4] = readl(mmio + CMD0);
+ buf[5] = readl(mmio + CMD2);
+ buf[6] = readl(mmio + CMD3);
+ buf[7] = readl(mmio + CMD7);
+ buf[8] = readl(mmio + INT0);
+ buf[9] = readl(mmio + INTEN0);
+ buf[10] = readl(mmio + LADRF);
+ buf[11] = readl(mmio + LADRF+4);
+ buf[12] = readl(mmio + STAT0);
}
+
/*
amd8111e crc generator implementation is different from the kernel
ether_crc() function.
*/
-int amd8111e_ether_crc(int len, char* mac_addr)
+static int amd8111e_ether_crc(int len, char* mac_addr)
{
int i,byte;
unsigned char octet;
}
-/*
-This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application.
-*/
-
-static int amd8111e_ethtool_ioctl(struct net_device* dev, void __user *useraddr)
+static void amd8111e_get_drvinfo(struct net_device* dev, struct ethtool_drvinfo *info)
{
struct amd8111e_priv *lp = netdev_priv(dev);
struct pci_dev *pci_dev = lp->pci_dev;
- u32 ethcmd;
-
- if( useraddr == NULL)
+ strcpy (info->driver, MODULE_NAME);
+ strcpy (info->version, MODULE_VERS);
+ sprintf(info->fw_version,"%u",chip_version);
+ strcpy (info->bus_info, pci_name(pci_dev));
+}
+
+static int amd8111e_get_regs_len(struct net_device *dev)
+{
+ return AMD8111E_REG_DUMP_LEN;
+}
+
+static void amd8111e_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ regs->version = 0;
+ amd8111e_read_regs(lp, buf);
+}
+
+static int amd8111e_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ spin_lock_irq(&lp->lock);
+ mii_ethtool_gset(&lp->mii_if, ecmd);
+ spin_unlock_irq(&lp->lock);
+ return 0;
+}
+
+static int amd8111e_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ int res;
+ spin_lock_irq(&lp->lock);
+ res = mii_ethtool_sset(&lp->mii_if, ecmd);
+ spin_unlock_irq(&lp->lock);
+ return res;
+}
+
+static int amd8111e_nway_reset(struct net_device *dev)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ return mii_nway_restart(&lp->mii_if);
+}
+
+static u32 amd8111e_get_link(struct net_device *dev)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ return mii_link_ok(&lp->mii_if);
+}
+
+static void amd8111e_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol_info)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ wol_info->supported = WAKE_MAGIC|WAKE_PHY;
+ if (lp->options & OPTION_WOL_ENABLE)
+ wol_info->wolopts = WAKE_MAGIC;
+}
+
+static int amd8111e_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol_info)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ if (wol_info->wolopts & ~(WAKE_MAGIC|WAKE_PHY))
return -EINVAL;
- if(copy_from_user (ðcmd, useraddr, sizeof (ethcmd)))
- return -EFAULT;
-
- switch(ethcmd){
-
- case ETHTOOL_GDRVINFO:{
- struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
- strcpy (info.driver, MODULE_NAME);
- strcpy (info.version, MODULE_VERS);
- memset(&info.fw_version, 0, sizeof(info.fw_version));
- sprintf(info.fw_version,"%u",chip_version);
- strcpy (info.bus_info, pci_name(pci_dev));
- info.eedump_len = 0;
- info.regdump_len = AMD8111E_REG_DUMP_LEN;
- if (copy_to_user (useraddr, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- /* get settings */
- case ETHTOOL_GSET: {
- struct ethtool_cmd ecmd = { ETHTOOL_GSET };
- spin_lock_irq(&lp->lock);
- mii_ethtool_gset(&lp->mii_if, &ecmd);
- spin_unlock_irq(&lp->lock);
- if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
- return -EFAULT;
- return 0;
- }
- /* set settings */
- case ETHTOOL_SSET: {
- int r;
- struct ethtool_cmd ecmd;
- if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
- return -EFAULT;
+ spin_lock_irq(&lp->lock);
+ if (wol_info->wolopts & WAKE_MAGIC)
+ lp->options |=
+ (OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
+ else if(wol_info->wolopts & WAKE_PHY)
+ lp->options |=
+ (OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
+ else
+ lp->options &= ~OPTION_WOL_ENABLE;
+ spin_unlock_irq(&lp->lock);
+ return 0;
+}
- spin_lock_irq(&lp->lock);
- r = mii_ethtool_sset(&lp->mii_if, &ecmd);
- spin_unlock_irq(&lp->lock);
- return r;
- }
- case ETHTOOL_GREGS: {
- struct ethtool_regs regs;
- u8 *regbuf;
- int ret;
-
- if (copy_from_user(®s, useraddr, sizeof(regs)))
- return -EFAULT;
- if (regs.len > AMD8111E_REG_DUMP_LEN)
- regs.len = AMD8111E_REG_DUMP_LEN;
- regs.version = 0;
- if (copy_to_user(useraddr, ®s, sizeof(regs)))
- return -EFAULT;
-
- regbuf = amd8111e_read_regs(lp);
- if (!regbuf)
- return -ENOMEM;
-
- useraddr += offsetof(struct ethtool_regs, data);
- ret = 0;
- if (copy_to_user(useraddr, regbuf, regs.len))
- ret = -EFAULT;
- kfree(regbuf);
- return ret;
- }
- /* restart autonegotiation */
- case ETHTOOL_NWAY_RST: {
- return mii_nway_restart(&lp->mii_if);
- }
- /* get link status */
- case ETHTOOL_GLINK: {
- struct ethtool_value val = {ETHTOOL_GLINK};
- val.data = mii_link_ok(&lp->mii_if);
- if (copy_to_user(useraddr, &val, sizeof(val)))
- return -EFAULT;
- return 0;
- }
- case ETHTOOL_GWOL: {
- struct ethtool_wolinfo wol_info = { ETHTOOL_GWOL };
-
- wol_info.supported = WAKE_MAGIC|WAKE_PHY;
- wol_info.wolopts = 0;
- if (lp->options & OPTION_WOL_ENABLE)
- wol_info.wolopts = WAKE_MAGIC;
- memset(&wol_info.sopass, 0, sizeof(wol_info.sopass));
- if (copy_to_user(useraddr, &wol_info, sizeof(wol_info)))
- return -EFAULT;
- return 0;
- }
- case ETHTOOL_SWOL: {
- struct ethtool_wolinfo wol_info;
+static struct ethtool_ops ops = {
+ .get_drvinfo = amd8111e_get_drvinfo,
+ .get_regs_len = amd8111e_get_regs_len,
+ .get_regs = amd8111e_get_regs,
+ .get_settings = amd8111e_get_settings,
+ .set_settings = amd8111e_set_settings,
+ .nway_reset = amd8111e_nway_reset,
+ .get_link = amd8111e_get_link,
+ .get_wol = amd8111e_get_wol,
+ .set_wol = amd8111e_set_wol,
+};
- if (copy_from_user(&wol_info, useraddr, sizeof(wol_info)))
- return -EFAULT;
- if (wol_info.wolopts & ~(WAKE_MAGIC |WAKE_PHY))
- return -EINVAL;
- spin_lock_irq(&lp->lock);
- if(wol_info.wolopts & WAKE_MAGIC)
- lp->options |=
- (OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
- else if(wol_info.wolopts & WAKE_PHY)
- lp->options |=
- (OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
- else
- lp->options &= ~OPTION_WOL_ENABLE;
- spin_unlock_irq(&lp->lock);
- return 0;
- }
+/*
+This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application.
+*/
- default:
- break;
- }
- return -EOPNOTSUPP;
-}
static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = if_mii(ifr);
return -EPERM;
switch(cmd) {
- case SIOCETHTOOL:
- return amd8111e_ethtool_ioctl(dev, ifr->ifr_data);
case SIOCGMIIPHY:
- data->phy_id = PHY_ID;
+ data->phy_id = lp->ext_phy_addr;
/* fallthru */
case SIOCGMIIREG:
}
static int amd8111e_set_mac_address(struct net_device *dev, void *p)
{
- struct amd8111e_priv *lp = dev->priv;
+ struct amd8111e_priv *lp = netdev_priv(dev);
int i;
struct sockaddr *addr = p;
/*
This function changes the mtu of the device. It restarts the device to initialize the descriptor with new receive buffers.
*/
-int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
+static int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
{
struct amd8111e_priv *lp = netdev_priv(dev);
int err;
if(!err)
netif_wake_queue(dev);
}
-static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state)
+static int amd8111e_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
struct amd8111e_priv *lp = netdev_priv(dev);
if(lp->options & OPTION_WAKE_PHY_ENABLE)
amd8111e_enable_link_change(lp);
- pci_enable_wake(pci_dev, 3, 1);
- pci_enable_wake(pci_dev, 4, 1); /* D3 cold */
+ pci_enable_wake(pci_dev, PCI_D3hot, 1);
+ pci_enable_wake(pci_dev, PCI_D3cold, 1);
}
else{
- pci_enable_wake(pci_dev, 3, 0);
- pci_enable_wake(pci_dev, 4, 0); /* 4 == D3 cold */
+ pci_enable_wake(pci_dev, PCI_D3hot, 0);
+ pci_enable_wake(pci_dev, PCI_D3cold, 0);
}
- pci_save_state(pci_dev, lp->pm_state);
- pci_set_power_state(pci_dev, 3);
+ pci_save_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D3hot);
return 0;
}
if (!netif_running(dev))
return 0;
- pci_set_power_state(pci_dev, 0);
- pci_restore_state(pci_dev, lp->pm_state);
+ pci_set_power_state(pci_dev, PCI_D0);
+ pci_restore_state(pci_dev);
- pci_enable_wake(pci_dev, 3, 0);
- pci_enable_wake(pci_dev, 4, 0); /* D3 cold */
+ pci_enable_wake(pci_dev, PCI_D3hot, 0);
+ pci_enable_wake(pci_dev, PCI_D3cold, 0); /* D3 cold */
netif_device_attach(dev);
struct net_device *dev = pci_get_drvdata(pdev);
if (dev) {
unregister_netdev(dev);
- iounmap((void *) ((struct amd8111e_priv *)(dev->priv))->mmio);
+ iounmap(((struct amd8111e_priv *)netdev_priv(dev))->mmio);
free_netdev(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
{
struct amd8111e_priv *lp = netdev_priv(dev);
struct ipg_info* ipg_data = &lp->ipg_data;
- void * mmio = lp->mmio;
+ void __iomem *mmio = lp->mmio;
unsigned int prev_col_cnt = ipg_data->col_cnt;
unsigned int total_col_cnt;
unsigned int tmp_ipg;
}
+static void __devinit amd8111e_probe_ext_phy(struct net_device* dev)
+{
+ struct amd8111e_priv *lp = netdev_priv(dev);
+ int i;
+
+ for (i = 0x1e; i >= 0; i--) {
+ u32 id1, id2;
+
+ if (amd8111e_read_phy(lp, i, MII_PHYSID1, &id1))
+ continue;
+ if (amd8111e_read_phy(lp, i, MII_PHYSID2, &id2))
+ continue;
+ lp->ext_phy_id = (id1 << 16) | id2;
+ lp->ext_phy_addr = i;
+ return;
+ }
+ lp->ext_phy_id = 0;
+ lp->ext_phy_addr = 1;
+}
+
static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
}
/* Initialize DMA */
- if(!pci_dma_supported(pdev, 0xffffffff)){
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) < 0) {
printk(KERN_ERR "amd8111e: DMA not supported,"
"exiting.\n");
- goto err_free_reg;
- } else
- pdev->dma_mask = 0xffffffff;
+ goto err_free_reg;
+ }
reg_addr = pci_resource_start(pdev, 0);
reg_len = pci_resource_len(pdev, 0);
lp->amd8111e_net_dev = dev;
lp->pm_cap = pm_cap;
- /* setting mii default values */
- lp->mii_if.dev = dev;
- lp->mii_if.mdio_read = amd8111e_mdio_read;
- lp->mii_if.mdio_write = amd8111e_mdio_write;
- lp->mii_if.phy_id = PHY_ID;
-
spin_lock_init(&lp->lock);
lp->mmio = ioremap(reg_addr, reg_len);
dev->set_mac_address = amd8111e_set_mac_address;
dev->do_ioctl = amd8111e_ioctl;
dev->change_mtu = amd8111e_change_mtu;
+ SET_ETHTOOL_OPS(dev, &ops);
dev->irq =pdev->irq;
dev->tx_timeout = amd8111e_tx_timeout;
dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
dev->vlan_rx_register =amd8111e_vlan_rx_register;
dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
#endif
-
+ /* Probe the external PHY */
+ amd8111e_probe_ext_phy(dev);
+
+ /* setting mii default values */
+ lp->mii_if.dev = dev;
+ lp->mii_if.mdio_read = amd8111e_mdio_read;
+ lp->mii_if.mdio_write = amd8111e_mdio_write;
+ lp->mii_if.phy_id = lp->ext_phy_addr;
+
/* Set receive buffer length and set jumbo option*/
amd8111e_set_rx_buff_len(dev);
for (i = 0; i < 6; i++)
printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
printk( "\n");
+ if (lp->ext_phy_id)
+ printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
+ dev->name, lp->ext_phy_id, lp->ext_phy_addr);
+ else
+ printk(KERN_INFO "%s: Couldn't detect MII PHY, assuming address 0x01\n",
+ dev->name);
return 0;
err_iounmap:
- iounmap((void *) lp->mmio);
+ iounmap(lp->mmio);
err_free_dev:
free_netdev(dev);