@@ -396,6 +474,12 @@ static inline void pci_push(u8 * base)
readl(base);
}
+static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
+{
+ return le32_to_cpu(prd->FlagLen)
+ & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
+}
+
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
int delay, int delaymax, const char *msg)
{@@ -422,24 +506,18 @@ static int reg_delay(struct net_device *
static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
{
u8 *base = get_hwbase(dev);
- int was_running;
u32 reg;
int retval;
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
- was_running = 0;
- reg = readl(base + NvRegAdapterControl);
- if (reg & NVREG_ADAPTCTL_RUNNING) {
- was_running = 1;
- writel(reg & ~NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
- }
+
reg = readl(base + NvRegMIIControl);
if (reg & NVREG_MIICTL_INUSE) {
writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl);
udelay(NV_MIIBUSY_DELAY);
}
- reg = NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
+ reg = (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
if (value != MII_READ) {
writel(value, base + NvRegMIIData);
reg |= NVREG_MIICTL_WRITE;@@ -461,19 +539,117 @@ static int mii_rw(struct net_device *dev
dev->name, miireg, addr);
retval = -1;
} else {
- /* FIXME: why is that required? */
- udelay(50);
retval = readl(base + NvRegMIIData);
dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n",
dev->name, miireg, addr, retval);
}
- if (was_running) {
- reg = readl(base + NvRegAdapterControl);
- writel(reg | NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
- }
+
return retval;
}
+static int phy_reset(struct net_device *dev)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ u32 miicontrol;
+ unsigned int tries = 0;
+
+ miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ miicontrol |= BMCR_RESET;
+ if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) {
+ return -1;
+ }
+
+ /* wait for 500ms */
+ msleep(500);
+
+ /* must wait till reset is deasserted */
+ while (miicontrol & BMCR_RESET) {
+ msleep(10);
+ miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ /* FIXME: 100 tries seem excessive */
+ if (tries++ > 100)
+ return -1;
+ }
+ return 0;
+}
+
+static int phy_init(struct net_device *dev)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ u8 *base = get_hwbase(dev);
+ u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;
+
+ /* set advertise register */
+ reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
+ reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|0x800|0x400);
+ if (mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg)) {
+ printk(KERN_INFO "%s: phy write to advertise failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+
+ /* get phy interface type */
+ phyinterface = readl(base + NvRegPhyInterface);
+
+ /* see if gigabit phy */
+ mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
+ if (mii_status & PHY_GIGABIT) {
+ np->gigabit = PHY_GIGABIT;
+ mii_control_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
+ mii_control_1000 &= ~ADVERTISE_1000HALF;
+ if (phyinterface & PHY_RGMII)
+ mii_control_1000 |= ADVERTISE_1000FULL;
+ else
+ mii_control_1000 &= ~ADVERTISE_1000FULL;
+
+ if (mii_rw(dev, np->phyaddr, MII_1000BT_CR, mii_control_1000)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
+ else
+ np->gigabit = 0;
+
+ /* reset the phy */
+ if (phy_reset(dev)) {
+ printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+
+ /* phy vendor specific configuration */
+ if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) {
+ phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ);
+ phy_reserved &= ~(PHY_INIT1 | PHY_INIT2);
+ phy_reserved |= (PHY_INIT3 | PHY_INIT4);
+ if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
+ phy_reserved |= PHY_INIT5;
+ if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
+ if (np->phy_oui == PHY_OUI_CICADA) {
+ phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ);
+ phy_reserved |= PHY_INIT6;
+ if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
+
+ /* restart auto negotiation */
+ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
+ if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) {
+ return PHY_ERROR;
+ }
+
+ return 0;
+}
+
static void nv_start_rx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);@@ -488,6 +664,8 @@ static void nv_start_rx(struct net_devic
writel(np->linkspeed, base + NvRegLinkSpeed);
pci_push(base);
writel(NVREG_RCVCTL_START, base + NvRegReceiverControl);
+ dprintk(KERN_DEBUG "%s: nv_start_rx to duplex %d, speed 0x%08x.\n",
+ dev->name, np->duplex, np->linkspeed);
pci_push(base);
}
@@ -498,8 +676,8 @@ static void nv_stop_rx(struct net_device
dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
writel(0, base + NvRegReceiverControl);
reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
- NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
- KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");
+ NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
+ KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");
udelay(NV_RXSTOP_DELAY2);
writel(0, base + NvRegLinkSpeed);
@@ -521,8 +699,8 @@ static void nv_stop_tx(struct net_device
dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
writel(0, base + NvRegTransmitterControl);
reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
- NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
- KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
+ NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
+ KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
udelay(NV_TXSTOP_DELAY2);
writel(0, base + NvRegUnknownTransmitterReg);
@@ -530,13 +708,14 @@ static void nv_stop_tx(struct net_device
static void nv_txrx_reset(struct net_device *dev)
{
+ struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
- writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
- writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
}
@@ -651,11 +830,12 @@ static int nv_alloc_rx(struct net_device
{
struct fe_priv *np = get_nvpriv(dev);
unsigned int refill_rx = np->refill_rx;
+ int nr;
while (np->cur_rx != refill_rx) {
- int nr = refill_rx % RX_RING;
struct sk_buff *skb;
+ nr = refill_rx % RX_RING;
if (np->rx_skbuff[nr] == NULL) {
skb = dev_alloc_skb(RX_ALLOC_BUFSIZE);@@ -670,10 +850,9 @@ static int nv_alloc_rx(struct net_device
np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len,
PCI_DMA_FROMDEVICE);
np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
- np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE);
wmb();
- np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL);
- dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
+ np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
+ dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
dev->name, refill_rx);
refill_rx++;
}
@@ -704,15 +883,13 @@ static int nv_init_ring(struct net_devic
int i;
np->next_tx = np->nic_tx = 0;
- for (i = 0; i < TX_RING; i++) {
- np->tx_ring[i].Flags = 0;
- }
+ for (i = 0; i < TX_RING; i++)
+ np->tx_ring[i].FlagLen = 0;
np->cur_rx = RX_RING;
np->refill_rx = 0;
- for (i = 0; i < RX_RING; i++) {
- np->rx_ring[i].Flags = 0;
- }
+ for (i = 0; i < RX_RING; i++)
+ np->rx_ring[i].FlagLen = 0;
return nv_alloc_rx(dev);
}
@@ -721,7 +898,7 @@ static void nv_drain_tx(struct net_devic
struct fe_priv *np = get_nvpriv(dev);
int i;
for (i = 0; i < TX_RING; i++) {
- np->tx_ring[i].Flags = 0;
+ np->tx_ring[i].FlagLen = 0;
if (np->tx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->tx_dma[i],
np->tx_skbuff[i]->len,@@ -738,7 +915,7 @@ static void nv_drain_rx(struct net_devic
struct fe_priv *np = get_nvpriv(dev);
int i;
for (i = 0; i < RX_RING; i++) {
- np->rx_ring[i].Flags = 0;
+ np->rx_ring[i].FlagLen = 0;
wmb();
if (np->rx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->rx_dma[i],@@ -770,11 +947,10 @@ static int nv_start_xmit(struct sk_buff
PCI_DMA_TODEVICE);
np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring[nr].Length = cpu_to_le16(skb->len-1);
spin_lock_irq(&np->lock);
wmb();
- np->tx_ring[nr].Flags = np->tx_flags;
+ np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n",
dev->name, np->next_tx);
{@@ -793,7 +969,7 @@ static int nv_start_xmit(struct sk_buff
if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
netif_stop_queue(dev);
spin_unlock_irq(&np->lock);
- writel(NVREG_TXRXCTL_KICK, get_hwbase(dev) + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
pci_push(get_hwbase(dev));
return 0;
}
@@ -806,27 +982,42 @@ static int nv_start_xmit(struct sk_buff
static void nv_tx_done(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
+ u32 Flags;
+ int i;
- while (np->nic_tx < np->next_tx) {
- struct ring_desc *prd;
- int i = np->nic_tx % TX_RING;
+ while (np->nic_tx != np->next_tx) {
+ i = np->nic_tx % TX_RING;
- prd = &np->tx_ring[i];
+ Flags = cpu_to_le32(np->tx_ring[i].FlagLen);