X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Famd8111e.c;h=d9ba8be72af804462735ef7a6facad667f3da765;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=91fa987dc8a868de846bfceb2691b4001b273d0d;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 91fa987dc..d9ba8be72 100755 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -87,6 +87,7 @@ Revision History: #include #include #include +#include #include #include @@ -105,11 +106,12 @@ Revision History: 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[] = { @@ -124,7 +126,7 @@ This function will read the PHY registers. */ 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; @@ -155,7 +157,7 @@ This function will write into PHY registers. 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); @@ -211,7 +213,7 @@ static void amd8111e_set_ext_phy(struct net_device *dev) 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){ @@ -235,11 +237,11 @@ static void amd8111e_set_ext_phy(struct net_device *dev) } 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); } @@ -350,6 +352,7 @@ static int amd8111e_init_ring(struct net_device *dev) 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); } @@ -384,7 +387,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod) 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; @@ -442,7 +445,7 @@ This function initializes the device registers and starts the device. 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 */ @@ -522,14 +525,14 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp) { 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); @@ -723,9 +726,9 @@ static int amd8111e_tx(struct net_device *dev) /* 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; @@ -736,15 +739,16 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) 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, * to Russ Nelson: Even with @@ -753,105 +757,105 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) * 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 @@ -873,11 +877,12 @@ static int amd8111e_rx(struct net_device *dev) /* 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, * to Russ Nelson: Even with full-sized @@ -888,7 +893,6 @@ static int amd8111e_rx(struct net_device *dev) 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; @@ -897,7 +901,7 @@ static int amd8111e_rx(struct net_device *dev) 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; @@ -931,12 +935,10 @@ static int amd8111e_rx(struct net_device *dev) 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 @@ -952,6 +954,7 @@ err_next_pkt: = 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; } @@ -1004,7 +1007,7 @@ static int amd8111e_link_change(struct net_device* dev) /* 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; @@ -1027,7 +1030,7 @@ This function reads the mib registers and returns the hardware statistics. It u 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; @@ -1260,19 +1263,21 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg 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. */ @@ -1285,7 +1290,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg 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 */ @@ -1293,11 +1298,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg /* 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 @@ -1321,7 +1326,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg err_no_interrupt: writel( VAL0 | INTREN,mmio + CMD0); - if (regs) spin_unlock(&lp->lock); + spin_unlock(&lp->lock); return IRQ_RETVAL(handled); } @@ -1382,6 +1387,8 @@ static int amd8111e_open(struct net_device * dev ) if(amd8111e_restart(dev)){ spin_unlock_irq(&lp->lock); + if (dev->irq) + free_irq(dev->irq, dev); return -ENOMEM; } /* Start ipg timer */ @@ -1432,7 +1439,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) #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)); @@ -1444,6 +1451,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) (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); @@ -1464,37 +1472,30 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) /* 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; @@ -1567,131 +1568,101 @@ static void amd8111e_set_multicast_list(struct net_device *dev) } -/* -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); @@ -1703,10 +1674,8 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) 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: @@ -1736,7 +1705,7 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) } 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; @@ -1754,7 +1723,7 @@ static int amd8111e_set_mac_address(struct net_device *dev, void *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; @@ -1836,7 +1805,7 @@ static void amd8111e_tx_timeout(struct net_device *dev) 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); @@ -1865,17 +1834,17 @@ static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state) 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; } @@ -1887,11 +1856,11 @@ static int amd8111e_resume(struct pci_dev *pci_dev) 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); @@ -1912,7 +1881,7 @@ static void __devexit amd8111e_remove_one(struct pci_dev *pdev) 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); @@ -1923,7 +1892,7 @@ static void amd8111e_config_ipg(struct net_device* dev) { 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; @@ -1979,6 +1948,26 @@ static void amd8111e_config_ipg(struct net_device* dev) } +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) { @@ -2018,12 +2007,11 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, } /* 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); @@ -2049,12 +2037,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, 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); @@ -2085,6 +2067,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, 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; @@ -2101,7 +2084,15 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, 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); @@ -2134,9 +2125,15 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, 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);