|
@@ -1,5 +1,6 @@
|
|
|
/*
|
|
|
* Copyright (C) 2001,2002,2003,2004 Broadcom Corporation
|
|
|
+ * Copyright (c) 2006, 2007 Maciej W. Rozycki
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
* modify it under the terms of the GNU General Public License
|
|
@@ -18,7 +19,12 @@
|
|
|
*
|
|
|
* This driver is designed for the Broadcom SiByte SOC built-in
|
|
|
* Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp.
|
|
|
+ *
|
|
|
+ * Updated to the driver model and the PHY abstraction layer
|
|
|
+ * by Maciej W. Rozycki.
|
|
|
*/
|
|
|
+
|
|
|
+#include <linux/bug.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/string.h>
|
|
@@ -32,9 +38,15 @@
|
|
|
#include <linux/skbuff.h>
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/bitops.h>
|
|
|
-#include <asm/processor.h> /* Processor type for cache alignment. */
|
|
|
-#include <asm/io.h>
|
|
|
+#include <linux/err.h>
|
|
|
+#include <linux/ethtool.h>
|
|
|
+#include <linux/mii.h>
|
|
|
+#include <linux/phy.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
+
|
|
|
#include <asm/cache.h>
|
|
|
+#include <asm/io.h>
|
|
|
+#include <asm/processor.h> /* Processor type for cache alignment. */
|
|
|
|
|
|
/* This is only here until the firmware is ready. In that case,
|
|
|
the firmware leaves the ethernet address in the register for us. */
|
|
@@ -48,7 +60,7 @@
|
|
|
|
|
|
/* These identify the driver base version and may not be removed. */
|
|
|
#if 0
|
|
|
-static char version1[] __devinitdata =
|
|
|
+static char version1[] __initdata =
|
|
|
"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";
|
|
|
#endif
|
|
|
|
|
@@ -57,8 +69,6 @@ static char version1[] __devinitdata =
|
|
|
|
|
|
#define CONFIG_SBMAC_COALESCE
|
|
|
|
|
|
-#define MAX_UNITS 4 /* More are supported, limit only on options */
|
|
|
-
|
|
|
/* Time in jiffies before concluding the transmitter is hung. */
|
|
|
#define TX_TIMEOUT (2*HZ)
|
|
|
|
|
@@ -74,26 +84,6 @@ static int debug = 1;
|
|
|
module_param(debug, int, S_IRUGO);
|
|
|
MODULE_PARM_DESC(debug, "Debug messages");
|
|
|
|
|
|
-/* mii status msgs */
|
|
|
-static int noisy_mii = 1;
|
|
|
-module_param(noisy_mii, int, S_IRUGO);
|
|
|
-MODULE_PARM_DESC(noisy_mii, "MII status messages");
|
|
|
-
|
|
|
-/* Used to pass the media type, etc.
|
|
|
- Both 'options[]' and 'full_duplex[]' should exist for driver
|
|
|
- interoperability.
|
|
|
- The media type is usually passed in 'options[]'.
|
|
|
-*/
|
|
|
-#ifdef MODULE
|
|
|
-static int options[MAX_UNITS] = {-1, -1, -1, -1};
|
|
|
-module_param_array(options, int, NULL, S_IRUGO);
|
|
|
-MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS));
|
|
|
-
|
|
|
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1};
|
|
|
-module_param_array(full_duplex, int, NULL, S_IRUGO);
|
|
|
-MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
|
|
|
-#endif
|
|
|
-
|
|
|
#ifdef CONFIG_SBMAC_COALESCE
|
|
|
static int int_pktcnt_tx = 255;
|
|
|
module_param(int_pktcnt_tx, int, S_IRUGO);
|
|
@@ -112,6 +102,7 @@ module_param(int_timeout_rx, int, S_IRUGO);
|
|
|
MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
|
|
|
#endif
|
|
|
|
|
|
+#include <asm/sibyte/board.h>
|
|
|
#include <asm/sibyte/sb1250.h>
|
|
|
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
|
|
|
#include <asm/sibyte/bcm1480_regs.h>
|
|
@@ -135,22 +126,43 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
|
|
|
#error invalid SiByte MAC configuation
|
|
|
#endif
|
|
|
|
|
|
+#ifdef K_INT_PHY
|
|
|
+#define SBMAC_PHY_INT K_INT_PHY
|
|
|
+#else
|
|
|
+#define SBMAC_PHY_INT PHY_POLL
|
|
|
+#endif
|
|
|
+
|
|
|
/**********************************************************************
|
|
|
* Simple types
|
|
|
********************************************************************* */
|
|
|
|
|
|
+enum sbmac_speed {
|
|
|
+ sbmac_speed_none = 0,
|
|
|
+ sbmac_speed_10 = SPEED_10,
|
|
|
+ sbmac_speed_100 = SPEED_100,
|
|
|
+ sbmac_speed_1000 = SPEED_1000,
|
|
|
+};
|
|
|
|
|
|
-enum sbmac_speed { sbmac_speed_auto, sbmac_speed_10,
|
|
|
- sbmac_speed_100, sbmac_speed_1000 };
|
|
|
-
|
|
|
-enum sbmac_duplex { sbmac_duplex_auto, sbmac_duplex_half,
|
|
|
- sbmac_duplex_full };
|
|
|
+enum sbmac_duplex {
|
|
|
+ sbmac_duplex_none = -1,
|
|
|
+ sbmac_duplex_half = DUPLEX_HALF,
|
|
|
+ sbmac_duplex_full = DUPLEX_FULL,
|
|
|
+};
|
|
|
|
|
|
-enum sbmac_fc { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
|
|
|
- sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
|
|
|
+enum sbmac_fc {
|
|
|
+ sbmac_fc_none,
|
|
|
+ sbmac_fc_disabled,
|
|
|
+ sbmac_fc_frame,
|
|
|
+ sbmac_fc_collision,
|
|
|
+ sbmac_fc_carrier,
|
|
|
+};
|
|
|
|
|
|
-enum sbmac_state { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
|
|
|
- sbmac_state_broken };
|
|
|
+enum sbmac_state {
|
|
|
+ sbmac_state_uninit,
|
|
|
+ sbmac_state_off,
|
|
|
+ sbmac_state_on,
|
|
|
+ sbmac_state_broken,
|
|
|
+};
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
@@ -244,18 +256,14 @@ struct sbmac_softc {
|
|
|
*/
|
|
|
struct net_device *sbm_dev; /* pointer to linux device */
|
|
|
struct napi_struct napi;
|
|
|
+ struct phy_device *phy_dev; /* the associated PHY device */
|
|
|
+ struct mii_bus mii_bus; /* the MII bus */
|
|
|
+ int phy_irq[PHY_MAX_ADDR];
|
|
|
spinlock_t sbm_lock; /* spin lock */
|
|
|
- struct timer_list sbm_timer; /* for monitoring MII */
|
|
|
int sbm_devflags; /* current device flags */
|
|
|
|
|
|
- int sbm_phy_oldbmsr;
|
|
|
- int sbm_phy_oldanlpar;
|
|
|
- int sbm_phy_oldk1stsr;
|
|
|
- int sbm_phy_oldlinkstat;
|
|
|
int sbm_buffersize;
|
|
|
|
|
|
- unsigned char sbm_phys[2];
|
|
|
-
|
|
|
/*
|
|
|
* Controller-specific things
|
|
|
*/
|
|
@@ -274,6 +282,8 @@ struct sbmac_softc {
|
|
|
enum sbmac_speed sbm_speed; /* current speed */
|
|
|
enum sbmac_duplex sbm_duplex; /* current duplex */
|
|
|
enum sbmac_fc sbm_fc; /* cur. flow control setting */
|
|
|
+ int sbm_pause; /* current pause setting */
|
|
|
+ int sbm_link; /* current link state */
|
|
|
|
|
|
unsigned char sbm_hwaddr[ETHER_ADDR_LEN];
|
|
|
|
|
@@ -313,36 +323,37 @@ static uint64_t sbmac_addr2reg(unsigned char *ptr);
|
|
|
static irqreturn_t sbmac_intr(int irq, void *dev_instance);
|
|
|
static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
|
|
|
static void sbmac_setmulti(struct sbmac_softc *sc);
|
|
|
-static int sbmac_init(struct net_device *dev, int idx);
|
|
|
+static int sbmac_init(struct platform_device *pldev, long long base);
|
|
|
static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed);
|
|
|
static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
|
|
|
enum sbmac_fc fc);
|
|
|
|
|
|
static int sbmac_open(struct net_device *dev);
|
|
|
-static void sbmac_timer(unsigned long data);
|
|
|
static void sbmac_tx_timeout (struct net_device *dev);
|
|
|
static void sbmac_set_rx_mode(struct net_device *dev);
|
|
|
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
|
|
static int sbmac_close(struct net_device *dev);
|
|
|
static int sbmac_poll(struct napi_struct *napi, int budget);
|
|
|
|
|
|
-static int sbmac_mii_poll(struct sbmac_softc *s, int noisy);
|
|
|
+static void sbmac_mii_poll(struct net_device *dev);
|
|
|
static int sbmac_mii_probe(struct net_device *dev);
|
|
|
|
|
|
-static void sbmac_mii_sync(struct sbmac_softc *s);
|
|
|
-static void sbmac_mii_senddata(struct sbmac_softc *s, unsigned int data,
|
|
|
+static void sbmac_mii_sync(void __iomem *sbm_mdio);
|
|
|
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
|
|
|
int bitcnt);
|
|
|
-static unsigned int sbmac_mii_read(struct sbmac_softc *s, int phyaddr,
|
|
|
- int regidx);
|
|
|
-static void sbmac_mii_write(struct sbmac_softc *s, int phyaddr, int regidx,
|
|
|
- unsigned int regval);
|
|
|
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx);
|
|
|
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
|
|
|
+ u16 val);
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
* Globals
|
|
|
********************************************************************* */
|
|
|
|
|
|
-static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
|
|
|
+static char sbmac_string[] = "sb1250-mac";
|
|
|
+static char sbmac_pretty[] = "SB1250 MAC";
|
|
|
+
|
|
|
+static char sbmac_mdio_string[] = "sb1250-mac-mdio";
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
@@ -354,185 +365,66 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
|
|
|
#define MII_COMMAND_WRITE 0x01
|
|
|
#define MII_COMMAND_ACK 0x02
|
|
|
|
|
|
-#define BMCR_RESET 0x8000
|
|
|
-#define BMCR_LOOPBACK 0x4000
|
|
|
-#define BMCR_SPEED0 0x2000
|
|
|
-#define BMCR_ANENABLE 0x1000
|
|
|
-#define BMCR_POWERDOWN 0x0800
|
|
|
-#define BMCR_ISOLATE 0x0400
|
|
|
-#define BMCR_RESTARTAN 0x0200
|
|
|
-#define BMCR_DUPLEX 0x0100
|
|
|
-#define BMCR_COLTEST 0x0080
|
|
|
-#define BMCR_SPEED1 0x0040
|
|
|
-#define BMCR_SPEED1000 BMCR_SPEED1
|
|
|
-#define BMCR_SPEED100 BMCR_SPEED0
|
|
|
-#define BMCR_SPEED10 0
|
|
|
-
|
|
|
-#define BMSR_100BT4 0x8000
|
|
|
-#define BMSR_100BT_FDX 0x4000
|
|
|
-#define BMSR_100BT_HDX 0x2000
|
|
|
-#define BMSR_10BT_FDX 0x1000
|
|
|
-#define BMSR_10BT_HDX 0x0800
|
|
|
-#define BMSR_100BT2_FDX 0x0400
|
|
|
-#define BMSR_100BT2_HDX 0x0200
|
|
|
-#define BMSR_1000BT_XSR 0x0100
|
|
|
-#define BMSR_PRESUP 0x0040
|
|
|
-#define BMSR_ANCOMPLT 0x0020
|
|
|
-#define BMSR_REMFAULT 0x0010
|
|
|
-#define BMSR_AUTONEG 0x0008
|
|
|
-#define BMSR_LINKSTAT 0x0004
|
|
|
-#define BMSR_JABDETECT 0x0002
|
|
|
-#define BMSR_EXTCAPAB 0x0001
|
|
|
-
|
|
|
-#define PHYIDR1 0x2000
|
|
|
-#define PHYIDR2 0x5C60
|
|
|
-
|
|
|
-#define ANAR_NP 0x8000
|
|
|
-#define ANAR_RF 0x2000
|
|
|
-#define ANAR_ASYPAUSE 0x0800
|
|
|
-#define ANAR_PAUSE 0x0400
|
|
|
-#define ANAR_T4 0x0200
|
|
|
-#define ANAR_TXFD 0x0100
|
|
|
-#define ANAR_TXHD 0x0080
|
|
|
-#define ANAR_10FD 0x0040
|
|
|
-#define ANAR_10HD 0x0020
|
|
|
-#define ANAR_PSB 0x0001
|
|
|
-
|
|
|
-#define ANLPAR_NP 0x8000
|
|
|
-#define ANLPAR_ACK 0x4000
|
|
|
-#define ANLPAR_RF 0x2000
|
|
|
-#define ANLPAR_ASYPAUSE 0x0800
|
|
|
-#define ANLPAR_PAUSE 0x0400
|
|
|
-#define ANLPAR_T4 0x0200
|
|
|
-#define ANLPAR_TXFD 0x0100
|
|
|
-#define ANLPAR_TXHD 0x0080
|
|
|
-#define ANLPAR_10FD 0x0040
|
|
|
-#define ANLPAR_10HD 0x0020
|
|
|
-#define ANLPAR_PSB 0x0001 /* 802.3 */
|
|
|
-
|
|
|
-#define ANER_PDF 0x0010
|
|
|
-#define ANER_LPNPABLE 0x0008
|
|
|
-#define ANER_NPABLE 0x0004
|
|
|
-#define ANER_PAGERX 0x0002
|
|
|
-#define ANER_LPANABLE 0x0001
|
|
|
-
|
|
|
-#define ANNPTR_NP 0x8000
|
|
|
-#define ANNPTR_MP 0x2000
|
|
|
-#define ANNPTR_ACK2 0x1000
|
|
|
-#define ANNPTR_TOGTX 0x0800
|
|
|
-#define ANNPTR_CODE 0x0008
|
|
|
-
|
|
|
-#define ANNPRR_NP 0x8000
|
|
|
-#define ANNPRR_MP 0x2000
|
|
|
-#define ANNPRR_ACK3 0x1000
|
|
|
-#define ANNPRR_TOGTX 0x0800
|
|
|
-#define ANNPRR_CODE 0x0008
|
|
|
-
|
|
|
-#define K1TCR_TESTMODE 0x0000
|
|
|
-#define K1TCR_MSMCE 0x1000
|
|
|
-#define K1TCR_MSCV 0x0800
|
|
|
-#define K1TCR_RPTR 0x0400
|
|
|
-#define K1TCR_1000BT_FDX 0x200
|
|
|
-#define K1TCR_1000BT_HDX 0x100
|
|
|
-
|
|
|
-#define K1STSR_MSMCFLT 0x8000
|
|
|
-#define K1STSR_MSCFGRES 0x4000
|
|
|
-#define K1STSR_LRSTAT 0x2000
|
|
|
-#define K1STSR_RRSTAT 0x1000
|
|
|
-#define K1STSR_LP1KFD 0x0800
|
|
|
-#define K1STSR_LP1KHD 0x0400
|
|
|
-#define K1STSR_LPASMDIR 0x0200
|
|
|
-
|
|
|
-#define K1SCR_1KX_FDX 0x8000
|
|
|
-#define K1SCR_1KX_HDX 0x4000
|
|
|
-#define K1SCR_1KT_FDX 0x2000
|
|
|
-#define K1SCR_1KT_HDX 0x1000
|
|
|
-
|
|
|
-#define STRAP_PHY1 0x0800
|
|
|
-#define STRAP_NCMODE 0x0400
|
|
|
-#define STRAP_MANMSCFG 0x0200
|
|
|
-#define STRAP_ANENABLE 0x0100
|
|
|
-#define STRAP_MSVAL 0x0080
|
|
|
-#define STRAP_1KHDXADV 0x0010
|
|
|
-#define STRAP_1KFDXADV 0x0008
|
|
|
-#define STRAP_100ADV 0x0004
|
|
|
-#define STRAP_SPEEDSEL 0x0000
|
|
|
-#define STRAP_SPEED100 0x0001
|
|
|
-
|
|
|
-#define PHYSUP_SPEED1000 0x10
|
|
|
-#define PHYSUP_SPEED100 0x08
|
|
|
-#define PHYSUP_SPEED10 0x00
|
|
|
-#define PHYSUP_LINKUP 0x04
|
|
|
-#define PHYSUP_FDX 0x02
|
|
|
-
|
|
|
-#define MII_BMCR 0x00 /* Basic mode control register (rw) */
|
|
|
-#define MII_BMSR 0x01 /* Basic mode status register (ro) */
|
|
|
-#define MII_PHYIDR1 0x02
|
|
|
-#define MII_PHYIDR2 0x03
|
|
|
-
|
|
|
-#define MII_K1STSR 0x0A /* 1K Status Register (ro) */
|
|
|
-#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
|
|
|
-
|
|
|
-
|
|
|
#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */
|
|
|
|
|
|
#define ENABLE 1
|
|
|
#define DISABLE 0
|
|
|
|
|
|
/**********************************************************************
|
|
|
- * SBMAC_MII_SYNC(s)
|
|
|
+ * SBMAC_MII_SYNC(sbm_mdio)
|
|
|
*
|
|
|
* Synchronize with the MII - send a pattern of bits to the MII
|
|
|
* that will guarantee that it is ready to accept a command.
|
|
|
*
|
|
|
* Input parameters:
|
|
|
- * s - sbmac structure
|
|
|
+ * sbm_mdio - address of the MAC's MDIO register
|
|
|
*
|
|
|
* Return value:
|
|
|
* nothing
|
|
|
********************************************************************* */
|
|
|
|
|
|
-static void sbmac_mii_sync(struct sbmac_softc *s)
|
|
|
+static void sbmac_mii_sync(void __iomem *sbm_mdio)
|
|
|
{
|
|
|
int cnt;
|
|
|
uint64_t bits;
|
|
|
int mac_mdio_genc;
|
|
|
|
|
|
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
|
|
|
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
|
|
|
|
|
|
bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
|
|
|
|
|
|
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
|
|
|
|
|
|
for (cnt = 0; cnt < 32; cnt++) {
|
|
|
- __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
|
|
|
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
|
|
|
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
|
- * SBMAC_MII_SENDDATA(s,data,bitcnt)
|
|
|
+ * SBMAC_MII_SENDDATA(sbm_mdio, data, bitcnt)
|
|
|
*
|
|
|
* Send some bits to the MII. The bits to be sent are right-
|
|
|
* justified in the 'data' parameter.
|
|
|
*
|
|
|
* Input parameters:
|
|
|
- * s - sbmac structure
|
|
|
- * data - data to send
|
|
|
- * bitcnt - number of bits to send
|
|
|
+ * sbm_mdio - address of the MAC's MDIO register
|
|
|
+ * data - data to send
|
|
|
+ * bitcnt - number of bits to send
|
|
|
********************************************************************* */
|
|
|
|
|
|
-static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
|
|
|
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
|
|
|
+ int bitcnt)
|
|
|
{
|
|
|
int i;
|
|
|
uint64_t bits;
|
|
|
unsigned int curmask;
|
|
|
int mac_mdio_genc;
|
|
|
|
|
|
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
|
|
|
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
|
|
|
|
|
|
bits = M_MAC_MDIO_DIR_OUTPUT;
|
|
|
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
|
|
|
|
|
|
curmask = 1 << (bitcnt - 1);
|
|
|
|
|
@@ -540,9 +432,9 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
|
|
|
if (data & curmask)
|
|
|
bits |= M_MAC_MDIO_OUT;
|
|
|
else bits &= ~M_MAC_MDIO_OUT;
|
|
|
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
|
|
|
- __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
|
|
|
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
|
|
|
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
|
|
|
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
|
|
|
curmask >>= 1;
|
|
|
}
|
|
|
}
|
|
@@ -550,21 +442,22 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
- * SBMAC_MII_READ(s,phyaddr,regidx)
|
|
|
- *
|
|
|
+ * SBMAC_MII_READ(bus, phyaddr, regidx)
|
|
|
* Read a PHY register.
|
|
|
*
|
|
|
* Input parameters:
|
|
|
- * s - sbmac structure
|
|
|
+ * bus - MDIO bus handle
|
|
|
* phyaddr - PHY's address
|
|
|
- * regidx = index of register to read
|
|
|
+ * regnum - index of register to read
|
|
|
*
|
|
|
* Return value:
|
|
|
- * value read, or 0 if an error occurred.
|
|
|
+ * value read, or 0xffff if an error occurred.
|
|
|
********************************************************************* */
|
|
|
|
|
|
-static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
|
|
|
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
|
|
|
{
|
|
|
+ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
|
|
|
+ void __iomem *sbm_mdio = sc->sbm_mdio;
|
|
|
int idx;
|
|
|
int error;
|
|
|
int regval;
|
|
@@ -574,8 +467,7 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
|
|
|
* Synchronize ourselves so that the PHY knows the next
|
|
|
* thing coming down is a command
|
|
|
*/
|
|
|
-
|
|
|
- sbmac_mii_sync(s);
|
|
|
+ sbmac_mii_sync(sbm_mdio);
|
|
|
|
|
|
/*
|
|
|
* Send the data to the PHY. The sequence is
|
|
@@ -584,37 +476,37 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
|
|
|
* the PHY addr (5 bits)
|
|
|
* the register index (5 bits)
|
|
|
*/
|
|
|
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_READ, 2);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, regidx, 5);
|
|
|
|
|
|
- sbmac_mii_senddata(s,MII_COMMAND_START, 2);
|
|
|
- sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
|
|
|
- sbmac_mii_senddata(s,phyaddr, 5);
|
|
|
- sbmac_mii_senddata(s,regidx, 5);
|
|
|
-
|
|
|
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
|
|
|
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
|
|
|
|
|
|
/*
|
|
|
* Switch the port around without a clock transition.
|
|
|
*/
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
|
|
|
|
|
|
/*
|
|
|
* Send out a clock pulse to signal we want the status
|
|
|
*/
|
|
|
-
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
|
|
|
+ sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
|
|
|
|
|
|
/*
|
|
|
* If an error occurred, the PHY will signal '1' back
|
|
|
*/
|
|
|
- error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN;
|
|
|
+ error = __raw_readq(sbm_mdio) & M_MAC_MDIO_IN;
|
|
|
|
|
|
/*
|
|
|
* Issue an 'idle' clock pulse, but keep the direction
|
|
|
* the same.
|
|
|
*/
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
|
|
|
+ sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
|
|
|
|
|
|
regval = 0;
|
|
|
|
|
@@ -622,55 +514,60 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
|
|
|
regval <<= 1;
|
|
|
|
|
|
if (error == 0) {
|
|
|
- if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN)
|
|
|
+ if (__raw_readq(sbm_mdio) & M_MAC_MDIO_IN)
|
|
|
regval |= 1;
|
|
|
}
|
|
|
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
|
|
|
+ sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
|
|
|
}
|
|
|
|
|
|
/* Switch back to output */
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
|
|
|
|
|
|
if (error == 0)
|
|
|
return regval;
|
|
|
- return 0;
|
|
|
+ return 0xffff;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
- * SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
|
|
|
+ * SBMAC_MII_WRITE(bus, phyaddr, regidx, regval)
|
|
|
*
|
|
|
* Write a value to a PHY register.
|
|
|
*
|
|
|
* Input parameters:
|
|
|
- * s - sbmac structure
|
|
|
+ * bus - MDIO bus handle
|
|
|
* phyaddr - PHY to use
|
|
|
- * regidx - register within the PHY
|
|
|
- * regval - data to write to register
|
|
|
+ * regidx - register within the PHY
|
|
|
+ * regval - data to write to register
|
|
|
*
|
|
|
* Return value:
|
|
|
- * nothing
|
|
|
+ * 0 for success
|
|
|
********************************************************************* */
|
|
|
|
|
|
-static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
|
|
|
- unsigned int regval)
|
|
|
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
|
|
|
+ u16 regval)
|
|
|
{
|
|
|
+ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
|
|
|
+ void __iomem *sbm_mdio = sc->sbm_mdio;
|
|
|
int mac_mdio_genc;
|
|
|
|
|
|
- sbmac_mii_sync(s);
|
|
|
+ sbmac_mii_sync(sbm_mdio);
|
|
|
|
|
|
- sbmac_mii_senddata(s,MII_COMMAND_START,2);
|
|
|
- sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
|
|
|
- sbmac_mii_senddata(s,phyaddr, 5);
|
|
|
- sbmac_mii_senddata(s,regidx, 5);
|
|
|
- sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
|
|
|
- sbmac_mii_senddata(s,regval,16);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_WRITE, 2);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, regidx, 5);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_ACK, 2);
|
|
|
+ sbmac_mii_senddata(sbm_mdio, regval, 16);
|
|
|
|
|
|
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
|
|
|
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
|
|
|
|
|
|
- __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
|
|
|
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -713,27 +610,27 @@ static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
|
|
|
s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
|
|
|
#endif
|
|
|
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)));
|
|
|
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)));
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BYTES);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_COLLISIONS);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_LATE_COL);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_EX_COL);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_FCS_ERROR);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_ABORT);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BAD);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_GOOD);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_RUNT);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_OVERSIZE);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BYTES);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_MCAST);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BCAST);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BAD);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_GOOD);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_RUNT);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_OVERSIZE);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_FCS_ERROR);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_LENGTH_ERROR);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_CODE_ERROR);
|
|
|
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_ALIGN_ERROR);
|
|
|
|
|
|
/*
|
|
|
* initialize register pointers
|
|
@@ -953,7 +850,7 @@ static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb)
|
|
|
if (sb == NULL) {
|
|
|
sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN);
|
|
|
if (sb_new == NULL) {
|
|
|
- printk(KERN_INFO "%s: sk_buff allocation failed\n",
|
|
|
+ pr_info("%s: sk_buff allocation failed\n",
|
|
|
d->sbdma_eth->sbm_dev->name);
|
|
|
return -ENOBUFS;
|
|
|
}
|
|
@@ -1472,14 +1369,6 @@ static int sbmac_initctx(struct sbmac_softc *s)
|
|
|
s->sbm_imr = s->sbm_base + R_MAC_INT_MASK;
|
|
|
s->sbm_mdio = s->sbm_base + R_MAC_MDIO;
|
|
|
|
|
|
- s->sbm_phys[0] = 1;
|
|
|
- s->sbm_phys[1] = 0;
|
|
|
-
|
|
|
- s->sbm_phy_oldbmsr = 0;
|
|
|
- s->sbm_phy_oldanlpar = 0;
|
|
|
- s->sbm_phy_oldk1stsr = 0;
|
|
|
- s->sbm_phy_oldlinkstat = 0;
|
|
|
-
|
|
|
/*
|
|
|
* Initialize the DMA channels. Right now, only one per MAC is used
|
|
|
* Note: Only do this _once_, as it allocates memory from the kernel!
|
|
@@ -1494,14 +1383,6 @@ static int sbmac_initctx(struct sbmac_softc *s)
|
|
|
|
|
|
s->sbm_state = sbmac_state_off;
|
|
|
|
|
|
- /*
|
|
|
- * Initial speed is (XXX TEMP) 10MBit/s HDX no FC
|
|
|
- */
|
|
|
-
|
|
|
- s->sbm_speed = sbmac_speed_10;
|
|
|
- s->sbm_duplex = sbmac_duplex_half;
|
|
|
- s->sbm_fc = sbmac_fc_disabled;
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2008,8 +1889,6 @@ static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed)
|
|
|
cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
|
|
|
break;
|
|
|
|
|
|
- case sbmac_speed_auto: /* XXX not implemented */
|
|
|
- /* fall through */
|
|
|
default:
|
|
|
return 0;
|
|
|
}
|
|
@@ -2083,8 +1962,6 @@ static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
|
|
|
cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
|
|
|
break;
|
|
|
|
|
|
- case sbmac_fc_auto: /* XXX not implemented */
|
|
|
- /* fall through */
|
|
|
case sbmac_fc_frame: /* not valid in half duplex */
|
|
|
default: /* invalid selection */
|
|
|
return 0;
|
|
@@ -2103,15 +1980,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
|
|
|
|
|
|
case sbmac_fc_collision: /* not valid in full duplex */
|
|
|
case sbmac_fc_carrier: /* not valid in full duplex */
|
|
|
- case sbmac_fc_auto: /* XXX not implemented */
|
|
|
- /* fall through */
|
|
|
default:
|
|
|
return 0;
|
|
|
}
|
|
|
break;
|
|
|
- case sbmac_duplex_auto:
|
|
|
- /* XXX not implemented */
|
|
|
- break;
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2390,7 +2264,7 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
|
|
|
if (new_mtu > ENET_PACKET_SIZE)
|
|
|
return -EINVAL;
|
|
|
_dev->mtu = new_mtu;
|
|
|
- printk(KERN_INFO "changing the mtu to %d\n", new_mtu);
|
|
|
+ pr_info("changing the mtu to %d\n", new_mtu);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2406,20 +2280,17 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
|
|
|
* status
|
|
|
********************************************************************* */
|
|
|
|
|
|
-static int sbmac_init(struct net_device *dev, int idx)
|
|
|
+static int sbmac_init(struct platform_device *pldev, long long base)
|
|
|
{
|
|
|
- struct sbmac_softc *sc;
|
|
|
+ struct net_device *dev = pldev->dev.driver_data;
|
|
|
+ int idx = pldev->id;
|
|
|
+ struct sbmac_softc *sc = netdev_priv(dev);
|
|
|
unsigned char *eaddr;
|
|
|
uint64_t ea_reg;
|
|
|
int i;
|
|
|
int err;
|
|
|
DECLARE_MAC_BUF(mac);
|
|
|
|
|
|
- sc = netdev_priv(dev);
|
|
|
-
|
|
|
- /* Determine controller base address */
|
|
|
-
|
|
|
- sc->sbm_base = IOADDR(dev->base_addr);
|
|
|
sc->sbm_dev = dev;
|
|
|
sc->sbe_idx = idx;
|
|
|
|
|
@@ -2476,43 +2347,55 @@ static int sbmac_init(struct net_device *dev, int idx)
|
|
|
dev->poll_controller = sbmac_netpoll;
|
|
|
#endif
|
|
|
|
|
|
+ dev->irq = UNIT_INT(idx);
|
|
|
+
|
|
|
/* This is needed for PASS2 for Rx H/W checksum feature */
|
|
|
sbmac_set_iphdr_offset(sc);
|
|
|
|
|
|
err = register_netdev(dev);
|
|
|
- if (err)
|
|
|
- goto out_uninit;
|
|
|
-
|
|
|
- if (sc->rx_hw_checksum == ENABLE) {
|
|
|
- printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
|
|
|
- sc->sbm_dev->name);
|
|
|
+ if (err) {
|
|
|
+ printk(KERN_ERR "%s.%d: unable to register netdev\n",
|
|
|
+ sbmac_string, idx);
|
|
|
+ sbmac_uninitctx(sc);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
+ pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name);
|
|
|
+
|
|
|
+ if (sc->rx_hw_checksum == ENABLE)
|
|
|
+ pr_info("%s: enabling TCP rcv checksum\n", dev->name);
|
|
|
+
|
|
|
/*
|
|
|
* Display Ethernet address (this is called during the config
|
|
|
* process so we need to finish off the config message that
|
|
|
* was being displayed)
|
|
|
*/
|
|
|
- printk(KERN_INFO
|
|
|
- "%s: SiByte Ethernet at 0x%08lX, address: %s\n",
|
|
|
- dev->name, dev->base_addr, print_mac(mac, eaddr));
|
|
|
+ pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n",
|
|
|
+ dev->name, base, print_mac(mac, eaddr));
|
|
|
|
|
|
- return 0;
|
|
|
+ sc->mii_bus.name = sbmac_mdio_string;
|
|
|
+ sc->mii_bus.id = idx;
|
|
|
+ sc->mii_bus.priv = sc;
|
|
|
+ sc->mii_bus.read = sbmac_mii_read;
|
|
|
+ sc->mii_bus.write = sbmac_mii_write;
|
|
|
+ sc->mii_bus.irq = sc->phy_irq;
|
|
|
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
|
|
|
+ sc->mii_bus.irq[i] = SBMAC_PHY_INT;
|
|
|
|
|
|
-out_uninit:
|
|
|
- sbmac_uninitctx(sc);
|
|
|
+ sc->mii_bus.dev = &pldev->dev;
|
|
|
+ dev_set_drvdata(&pldev->dev, &sc->mii_bus);
|
|
|
|
|
|
- return err;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
static int sbmac_open(struct net_device *dev)
|
|
|
{
|
|
|
struct sbmac_softc *sc = netdev_priv(dev);
|
|
|
+ int err;
|
|
|
|
|
|
- if (debug > 1) {
|
|
|
- printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
|
|
|
- }
|
|
|
+ if (debug > 1)
|
|
|
+ pr_debug("%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
|
|
|
|
|
|
/*
|
|
|
* map/route interrupt (clear status first, in case something
|
|
@@ -2521,25 +2404,35 @@ static int sbmac_open(struct net_device *dev)
|
|
|
*/
|
|
|
|
|
|
__raw_readq(sc->sbm_isr);
|
|
|
- if (request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev))
|
|
|
- return -EBUSY;
|
|
|
+ err = request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev);
|
|
|
+ if (err) {
|
|
|
+ printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name,
|
|
|
+ dev->irq);
|
|
|
+ goto out_err;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
- * Probe phy address
|
|
|
+ * Probe PHY address
|
|
|
*/
|
|
|
-
|
|
|
- if(sbmac_mii_probe(dev) == -1) {
|
|
|
- printk("%s: failed to probe PHY.\n", dev->name);
|
|
|
- return -EINVAL;
|
|
|
+ err = mdiobus_register(&sc->mii_bus);
|
|
|
+ if (err) {
|
|
|
+ printk(KERN_ERR "%s: unable to register MDIO bus\n",
|
|
|
+ dev->name);
|
|
|
+ goto out_unirq;
|
|
|
}
|
|
|
|
|
|
- napi_enable(&sc->napi);
|
|
|
+ sc->sbm_speed = sbmac_speed_none;
|
|
|
+ sc->sbm_duplex = sbmac_duplex_none;
|
|
|
+ sc->sbm_fc = sbmac_fc_none;
|
|
|
+ sc->sbm_pause = -1;
|
|
|
+ sc->sbm_link = 0;
|
|
|
|
|
|
/*
|
|
|
- * Configure default speed
|
|
|
+ * Attach to the PHY
|
|
|
*/
|
|
|
-
|
|
|
- sbmac_mii_poll(sc,noisy_mii);
|
|
|
+ err = sbmac_mii_probe(dev);
|
|
|
+ if (err)
|
|
|
+ goto out_unregister;
|
|
|
|
|
|
/*
|
|
|
* Turn on the channel
|
|
@@ -2547,200 +2440,133 @@ static int sbmac_open(struct net_device *dev)
|
|
|
|
|
|
sbmac_set_channel_state(sc,sbmac_state_on);
|
|
|
|
|
|
- /*
|
|
|
- * XXX Station address is in dev->dev_addr
|
|
|
- */
|
|
|
-
|
|
|
- if (dev->if_port == 0)
|
|
|
- dev->if_port = 0;
|
|
|
-
|
|
|
netif_start_queue(dev);
|
|
|
|
|
|
sbmac_set_rx_mode(dev);
|
|
|
|
|
|
- /* Set the timer to check for link beat. */
|
|
|
- init_timer(&sc->sbm_timer);
|
|
|
- sc->sbm_timer.expires = jiffies + 2 * HZ/100;
|
|
|
- sc->sbm_timer.data = (unsigned long)dev;
|
|
|
- sc->sbm_timer.function = &sbmac_timer;
|
|
|
- add_timer(&sc->sbm_timer);
|
|
|
+ phy_start(sc->phy_dev);
|
|
|
+
|
|
|
+ napi_enable(&sc->napi);
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+out_unregister:
|
|
|
+ mdiobus_unregister(&sc->mii_bus);
|
|
|
+
|
|
|
+out_unirq:
|
|
|
+ free_irq(dev->irq, dev);
|
|
|
+
|
|
|
+out_err:
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
static int sbmac_mii_probe(struct net_device *dev)
|
|
|
{
|
|
|
+ struct sbmac_softc *sc = netdev_priv(dev);
|
|
|
+ struct phy_device *phy_dev;
|
|
|
int i;
|
|
|
- struct sbmac_softc *s = netdev_priv(dev);
|
|
|
- u16 bmsr, id1, id2;
|
|
|
- u32 vendor, device;
|
|
|
-
|
|
|
- for (i=1; i<31; i++) {
|
|
|
- bmsr = sbmac_mii_read(s, i, MII_BMSR);
|
|
|
- if (bmsr != 0) {
|
|
|
- s->sbm_phys[0] = i;
|
|
|
- id1 = sbmac_mii_read(s, i, MII_PHYIDR1);
|
|
|
- id2 = sbmac_mii_read(s, i, MII_PHYIDR2);
|
|
|
- vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f);
|
|
|
- device = (id2 >> 4) & 0x3f;
|
|
|
-
|
|
|
- printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n",
|
|
|
- dev->name, i, vendor, device);
|
|
|
- return i;
|
|
|
- }
|
|
|
- }
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
|
|
|
-{
|
|
|
- int bmsr,bmcr,k1stsr,anlpar;
|
|
|
- int chg;
|
|
|
- char buffer[100];
|
|
|
- char *p = buffer;
|
|
|
-
|
|
|
- /* Read the mode status and mode control registers. */
|
|
|
- bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
|
|
|
- bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
|
|
|
-
|
|
|
- /* get the link partner status */
|
|
|
- anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
|
|
|
|
|
|
- /* if supported, read the 1000baseT register */
|
|
|
- if (bmsr & BMSR_1000BT_XSR) {
|
|
|
- k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
|
|
|
- }
|
|
|
- else {
|
|
|
- k1stsr = 0;
|
|
|
- }
|
|
|
-
|
|
|
- chg = 0;
|
|
|
-
|
|
|
- if ((bmsr & BMSR_LINKSTAT) == 0) {
|
|
|
- /*
|
|
|
- * If link status is down, clear out old info so that when
|
|
|
- * it comes back up it will force us to reconfigure speed
|
|
|
- */
|
|
|
- s->sbm_phy_oldbmsr = 0;
|
|
|
- s->sbm_phy_oldanlpar = 0;
|
|
|
- s->sbm_phy_oldk1stsr = 0;
|
|
|
- return 0;
|
|
|
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
|
|
|
+ phy_dev = sc->mii_bus.phy_map[i];
|
|
|
+ if (phy_dev)
|
|
|
+ break;
|
|
|
}
|
|
|
-
|
|
|
- if ((s->sbm_phy_oldbmsr != bmsr) ||
|
|
|
- (s->sbm_phy_oldanlpar != anlpar) ||
|
|
|
- (s->sbm_phy_oldk1stsr != k1stsr)) {
|
|
|
- if (debug > 1) {
|
|
|
- printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n",
|
|
|
- s->sbm_dev->name,
|
|
|
- s->sbm_phy_oldbmsr,bmsr,
|
|
|
- s->sbm_phy_oldanlpar,anlpar,
|
|
|
- s->sbm_phy_oldk1stsr,k1stsr);
|
|
|
- }
|
|
|
- s->sbm_phy_oldbmsr = bmsr;
|
|
|
- s->sbm_phy_oldanlpar = anlpar;
|
|
|
- s->sbm_phy_oldk1stsr = k1stsr;
|
|
|
- chg = 1;
|
|
|
+ if (!phy_dev) {
|
|
|
+ printk(KERN_ERR "%s: no PHY found\n", dev->name);
|
|
|
+ return -ENXIO;
|
|
|
}
|
|
|
|
|
|
- if (chg == 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- p += sprintf(p,"Link speed: ");
|
|
|
-
|
|
|
- if (k1stsr & K1STSR_LP1KFD) {
|
|
|
- s->sbm_speed = sbmac_speed_1000;
|
|
|
- s->sbm_duplex = sbmac_duplex_full;
|
|
|
- s->sbm_fc = sbmac_fc_frame;
|
|
|
- p += sprintf(p,"1000BaseT FDX");
|
|
|
- }
|
|
|
- else if (k1stsr & K1STSR_LP1KHD) {
|
|
|
- s->sbm_speed = sbmac_speed_1000;
|
|
|
- s->sbm_duplex = sbmac_duplex_half;
|
|
|
- s->sbm_fc = sbmac_fc_disabled;
|
|
|
- p += sprintf(p,"1000BaseT HDX");
|
|
|
- }
|
|
|
- else if (anlpar & ANLPAR_TXFD) {
|
|
|
- s->sbm_speed = sbmac_speed_100;
|
|
|
- s->sbm_duplex = sbmac_duplex_full;
|
|
|
- s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
|
|
|
- p += sprintf(p,"100BaseT FDX");
|
|
|
- }
|
|
|
- else if (anlpar & ANLPAR_TXHD) {
|
|
|
- s->sbm_speed = sbmac_speed_100;
|
|
|
- s->sbm_duplex = sbmac_duplex_half;
|
|
|
- s->sbm_fc = sbmac_fc_disabled;
|
|
|
- p += sprintf(p,"100BaseT HDX");
|
|
|
- }
|
|
|
- else if (anlpar & ANLPAR_10FD) {
|
|
|
- s->sbm_speed = sbmac_speed_10;
|
|
|
- s->sbm_duplex = sbmac_duplex_full;
|
|
|
- s->sbm_fc = sbmac_fc_frame;
|
|
|
- p += sprintf(p,"10BaseT FDX");
|
|
|
- }
|
|
|
- else if (anlpar & ANLPAR_10HD) {
|
|
|
- s->sbm_speed = sbmac_speed_10;
|
|
|
- s->sbm_duplex = sbmac_duplex_half;
|
|
|
- s->sbm_fc = sbmac_fc_collision;
|
|
|
- p += sprintf(p,"10BaseT HDX");
|
|
|
- }
|
|
|
- else {
|
|
|
- p += sprintf(p,"Unknown");
|
|
|
+ phy_dev = phy_connect(dev, phy_dev->dev.bus_id, &sbmac_mii_poll, 0,
|
|
|
+ PHY_INTERFACE_MODE_GMII);
|
|
|
+ if (IS_ERR(phy_dev)) {
|
|
|
+ printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
|
|
|
+ return PTR_ERR(phy_dev);
|
|
|
}
|
|
|
|
|
|
- if (noisy) {
|
|
|
- printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
|
|
|
- }
|
|
|
+ /* Remove any features not supported by the controller */
|
|
|
+ phy_dev->supported &= SUPPORTED_10baseT_Half |
|
|
|
+ SUPPORTED_10baseT_Full |
|
|
|
+ SUPPORTED_100baseT_Half |
|
|
|
+ SUPPORTED_100baseT_Full |
|
|
|
+ SUPPORTED_1000baseT_Half |
|
|
|
+ SUPPORTED_1000baseT_Full |
|
|
|
+ SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_MII |
|
|
|
+ SUPPORTED_Pause |
|
|
|
+ SUPPORTED_Asym_Pause;
|
|
|
+ phy_dev->advertising = phy_dev->supported;
|
|
|
+
|
|
|
+ pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
|
|
|
+ dev->name, phy_dev->drv->name,
|
|
|
+ phy_dev->dev.bus_id, phy_dev->irq);
|
|
|
+
|
|
|
+ sc->phy_dev = phy_dev;
|
|
|
|
|
|
- return 1;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void sbmac_timer(unsigned long data)
|
|
|
+static void sbmac_mii_poll(struct net_device *dev)
|
|
|
{
|
|
|
- struct net_device *dev = (struct net_device *)data;
|
|
|
struct sbmac_softc *sc = netdev_priv(dev);
|
|
|
- int next_tick = HZ;
|
|
|
- int mii_status;
|
|
|
+ struct phy_device *phy_dev = sc->phy_dev;
|
|
|
+ unsigned long flags;
|
|
|
+ enum sbmac_fc fc;
|
|
|
+ int link_chg, speed_chg, duplex_chg, pause_chg, fc_chg;
|
|
|
+
|
|
|
+ link_chg = (sc->sbm_link != phy_dev->link);
|
|
|
+ speed_chg = (sc->sbm_speed != phy_dev->speed);
|
|
|
+ duplex_chg = (sc->sbm_duplex != phy_dev->duplex);
|
|
|
+ pause_chg = (sc->sbm_pause != phy_dev->pause);
|
|
|
+
|
|
|
+ if (!link_chg && !speed_chg && !duplex_chg && !pause_chg)
|
|
|
+ return; /* Hmmm... */
|
|
|
+
|
|
|
+ if (!phy_dev->link) {
|
|
|
+ if (link_chg) {
|
|
|
+ sc->sbm_link = phy_dev->link;
|
|
|
+ sc->sbm_speed = sbmac_speed_none;
|
|
|
+ sc->sbm_duplex = sbmac_duplex_none;
|
|
|
+ sc->sbm_fc = sbmac_fc_disabled;
|
|
|
+ sc->sbm_pause = -1;
|
|
|
+ pr_info("%s: link unavailable\n", dev->name);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- spin_lock_irq (&sc->sbm_lock);
|
|
|
+ if (phy_dev->duplex == DUPLEX_FULL) {
|
|
|
+ if (phy_dev->pause)
|
|
|
+ fc = sbmac_fc_frame;
|
|
|
+ else
|
|
|
+ fc = sbmac_fc_disabled;
|
|
|
+ } else
|
|
|
+ fc = sbmac_fc_collision;
|
|
|
+ fc_chg = (sc->sbm_fc != fc);
|
|
|
|
|
|
- /* make IFF_RUNNING follow the MII status bit "Link established" */
|
|
|
- mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
|
|
|
+ pr_info("%s: link available: %dbase-%cD\n", dev->name, phy_dev->speed,
|
|
|
+ phy_dev->duplex == DUPLEX_FULL ? 'F' : 'H');
|
|
|
|
|
|
- if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
|
|
|
- sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
|
|
|
- if (mii_status & BMSR_LINKSTAT) {
|
|
|
- netif_carrier_on(dev);
|
|
|
- }
|
|
|
- else {
|
|
|
- netif_carrier_off(dev);
|
|
|
- }
|
|
|
- }
|
|
|
+ spin_lock_irqsave(&sc->sbm_lock, flags);
|
|
|
|
|
|
- /*
|
|
|
- * Poll the PHY to see what speed we should be running at
|
|
|
- */
|
|
|
+ sc->sbm_speed = phy_dev->speed;
|
|
|
+ sc->sbm_duplex = phy_dev->duplex;
|
|
|
+ sc->sbm_fc = fc;
|
|
|
+ sc->sbm_pause = phy_dev->pause;
|
|
|
+ sc->sbm_link = phy_dev->link;
|
|
|
|
|
|
- if (sbmac_mii_poll(sc,noisy_mii)) {
|
|
|
- if (sc->sbm_state != sbmac_state_off) {
|
|
|
- /*
|
|
|
- * something changed, restart the channel
|
|
|
- */
|
|
|
- if (debug > 1) {
|
|
|
- printk("%s: restarting channel because speed changed\n",
|
|
|
- sc->sbm_dev->name);
|
|
|
- }
|
|
|
- sbmac_channel_stop(sc);
|
|
|
- sbmac_channel_start(sc);
|
|
|
- }
|
|
|
+ if ((speed_chg || duplex_chg || fc_chg) &&
|
|
|
+ sc->sbm_state != sbmac_state_off) {
|
|
|
+ /*
|
|
|
+ * something changed, restart the channel
|
|
|
+ */
|
|
|
+ if (debug > 1)
|
|
|
+ pr_debug("%s: restarting channel "
|
|
|
+ "because PHY state changed\n", dev->name);
|
|
|
+ sbmac_channel_stop(sc);
|
|
|
+ sbmac_channel_start(sc);
|
|
|
}
|
|
|
|
|
|
- spin_unlock_irq (&sc->sbm_lock);
|
|
|
-
|
|
|
- sc->sbm_timer.expires = jiffies + next_tick;
|
|
|
- add_timer(&sc->sbm_timer);
|
|
|
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2793,64 +2619,34 @@ static void sbmac_set_rx_mode(struct net_device *dev)
|
|
|
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
|
{
|
|
|
struct sbmac_softc *sc = netdev_priv(dev);
|
|
|
- u16 *data = (u16 *)&rq->ifr_ifru;
|
|
|
- unsigned long flags;
|
|
|
- int retval;
|
|
|
|
|
|
- spin_lock_irqsave(&sc->sbm_lock, flags);
|
|
|
- retval = 0;
|
|
|
-
|
|
|
- switch(cmd) {
|
|
|
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
|
|
|
- data[0] = sc->sbm_phys[0] & 0x1f;
|
|
|
- /* Fall Through */
|
|
|
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
|
|
|
- data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f);
|
|
|
- break;
|
|
|
- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
|
|
|
- if (!capable(CAP_NET_ADMIN)) {
|
|
|
- retval = -EPERM;
|
|
|
- break;
|
|
|
- }
|
|
|
- if (debug > 1) {
|
|
|
- printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name,
|
|
|
- data[0],data[1],data[2]);
|
|
|
- }
|
|
|
- sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]);
|
|
|
- break;
|
|
|
- default:
|
|
|
- retval = -EOPNOTSUPP;
|
|
|
- }
|
|
|
+ if (!netif_running(dev) || !sc->phy_dev)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
|
|
|
- return retval;
|
|
|
+ return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd);
|
|
|
}
|
|
|
|
|
|
static int sbmac_close(struct net_device *dev)
|
|
|
{
|
|
|
struct sbmac_softc *sc = netdev_priv(dev);
|
|
|
- unsigned long flags;
|
|
|
- int irq;
|
|
|
|
|
|
napi_disable(&sc->napi);
|
|
|
|
|
|
- sbmac_set_channel_state(sc,sbmac_state_off);
|
|
|
-
|
|
|
- del_timer_sync(&sc->sbm_timer);
|
|
|
+ phy_stop(sc->phy_dev);
|
|
|
|
|
|
- spin_lock_irqsave(&sc->sbm_lock, flags);
|
|
|
+ sbmac_set_channel_state(sc, sbmac_state_off);
|
|
|
|
|
|
netif_stop_queue(dev);
|
|
|
|
|
|
- if (debug > 1) {
|
|
|
- printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
|
|
|
- }
|
|
|
+ if (debug > 1)
|
|
|
+ pr_debug("%s: Shutting down ethercard\n", dev->name);
|
|
|
|
|
|
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
|
|
|
+ phy_disconnect(sc->phy_dev);
|
|
|
+ sc->phy_dev = NULL;
|
|
|
+
|
|
|
+ mdiobus_unregister(&sc->mii_bus);
|
|
|
|
|
|
- irq = dev->irq;
|
|
|
- synchronize_irq(irq);
|
|
|
- free_irq(irq, dev);
|
|
|
+ free_irq(dev->irq, dev);
|
|
|
|
|
|
sbdma_emptyring(&(sc->sbm_txdma));
|
|
|
sbdma_emptyring(&(sc->sbm_rxdma));
|
|
@@ -2883,54 +2679,195 @@ static int sbmac_poll(struct napi_struct *napi, int budget)
|
|
|
return work_done;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static int __init sbmac_probe(struct platform_device *pldev)
|
|
|
+{
|
|
|
+ struct net_device *dev;
|
|
|
+ struct sbmac_softc *sc;
|
|
|
+ void __iomem *sbm_base;
|
|
|
+ struct resource *res;
|
|
|
+ u64 sbmac_orig_hwaddr;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
|
|
|
+ BUG_ON(!res);
|
|
|
+ sbm_base = ioremap_nocache(res->start, res->end - res->start + 1);
|
|
|
+ if (!sbm_base) {
|
|
|
+ printk(KERN_ERR "%s: unable to map device registers\n",
|
|
|
+ pldev->dev.bus_id);
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto out_out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
|
|
|
+ * value for us by the firmware if we're going to use this MAC.
|
|
|
+ * If we find a zero, skip this MAC.
|
|
|
+ */
|
|
|
+ sbmac_orig_hwaddr = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
|
|
|
+ pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", pldev->dev.bus_id,
|
|
|
+ sbmac_orig_hwaddr ? "" : "not ", (long long)res->start);
|
|
|
+ if (sbmac_orig_hwaddr == 0) {
|
|
|
+ err = 0;
|
|
|
+ goto out_unmap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Okay, cool. Initialize this MAC.
|
|
|
+ */
|
|
|
+ dev = alloc_etherdev(sizeof(struct sbmac_softc));
|
|
|
+ if (!dev) {
|
|
|
+ printk(KERN_ERR "%s: unable to allocate etherdev\n",
|
|
|
+ pldev->dev.bus_id);
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto out_unmap;
|
|
|
+ }
|
|
|
+
|
|
|
+ pldev->dev.driver_data = dev;
|
|
|
+ SET_NETDEV_DEV(dev, &pldev->dev);
|
|
|
+
|
|
|
+ sc = netdev_priv(dev);
|
|
|
+ sc->sbm_base = sbm_base;
|
|
|
+
|
|
|
+ err = sbmac_init(pldev, res->start);
|
|
|
+ if (err)
|
|
|
+ goto out_kfree;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_kfree:
|
|
|
+ free_netdev(dev);
|
|
|
+ __raw_writeq(sbmac_orig_hwaddr, sbm_base + R_MAC_ETHERNET_ADDR);
|
|
|
+
|
|
|
+out_unmap:
|
|
|
+ iounmap(sbm_base);
|
|
|
+
|
|
|
+out_out:
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int __exit sbmac_remove(struct platform_device *pldev)
|
|
|
+{
|
|
|
+ struct net_device *dev = pldev->dev.driver_data;
|
|
|
+ struct sbmac_softc *sc = netdev_priv(dev);
|
|
|
+
|
|
|
+ unregister_netdev(dev);
|
|
|
+ sbmac_uninitctx(sc);
|
|
|
+ iounmap(sc->sbm_base);
|
|
|
+ free_netdev(dev);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static struct platform_device **sbmac_pldev;
|
|
|
+static int sbmac_max_units;
|
|
|
+
|
|
|
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
|
|
|
-static void
|
|
|
-sbmac_setup_hwaddr(int chan,char *addr)
|
|
|
+static void __init sbmac_setup_hwaddr(int idx, char *addr)
|
|
|
{
|
|
|
+ void __iomem *sbm_base;
|
|
|
+ unsigned long start, end;
|
|
|
uint8_t eaddr[6];
|
|
|
uint64_t val;
|
|
|
- unsigned long port;
|
|
|
|
|
|
- port = A_MAC_CHANNEL_BASE(chan);
|
|
|
- sbmac_parse_hwaddr(addr,eaddr);
|
|
|
+ if (idx >= sbmac_max_units)
|
|
|
+ return;
|
|
|
+
|
|
|
+ start = A_MAC_CHANNEL_BASE(idx);
|
|
|
+ end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
|
|
|
+
|
|
|
+ sbm_base = ioremap_nocache(start, end - start + 1);
|
|
|
+ if (!sbm_base) {
|
|
|
+ printk(KERN_ERR "%s: unable to map device registers\n",
|
|
|
+ sbmac_string);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ sbmac_parse_hwaddr(addr, eaddr);
|
|
|
val = sbmac_addr2reg(eaddr);
|
|
|
- __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR));
|
|
|
- val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
|
|
|
+ __raw_writeq(val, sbm_base + R_MAC_ETHERNET_ADDR);
|
|
|
+ val = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
|
|
|
+
|
|
|
+ iounmap(sbm_base);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static struct net_device *dev_sbmac[MAX_UNITS];
|
|
|
+static int __init sbmac_platform_probe_one(int idx)
|
|
|
+{
|
|
|
+ struct platform_device *pldev;
|
|
|
+ struct {
|
|
|
+ struct resource r;
|
|
|
+ char name[strlen(sbmac_pretty) + 4];
|
|
|
+ } *res;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
|
|
|
+ if (!res) {
|
|
|
+ printk(KERN_ERR "%s.%d: unable to allocate memory\n",
|
|
|
+ sbmac_string, idx);
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto out_err;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This is the base address of the MAC.
|
|
|
+ */
|
|
|
+ snprintf(res->name, sizeof(res->name), "%s %d", sbmac_pretty, idx);
|
|
|
+ res->r.name = res->name;
|
|
|
+ res->r.flags = IORESOURCE_MEM;
|
|
|
+ res->r.start = A_MAC_CHANNEL_BASE(idx);
|
|
|
+ res->r.end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
|
|
|
+
|
|
|
+ pldev = platform_device_register_simple(sbmac_string, idx, &res->r, 1);
|
|
|
+ if (IS_ERR(pldev)) {
|
|
|
+ printk(KERN_ERR "%s.%d: unable to register platform device\n",
|
|
|
+ sbmac_string, idx);
|
|
|
+ err = PTR_ERR(pldev);
|
|
|
+ goto out_kfree;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!pldev->dev.driver) {
|
|
|
+ err = 0; /* No hardware at this address. */
|
|
|
+ goto out_unregister;
|
|
|
+ }
|
|
|
+
|
|
|
+ sbmac_pldev[idx] = pldev;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_unregister:
|
|
|
+ platform_device_unregister(pldev);
|
|
|
|
|
|
-static int __init
|
|
|
-sbmac_init_module(void)
|
|
|
+out_kfree:
|
|
|
+ kfree(res);
|
|
|
+
|
|
|
+out_err:
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static void __init sbmac_platform_probe(void)
|
|
|
{
|
|
|
- int idx;
|
|
|
- struct net_device *dev;
|
|
|
- unsigned long port;
|
|
|
- int chip_max_units;
|
|
|
+ int i;
|
|
|
|
|
|
/* Set the number of available units based on the SOC type. */
|
|
|
switch (soc_type) {
|
|
|
case K_SYS_SOC_TYPE_BCM1250:
|
|
|
case K_SYS_SOC_TYPE_BCM1250_ALT:
|
|
|
- chip_max_units = 3;
|
|
|
+ sbmac_max_units = 3;
|
|
|
break;
|
|
|
case K_SYS_SOC_TYPE_BCM1120:
|
|
|
case K_SYS_SOC_TYPE_BCM1125:
|
|
|
case K_SYS_SOC_TYPE_BCM1125H:
|
|
|
- case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
|
|
|
- chip_max_units = 2;
|
|
|
+ case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
|
|
|
+ sbmac_max_units = 2;
|
|
|
break;
|
|
|
case K_SYS_SOC_TYPE_BCM1x55:
|
|
|
case K_SYS_SOC_TYPE_BCM1x80:
|
|
|
- chip_max_units = 4;
|
|
|
+ sbmac_max_units = 4;
|
|
|
break;
|
|
|
default:
|
|
|
- chip_max_units = 0;
|
|
|
- break;
|
|
|
+ return; /* none */
|
|
|
}
|
|
|
- if (chip_max_units > MAX_UNITS)
|
|
|
- chip_max_units = MAX_UNITS;
|
|
|
|
|
|
/*
|
|
|
* For bringup when not using the firmware, we can pre-fill
|
|
@@ -2938,89 +2875,71 @@ sbmac_init_module(void)
|
|
|
* specified in this file (or maybe from the config file?)
|
|
|
*/
|
|
|
#ifdef SBMAC_ETH0_HWADDR
|
|
|
- if (chip_max_units > 0)
|
|
|
- sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
|
|
|
+ sbmac_setup_hwaddr(0, SBMAC_ETH0_HWADDR);
|
|
|
#endif
|
|
|
#ifdef SBMAC_ETH1_HWADDR
|
|
|
- if (chip_max_units > 1)
|
|
|
- sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
|
|
|
+ sbmac_setup_hwaddr(1, SBMAC_ETH1_HWADDR);
|
|
|
#endif
|
|
|
#ifdef SBMAC_ETH2_HWADDR
|
|
|
- if (chip_max_units > 2)
|
|
|
- sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
|
|
|
+ sbmac_setup_hwaddr(2, SBMAC_ETH2_HWADDR);
|
|
|
#endif
|
|
|
#ifdef SBMAC_ETH3_HWADDR
|
|
|
- if (chip_max_units > 3)
|
|
|
- sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR);
|
|
|
+ sbmac_setup_hwaddr(3, SBMAC_ETH3_HWADDR);
|
|
|
#endif
|
|
|
|
|
|
+ sbmac_pldev = kcalloc(sbmac_max_units, sizeof(*sbmac_pldev),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!sbmac_pldev) {
|
|
|
+ printk(KERN_ERR "%s: unable to allocate memory\n",
|
|
|
+ sbmac_string);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Walk through the Ethernet controllers and find
|
|
|
* those who have their MAC addresses set.
|
|
|
*/
|
|
|
- for (idx = 0; idx < chip_max_units; idx++) {
|
|
|
+ for (i = 0; i < sbmac_max_units; i++)
|
|
|
+ if (sbmac_platform_probe_one(i))
|
|
|
+ break;
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- * This is the base address of the MAC.
|
|
|
- */
|
|
|
|
|
|
- port = A_MAC_CHANNEL_BASE(idx);
|
|
|
+static void __exit sbmac_platform_cleanup(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
|
|
|
- /*
|
|
|
- * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
|
|
|
- * value for us by the firmware if we are going to use this MAC.
|
|
|
- * If we find a zero, skip this MAC.
|
|
|
- */
|
|
|
+ for (i = 0; i < sbmac_max_units; i++)
|
|
|
+ platform_device_unregister(sbmac_pldev[i]);
|
|
|
+ kfree(sbmac_pldev);
|
|
|
+}
|
|
|
|
|
|
- sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
|
|
|
- if (sbmac_orig_hwaddr[idx] == 0) {
|
|
|
- printk(KERN_DEBUG "sbmac: not configuring MAC at "
|
|
|
- "%lx\n", port);
|
|
|
- continue;
|
|
|
- }
|
|
|
|
|
|
- /*
|
|
|
- * Okay, cool. Initialize this MAC.
|
|
|
- */
|
|
|
+static struct platform_driver sbmac_driver = {
|
|
|
+ .probe = sbmac_probe,
|
|
|
+ .remove = __exit_p(sbmac_remove),
|
|
|
+ .driver = {
|
|
|
+ .name = sbmac_string,
|
|
|
+ },
|
|
|
+};
|
|
|
|
|
|
- dev = alloc_etherdev(sizeof(struct sbmac_softc));
|
|
|
- if (!dev)
|
|
|
- return -ENOMEM;
|
|
|
+static int __init sbmac_init_module(void)
|
|
|
+{
|
|
|
+ int err;
|
|
|
|
|
|
- printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
|
|
|
+ err = platform_driver_register(&sbmac_driver);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
- dev->irq = UNIT_INT(idx);
|
|
|
- dev->base_addr = port;
|
|
|
- dev->mem_end = 0;
|
|
|
- if (sbmac_init(dev, idx)) {
|
|
|
- port = A_MAC_CHANNEL_BASE(idx);
|
|
|
- __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR));
|
|
|
- free_netdev(dev);
|
|
|
- continue;
|
|
|
- }
|
|
|
- dev_sbmac[idx] = dev;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
+ sbmac_platform_probe();
|
|
|
|
|
|
+ return err;
|
|
|
+}
|
|
|
|
|
|
-static void __exit
|
|
|
-sbmac_cleanup_module(void)
|
|
|
+static void __exit sbmac_cleanup_module(void)
|
|
|
{
|
|
|
- struct net_device *dev;
|
|
|
- int idx;
|
|
|
-
|
|
|
- for (idx = 0; idx < MAX_UNITS; idx++) {
|
|
|
- struct sbmac_softc *sc;
|
|
|
- dev = dev_sbmac[idx];
|
|
|
- if (!dev)
|
|
|
- continue;
|
|
|
-
|
|
|
- sc = netdev_priv(dev);
|
|
|
- unregister_netdev(dev);
|
|
|
- sbmac_uninitctx(sc);
|
|
|
- free_netdev(dev);
|
|
|
- }
|
|
|
+ sbmac_platform_cleanup();
|
|
|
+ platform_driver_unregister(&sbmac_driver);
|
|
|
}
|
|
|
|
|
|
module_init(sbmac_init_module);
|