X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Fnet%2Fioc3-eth.c;h=1f25263dc7ebb8f90066d7388bbd297bd8d82b26;hb=d6a9e9b40be7da84f82eb414c2ad98c5bb69986b;hp=3ca1e8ece5485c43a99079175c1ab1aaab9db732;hpb=b4b613fd83853f8c688b3de20ab1a42331257975;p=linux-2.6-omap-h63xx.git diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 3ca1e8ece54..1f25263dc7e 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -5,7 +5,7 @@ * * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. * - * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle + * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. * * References: @@ -48,6 +48,7 @@ #ifdef CONFIG_SERIAL_8250 #include #include +#include #endif #include @@ -61,12 +62,7 @@ #include #include #include -#include -#include -#include -#include #include -#include #include /* @@ -94,6 +90,9 @@ struct ioc3_private { u32 emcr, ehar_h, ehar_l; spinlock_t ioc3_lock; struct mii_if_info mii; + unsigned long flags; +#define IOC3_FLAG_RX_CHECKSUMS 1 + struct pci_dev *pdev; /* Members used by autonegotiation */ @@ -444,18 +443,12 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip) */ static void ioc3_get_eaddr(struct ioc3_private *ip) { - int i; - + DECLARE_MAC_BUF(mac); ioc3_get_eaddr_nic(ip); - printk("Ethernet address is "); - for (i = 0; i < 6; i++) { - printk("%02x", priv_netdev(ip)->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk(".\n"); + printk("Ethernet address is %s.\n", + print_mac(mac, priv_netdev(ip)->dev_addr)); } static void __ioc3_set_mac_address(struct net_device *dev) @@ -520,8 +513,6 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev) return &ip->stats; } -#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM - static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) { struct ethhdr *eh = eth_hdr(skb); @@ -589,7 +580,6 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) if (csum == 0xffff) skb->ip_summed = CHECKSUM_UNNECESSARY; } -#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */ static inline void ioc3_rx(struct ioc3_private *ip) { @@ -624,9 +614,9 @@ static inline void ioc3_rx(struct ioc3_private *ip) goto next; } -#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM - ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len); -#endif + if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) + ioc3_tcpudp_checksum(skb, + w0 & ERXBUF_IPCKSUM_MASK, len); netif_rx(skb); @@ -1151,13 +1141,41 @@ static int ioc3_is_menet(struct pci_dev *pdev) * Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working * around ioc3 oddities in this respect. * - * The IOC3 serials use a 22MHz clock rate with an additional divider by 3. + * The IOC3 serials use a 22MHz clock rate with an additional divider which + * can be programmed in the SCR register if the DLAB bit is set. + * + * Register to interrupt zero because we share the interrupt with + * the serial driver which we don't properly support yet. + * + * Can't use UPF_IOREMAP as the whole of IOC3 resources have already been + * registered. */ +static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart) +{ +#define COSMISC_CONSTANT 6 + + struct uart_port port = { + .irq = 0, + .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 0, + .uartclk = (22000000 << 1) / COSMISC_CONSTANT, + + .membase = (unsigned char __iomem *) uart, + .mapbase = (unsigned long) uart, + }; + unsigned char lcr; + + lcr = uart->iu_lcr; + uart->iu_lcr = lcr | UART_LCR_DLAB; + uart->iu_scr = COSMISC_CONSTANT, + uart->iu_lcr = lcr; + uart->iu_lcr; + serial8250_register_port(&port); +} static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) { - struct uart_port port; - /* * We need to recognice and treat the fourth MENET serial as it * does not have an SuperIO chip attached to it, therefore attempting @@ -1171,28 +1189,40 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) return; /* - * Register to interrupt zero because we share the interrupt with - * the serial driver which we don't properly support yet. - * - * Can't use UPF_IOREMAP as the whole of IOC3 resources have already - * been registered. + * Switch IOC3 to PIO mode. It probably already was but let's be + * paranoid */ - memset(&port, 0, sizeof(port)); - port.irq = 0; - port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - port.iotype = UPIO_MEM; - port.regshift = 0; - port.uartclk = 22000000 / 3; - - port.membase = (unsigned char *) &ioc3->sregs.uarta; - serial8250_register_port(&port); - - port.membase = (unsigned char *) &ioc3->sregs.uartb; - serial8250_register_port(&port); + ioc3->gpcr_s = GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL; + ioc3->gpcr_s; + ioc3->gppr_6 = 0; + ioc3->gppr_6; + ioc3->gppr_7 = 0; + ioc3->gppr_7; + ioc3->sscr_a = ioc3->sscr_a & ~SSCR_DMA_EN; + ioc3->sscr_a; + ioc3->sscr_b = ioc3->sscr_b & ~SSCR_DMA_EN; + ioc3->sscr_b; + /* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */ + ioc3->sio_iec &= ~ (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL | + SIO_IR_SA_RX_HIGH | SIO_IR_SA_RX_TIMER | + SIO_IR_SA_DELTA_DCD | SIO_IR_SA_DELTA_CTS | + SIO_IR_SA_TX_EXPLICIT | SIO_IR_SA_MEMERR); + ioc3->sio_iec |= SIO_IR_SA_INT; + ioc3->sscr_a = 0; + ioc3->sio_iec &= ~ (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL | + SIO_IR_SB_RX_HIGH | SIO_IR_SB_RX_TIMER | + SIO_IR_SB_DELTA_DCD | SIO_IR_SB_DELTA_CTS | + SIO_IR_SB_TX_EXPLICIT | SIO_IR_SB_MEMERR); + ioc3->sio_iec |= SIO_IR_SB_INT; + ioc3->sscr_b = 0; + + ioc3_8250_register(&ioc3->sregs.uarta); + ioc3_8250_register(&ioc3->sregs.uartb); } #endif -static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit ioc3_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { unsigned int sw_physid1, sw_physid2; struct net_device *dev = NULL; @@ -1238,7 +1268,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); ip = netdev_priv(dev); @@ -1298,9 +1327,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->set_multicast_list = ioc3_set_multicast_list; dev->set_mac_address = ioc3_set_mac_address; dev->ethtool_ops = &ioc3_ethtool_ops; -#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM dev->features = NETIF_F_IP_CSUM; -#endif sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); @@ -1390,7 +1417,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) uint32_t w0 = 0; int produce; -#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM /* * IOC3 has a fairly simple minded checksumming hardware which simply * adds up the 1's complement checksum for the entire packet and @@ -1438,7 +1464,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); } -#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */ spin_lock_irq(&ip->ioc3_lock); @@ -1593,12 +1618,37 @@ static u32 ioc3_get_link(struct net_device *dev) return rc; } +static u32 ioc3_get_rx_csum(struct net_device *dev) +{ + struct ioc3_private *ip = netdev_priv(dev); + + return ip->flags & IOC3_FLAG_RX_CHECKSUMS; +} + +static int ioc3_set_rx_csum(struct net_device *dev, u32 data) +{ + struct ioc3_private *ip = netdev_priv(dev); + + spin_lock_bh(&ip->ioc3_lock); + if (data) + ip->flags |= IOC3_FLAG_RX_CHECKSUMS; + else + ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS; + spin_unlock_bh(&ip->ioc3_lock); + + return 0; +} + static const struct ethtool_ops ioc3_ethtool_ops = { .get_drvinfo = ioc3_get_drvinfo, .get_settings = ioc3_get_settings, .set_settings = ioc3_set_settings, .nway_reset = ioc3_nway_reset, .get_link = ioc3_get_link, + .get_rx_csum = ioc3_get_rx_csum, + .set_rx_csum = ioc3_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum }; static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)