patch-2.4.18 linux/drivers/net/8139cp.c
Next file: linux/drivers/net/8139too.c
Previous file: linux/drivers/net/3c527.c
Back to the patch index
Back to the overall index
- Lines: 330
- Date:
Mon Jan 14 17:27:24 2002
- Orig file:
linux.orig/drivers/net/8139cp.c
- Orig date:
Mon Feb 18 20:18:39 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/drivers/net/8139cp.c linux/drivers/net/8139cp.c
@@ -20,7 +20,6 @@
TODO, in rough priority order:
* dev->tx_timeout
* LinkChg interrupt
- * ETHTOOL_[GS]SET
* Support forcing media type with a module parameter,
like dl2k.c/sundance.c
* Implement PCI suspend/resume
@@ -33,18 +32,19 @@
* Rx checksumming
* Tx checksumming
* ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
- ETHTOOL_[GS]MSGLVL, ETHTOOL_NWAY_RST
* Jumbo frames / dev->change_mtu
* Investigate using skb->priority with h/w VLAN priority
* Investigate using High Priority Tx Queue with skb->priority
* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
+ * Implement Tx software interrupt mitigation via
+ Tx descriptor bit
*/
#define DRV_NAME "8139cp"
-#define DRV_VERSION "0.0.5"
-#define DRV_RELDATE "Oct 19, 2001"
+#define DRV_VERSION "0.0.6"
+#define DRV_RELDATE "Nov 19, 2001"
#include <linux/module.h>
@@ -55,6 +55,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
+#include <linux/mii.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -76,17 +77,6 @@
MODULE_PARM (multicast_filter_limit, "i");
MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered multicast addresses");
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
-#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
- || defined(__sparc_) || defined(__ia64__) \
- || defined(__sh__) || defined(__mips__)
-static int rx_copybreak = 1518;
-#else
-static int rx_copybreak = 100;
-#endif
-MODULE_PARM (rx_copybreak, "i");
-MODULE_PARM_DESC (rx_copybreak, "8139cp Breakpoint at which Rx packets are copied");
-
#define PFX DRV_NAME ": "
#define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
@@ -104,10 +94,10 @@
(((CP)->tx_tail <= (CP)->tx_head) ? \
(CP)->tx_tail + (CP_TX_RING_SIZE - 1) - (CP)->tx_head : \
(CP)->tx_tail - (CP)->tx_head - 1)
-#define CP_CHIP_VERSION 0x76
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
#define RX_OFFSET 2
+#define CP_INTERNAL_PHY 32
/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
#define RX_FIFO_THRESH 5 /* Rx buffer level before first PCI xfer. */
@@ -136,6 +126,11 @@
Config3 = 0x59, /* Config3 */
Config4 = 0x5A, /* Config4 */
MultiIntr = 0x5C, /* Multiple interrupt select */
+ BasicModeCtrl = 0x62, /* MII BMCR */
+ BasicModeStatus = 0x64, /* MII BMSR */
+ NWayAdvert = 0x66, /* MII ADVERTISE */
+ NWayLPAR = 0x68, /* MII LPA */
+ NWayExpansion = 0x6A, /* MII Expansion */
Config5 = 0xD8, /* Config5 */
TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */
CpCmd = 0xE0, /* C+ Command register (C+ mode only) */
@@ -289,6 +284,8 @@
struct sk_buff *frag_skb;
unsigned dropping_frag : 1;
+
+ struct mii_if_info mii_if;
};
#define cpr8(reg) readb(cp->regs + (reg))
@@ -333,8 +330,8 @@
netif_rx (skb);
}
-static inline void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
- u32 status, u32 len)
+static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
+ u32 status, u32 len)
{
if (netif_msg_rx_err (cp))
printk (KERN_DEBUG
@@ -428,8 +425,8 @@
while (rx_work--) {
u32 status, len;
dma_addr_t mapping;
- struct sk_buff *skb, *copy_skb;
- unsigned copying_skb, buflen;
+ struct sk_buff *skb, *new_skb;
+ unsigned buflen;
skb = cp->rx_skb[rx_tail].skb;
if (!skb)
@@ -452,43 +449,30 @@
goto rx_next;
}
- copying_skb = (len <= rx_copybreak);
-
if (netif_msg_rx_status(cp))
- printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n",
- cp->dev->name, rx_tail, status, len,
- copying_skb);
-
- buflen = copying_skb ? len : cp->rx_buf_sz;
- copy_skb = dev_alloc_skb (buflen + RX_OFFSET);
- if (!copy_skb) {
+ printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",
+ cp->dev->name, rx_tail, status, len);
+
+ buflen = cp->rx_buf_sz + RX_OFFSET;
+ new_skb = dev_alloc_skb (buflen);
+ if (!new_skb) {
cp->net_stats.rx_dropped++;
goto rx_next;
}
- skb_reserve(copy_skb, RX_OFFSET);
- copy_skb->dev = cp->dev;
-
- if (!copying_skb) {
- pci_unmap_single(cp->pdev, mapping,
- buflen, PCI_DMA_FROMDEVICE);
- skb->ip_summed = CHECKSUM_NONE;
- skb_trim(skb, len);
-
- mapping =
- cp->rx_skb[rx_tail].mapping =
- pci_map_single(cp->pdev, copy_skb->data,
- buflen, PCI_DMA_FROMDEVICE);
- cp->rx_skb[rx_tail].skb = copy_skb;
- skb_put(copy_skb, buflen);
- } else {
- skb_put(copy_skb, len);
- pci_dma_sync_single(cp->pdev, mapping, len, PCI_DMA_FROMDEVICE);
- memcpy(copy_skb->data, skb->data, len);
+ skb_reserve(new_skb, RX_OFFSET);
+ new_skb->dev = cp->dev;
- /* We'll reuse the original ring buffer. */
- skb = copy_skb;
- }
+ pci_unmap_single(cp->pdev, mapping,
+ buflen, PCI_DMA_FROMDEVICE);
+ skb->ip_summed = CHECKSUM_NONE;
+ skb_put(skb, len);
+
+ mapping =
+ cp->rx_skb[rx_tail].mapping =
+ pci_map_single(cp->pdev, new_skb->tail,
+ buflen, PCI_DMA_FROMDEVICE);
+ cp->rx_skb[rx_tail].skb = new_skb;
cp_rx_skb(cp, skb);
@@ -899,10 +883,9 @@
skb->dev = cp->dev;
skb_reserve(skb, RX_OFFSET);
- skb_put(skb, cp->rx_buf_sz);
cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
- skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
cp->rx_skb[i].skb = skb;
cp->rx_skb[i].frag = 0;
@@ -1025,6 +1008,39 @@
return 0;
}
+static char mii_2_8139_map[8] = {
+ BasicModeCtrl,
+ BasicModeStatus,
+ 0,
+ 0,
+ NWayAdvert,
+ NWayLPAR,
+ NWayExpansion,
+ 0
+};
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ struct cp_private *cp = dev->priv;
+
+ return location < 8 && mii_2_8139_map[location] ?
+ readw(cp->regs + mii_2_8139_map[location]) : 0;
+}
+
+
+static void mdio_write(struct net_device *dev, int phy_id, int location,
+ int value)
+{
+ struct cp_private *cp = dev->priv;
+
+ if (location == 0) {
+ cpw8(Cfg9346, Cfg9346_Unlock);
+ cpw16(BasicModeCtrl, value);
+ cpw8(Cfg9346, Cfg9346_Lock);
+ } else if (location < 8 && mii_2_8139_map[location])
+ cpw16(mii_2_8139_map[location], value);
+}
+
static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
{
u32 ethcmd;
@@ -1032,21 +1048,71 @@
/* dev_ioctl() in ../../net/core/dev.c has already checked
capable(CAP_NET_ADMIN), so don't bother with that here. */
- if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd)))
+ if (get_user(ethcmd, (u32 *)useraddr))
return -EFAULT;
switch (ethcmd) {
- case ETHTOOL_GDRVINFO:
- {
- struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
- strcpy (info.driver, DRV_NAME);
- strcpy (info.version, DRV_VERSION);
- strcpy (info.bus_info, cp->pdev->slot_name);
- if (copy_to_user (useraddr, &info, sizeof (info)))
- return -EFAULT;
- return 0;
- }
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ strcpy (info.driver, DRV_NAME);
+ strcpy (info.version, DRV_VERSION);
+ strcpy (info.bus_info, cp->pdev->slot_name);
+ 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(&cp->lock);
+ mii_ethtool_gset(&cp->mii_if, &ecmd);
+ spin_unlock_irq(&cp->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(&cp->lock);
+ r = mii_ethtool_sset(&cp->mii_if, &ecmd);
+ spin_unlock_irq(&cp->lock);
+ return r;
+ }
+ /* restart autonegotiation */
+ case ETHTOOL_NWAY_RST: {
+ return mii_nway_restart(&cp->mii_if);
+ }
+ /* get link status */
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = {ETHTOOL_GLINK};
+ edata.data = mii_link_ok(&cp->mii_if);
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get message-level */
+ case ETHTOOL_GMSGLVL: {
+ struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+ edata.data = cp->msg_enable;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+ /* set message-level */
+ case ETHTOOL_SMSGLVL: {
+ struct ethtool_value edata;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ cp->msg_enable = edata.data;
+ return 0;
+ }
default:
break;
@@ -1061,6 +1127,9 @@
struct cp_private *cp = dev->priv;
int rc = 0;
+ if (!netif_running(dev))
+ return -EINVAL;
+
switch (cmd) {
case SIOCETHTOOL:
return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
@@ -1173,6 +1242,10 @@
cp->dev = dev;
cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
spin_lock_init (&cp->lock);
+ cp->mii_if.dev = dev;
+ cp->mii_if.mdio_read = mdio_read;
+ cp->mii_if.mdio_write = mdio_write;
+ cp->mii_if.phy_id = CP_INTERNAL_PHY;
rc = pci_enable_device(pdev);
if (rc)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)