colinux64/patch/conet-pci-core.diff
2025-02-13 19:44:47 -07:00

450 lines
11 KiB
Diff
Executable File

Index: linux-2.6.22-source/drivers/net/conet.c
===================================================================
--- /dev/null
+++ linux-2.6.22-source/drivers/net/conet.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2003-2004 Dan Aloni <da-x@gmx.net>
+ * Copyright (C) 2004 Pat Erley
+ * Copyright (C) 2004 George Boutwell
+ * Copyright (C) 2007 Steve Shoecraft <sshoecraft@earthlink.net>
+ *
+ * Cooperative Linux Network Device implementation
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/pci.h>
+
+#include <linux/cooperative_internal.h>
+#include <linux/cooperative_pci.h>
+#include <asm/irq.h>
+
+#define DRV_NAME "conet"
+#define DRV_VERSION "1.02"
+
+struct conet_priv {
+ struct net_device_stats stats;
+ int unit;
+ unsigned short flags;
+ struct pci_dev *pdev;
+ spinlock_t rx_lock;
+ spinlock_t ioctl_lock;
+ struct mii_if_info mii_if;
+};
+
+#define CONET_FLAG_ENABLED 0x01
+#define CONET_FLAG_HANDLING 0x02
+#define CONET_FLAG_DEBUG 0x80
+
+static struct net_device *conet_dev[CO_MODULE_MAX_CONET];
+
+static int conet_open(struct net_device *dev)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+
+ if (priv->flags & CONET_FLAG_ENABLED) return 0;
+
+ priv->flags |= CONET_FLAG_ENABLED;
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int conet_stop(struct net_device *dev)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+
+ priv->flags &= ~CONET_FLAG_ENABLED;
+
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+static int conet_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int len;
+ char *data;
+ struct conet_priv *priv = netdev_priv(dev);
+
+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+ data = skb->data;
+
+ dev->trans_start = jiffies; /* save the timestamp */
+
+ co_send_message(CO_MODULE_LINUX,
+ CO_MODULE_CONET0 + priv->unit,
+ CO_PRIORITY_DISCARDABLE,
+ CO_MESSAGE_TYPE_OTHER,
+ len,
+ data);
+
+ priv->stats.tx_bytes+=skb->len;
+ priv->stats.tx_packets++;
+
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static void conet_rx(struct net_device *dev, co_linux_message_t *message)
+{
+ struct sk_buff *skb;
+ struct conet_priv *priv = netdev_priv(dev);
+ int len;
+ unsigned char *buf;
+
+ len = message->size;
+ if (len > 0x10000) {
+ printk("conet rx: buggy network reception\n");
+ priv->stats.rx_dropped++;
+ return;
+ }
+
+ buf = message->data;
+
+ /*
+ * The packet has been retrieved from the transmission
+ * medium. Build an skb around it, so upper layers can handle it
+ */
+ skb = dev_alloc_skb(len+2);
+ if (!skb) {
+ printk("conet rx: low on mem - packet dropped\n");
+ priv->stats.rx_dropped++;
+ return;
+ }
+
+ memcpy(skb_put(skb, len), buf, len);
+
+ /* Write metadata, and then pass to the receive level */
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_NONE; /* make the kernel calculate and verify
+ the checksum */
+
+ priv->stats.rx_bytes += len;
+ priv->stats.rx_packets++;
+
+ netif_rx(skb);
+ return;
+}
+
+static irqreturn_t conet_interrupt(int irq, void *dev_id)
+{
+ co_message_node_t *node_message;
+
+ while (co_get_message(&node_message, CO_DEVICE_NETWORK)) {
+ struct net_device *dev;
+ struct conet_priv *priv;
+ co_linux_message_t *message;
+
+ message = (co_linux_message_t *)&node_message->msg.data;
+ if (message->unit >= CO_MODULE_MAX_CONET) {
+ printk("conet interrupt: buggy network reception unit %d\n", message->unit);
+ return IRQ_HANDLED;
+ }
+
+ dev = conet_dev[message->unit];
+ if (!dev) {
+ co_free_message(node_message);
+ continue;
+ }
+
+ if (!netif_running(dev)) {
+ co_free_message(node_message);
+ continue;
+ }
+
+ if (node_message->msg.type == CO_MESSAGE_TYPE_STRING) {
+ int connected= *(int*)(message+1);
+ if (connected)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ co_free_message(node_message);
+ continue;
+ }
+
+ priv = netdev_priv(dev);
+ spin_lock(&priv->rx_lock);
+#if 0
+ if (priv->flags & CONET_FLAG_HANDLING) {
+ co_free_message(node_message);
+ continue;
+ }
+
+ priv->flags |= CONET_FLAG_HANDLING;
+ conet_rx(dev, message);
+ co_free_message(node_message);
+ priv->flags &= ~CONET_FLAG_HANDLING;
+#endif
+ conet_rx(dev, message);
+ co_free_message(node_message);
+ spin_unlock(&priv->rx_lock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct net_device_stats* conet_get_stats(struct net_device *dev)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+
+ return &priv->stats;
+}
+
+static int conet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ /* We support 100-baseT Full duplex TP */
+ cmd->port = PORT_TP;
+ cmd->duplex = DUPLEX_FULL;
+ cmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
+ cmd->speed = SPEED_100;
+ return 0;
+}
+
+static int conet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ /* We support TP Full duplex 100 */
+ if (cmd->port != PORT_TP || cmd->duplex != DUPLEX_FULL || cmd->speed != SPEED_100)
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static void conet_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(priv->pdev));
+}
+
+static u32 conet_get_link(struct net_device *dev)
+{
+ /* Always connected */
+ return 1;
+}
+
+static u32 conet_get_msglevel(struct net_device *dev)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+
+ return ((priv->flags & CONET_FLAG_DEBUG) != 0);
+}
+
+static void conet_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+
+ if (level)
+ priv->flags |= CONET_FLAG_DEBUG;
+ else
+ priv->flags &= ~CONET_FLAG_DEBUG;
+}
+
+static int conet_mdio_read(struct net_device *dev, int id, int reg)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+ int val;
+
+ if (priv->flags & CONET_FLAG_DEBUG)
+ printk(KERN_INFO "conet%d: mdio_read: id: %d, reg: %d\n", priv->unit, id, reg);
+ switch(reg) {
+ case MII_BMCR: /* Basic mode control register */
+ val = BMCR_FULLDPLX | BMCR_SPEED100;
+ break;
+ case MII_BMSR: /* Basic mode status register */
+ val = BMSR_LSTATUS | BMSR_100FULL;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static void conet_mdio_write(struct net_device *dev, int id, int reg, int val)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+
+ if (priv->flags & CONET_FLAG_DEBUG)
+ printk(KERN_INFO "conet%d: mdio_write: id: %d, reg: %d, val: %d\n", priv->unit, id, reg, val);
+ return;
+}
+
+static int conet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct conet_priv *priv = netdev_priv(dev);
+ int rc;
+
+ spin_lock(&priv->ioctl_lock);
+ rc = generic_mii_ioctl(&priv->mii_if, if_mii(rq), cmd, NULL);
+ spin_unlock(&priv->ioctl_lock);
+
+ return rc;
+}
+
+static const struct ethtool_ops conet_ethtool_ops = {
+ .get_settings = conet_get_settings,
+ .set_settings = conet_set_settings,
+ .get_drvinfo = conet_get_drvinfo,
+ .get_link = conet_get_link,
+ .get_msglevel = conet_get_msglevel,
+ .set_msglevel = conet_set_msglevel,
+#if 0
+ .nway_reset = conet_nway_reset,
+ .get_ringparam = conet_get_ringparam,
+ .set_ringparam = conet_set_ringparam,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_tso = ethtool_op_get_tso,
+ .get_strings = conet_get_strings,
+ .self_test_count = conet_self_test_count,
+ .self_test = conet_ethtool_test,
+ .phys_id = conet_phys_id,
+ .get_regs_len = conet_get_regs_len,
+ .get_regs = conet_get_regs,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+#endif
+};
+
+static struct pci_device_id conet_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CO, PCI_DEVICE_ID_CONET) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, conet_pci_ids);
+
+static int __devinit conet_pci_probe( struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ u8 unit, addr[6];
+ struct net_device *dev;
+ struct conet_priv *priv;
+ int rc;
+
+// printk(KERN_INFO "CONET: probing!\n");
+
+ unit = -1;
+ pci_read_config_byte(pdev, PCI_CO_UNIT, &unit);
+ pci_read_config_byte(pdev, PCI_CO_MAC1, &addr[0]);
+ pci_read_config_byte(pdev, PCI_CO_MAC2, &addr[1]);
+ pci_read_config_byte(pdev, PCI_CO_MAC3, &addr[2]);
+ pci_read_config_byte(pdev, PCI_CO_MAC4, &addr[3]);
+ pci_read_config_byte(pdev, PCI_CO_MAC5, &addr[4]);
+ pci_read_config_byte(pdev, PCI_CO_MAC6, &addr[5]);
+
+ dev = alloc_etherdev(sizeof(*priv));
+ if (dev == NULL) {
+ printk(KERN_ERR "conet%d: could not allocate memory for device.\n", unit);
+ rc = -ENOMEM;
+ goto error_out_pdev;
+ }
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ memcpy(dev->dev_addr, addr, 6);
+
+ dev->open = conet_open;
+ dev->stop = conet_stop;
+ dev->hard_start_xmit = conet_hard_start_xmit;
+ dev->ethtool_ops = &conet_ethtool_ops;
+ dev->get_stats = conet_get_stats;
+ dev->do_ioctl = conet_ioctl;
+ dev->irq = pdev->irq;
+
+ priv = netdev_priv(dev);
+ priv->unit = unit;
+ priv->pdev = pdev;
+
+ spin_lock_init(&priv->ioctl_lock);
+ spin_lock_init(&priv->rx_lock);
+
+ priv->mii_if.full_duplex = 1;
+ priv->mii_if.phy_id_mask = 0x1f;
+ priv->mii_if.reg_num_mask = 0x1f;
+ priv->mii_if.dev = dev;
+ priv->mii_if.mdio_read = conet_mdio_read;
+ priv->mii_if.mdio_write = conet_mdio_write;
+ priv->mii_if.phy_id = 1;
+
+ pci_set_drvdata(pdev, priv);
+
+ rc = register_netdev(dev);
+ if (rc) {
+ printk(KERN_ERR "conet%d: could not register device; rc: %d\n", unit, rc);
+ goto error_out_dev;
+ }
+
+ conet_dev[unit] = dev;
+
+ printk(KERN_INFO "conet%d: irq %d, HWAddr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ unit, NETWORK_IRQ, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+ return 0;
+
+error_out_dev:
+ free_netdev(dev);
+
+error_out_pdev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ return rc;
+}
+
+static void __devexit conet_pci_remove(struct pci_dev *pdev)
+{
+ struct conet_priv *priv = dev_get_drvdata(&pdev->dev);
+ struct net_device *net_dev = conet_dev[priv->unit];
+
+ unregister_netdev(net_dev);
+ free_netdev(net_dev);
+ dev_set_drvdata(&pdev->dev, NULL);
+}
+
+static struct pci_driver conet_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = conet_pci_ids,
+ .probe = conet_pci_probe,
+ .remove = __devexit_p(conet_pci_remove),
+};
+
+static int __init conet_pci_init(void)
+{
+ int unit, rc;
+
+// printk(KERN_INFO "CONET: Initializing...\n");
+
+ rc = request_irq(NETWORK_IRQ, &conet_interrupt, IRQF_SAMPLE_RANDOM, "conet", NULL);
+ if (rc) {
+ printk(KERN_ERR "CONET: unable to get irq %d", NETWORK_IRQ);
+ return rc;
+ }
+
+ /* Init our units */
+ for (unit=0; unit < CO_MODULE_MAX_CONET; unit++)
+ conet_dev[unit] = NULL;
+
+// printk(KERN_INFO "CONET: registering...\n");
+ return pci_register_driver(&conet_pci_driver);
+}
+
+static void __exit conet_pci_exit(void)
+{
+ pci_unregister_driver(&conet_pci_driver);
+}
+
+module_init(conet_pci_init);
+module_exit(conet_pci_exit);