patch-2.1.53 linux/drivers/net/sunhme.c
Next file: linux/drivers/net/sunhme.h
Previous file: linux/drivers/net/soundmodem/sm_afsk2400_8.c
Back to the patch index
Back to the overall index
- Lines: 1403
- Date:
Thu Sep 4 13:25:28 1997
- Orig file:
v2.1.52/linux/drivers/net/sunhme.c
- Orig date:
Thu Jul 17 10:06:05 1997
diff -u --recursive --new-file v2.1.52/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -20,6 +21,7 @@
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -35,11 +37,18 @@
#include <asm/auxio.h>
#include <asm/system.h>
#include <asm/pgtable.h>
+#include <asm/irq.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/pbm.h>
+#endif
+
#include "sunhme.h"
#ifdef MODULE
@@ -68,30 +77,33 @@
#define DEFAULT_JAMSIZE 4 /* Toe jam */
/* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */
-#define BB_PUT_BIT(tregs, bit) \
-do { (tregs)->bb_data = (bit); (tregs)->bb_clock = 0; (tregs)->bb_clock = 1; } while(0)
-
-#define BB_GET_BIT(tregs, internal) \
-({ \
- (tregs)->bb_clock = 0; \
- (tregs)->bb_clock = 1; \
- if(internal) \
- ((tregs)->cfg & TCV_CFG_MDIO0); \
- else \
- ((tregs)->cfg & TCV_CFG_MDIO1); \
+#define BB_PUT_BIT(hp, tregs, bit) \
+do { hme_write32(hp, &(tregs)->bb_data, (bit)); \
+ hme_write32(hp, &(tregs)->bb_clock, 0); \
+ hme_write32(hp, &(tregs)->bb_clock, 1); \
+} while(0)
+
+#define BB_GET_BIT(hp, tregs, internal) \
+({ \
+ hme_write32(hp, &(tregs)->bb_clock, 0); \
+ hme_write32(hp, &(tregs)->bb_clock, 1); \
+ if(internal) \
+ hme_read32(hp, &(tregs)->cfg) & TCV_CFG_MDIO0; \
+ else \
+ hme_read32(hp, &(tregs)->cfg) & TCV_CFG_MDIO1; \
})
-#define BB_GET_BIT2(tregs, internal) \
-({ \
- int retval; \
- (tregs)->bb_clock = 0; \
- udelay(1); \
- if(internal) \
- retval = ((tregs)->cfg & TCV_CFG_MDIO0); \
- else \
- retval = ((tregs)->cfg & TCV_CFG_MDIO1); \
- (tregs)->bb_clock = 1; \
- retval; \
+#define BB_GET_BIT2(hp, tregs, internal) \
+({ \
+ int retval; \
+ hme_write32(hp, &(tregs)->bb_clock, 0); \
+ udelay(1); \
+ if(internal) \
+ retval = hme_read32(hp, &(tregs)->cfg) & TCV_CFG_MDIO0; \
+ else \
+ retval = hme_read32(hp, &(tregs)->cfg) & TCV_CFG_MDIO1; \
+ hme_write32(hp, &(tregs)->bb_clock, 1); \
+ retval; \
})
#define TCVR_FAILURE 0x80000000 /* Impossible MIF read value */
@@ -107,38 +119,38 @@
ASD(("happy_meal_bb_read: reg=%d ", reg));
/* Enable the MIF BitBang outputs. */
- tregs->bb_oenab = 1;
+ hme_write32(hp, &tregs->bb_oenab, 1);
/* Force BitBang into the idle state. */
for(i = 0; i < 32; i++)
- BB_PUT_BIT(tregs, 1);
+ BB_PUT_BIT(hp, tregs, 1);
/* Give it the read sequence. */
- BB_PUT_BIT(tregs, 0);
- BB_PUT_BIT(tregs, 1);
- BB_PUT_BIT(tregs, 1);
- BB_PUT_BIT(tregs, 0);
+ BB_PUT_BIT(hp, tregs, 0);
+ BB_PUT_BIT(hp, tregs, 1);
+ BB_PUT_BIT(hp, tregs, 1);
+ BB_PUT_BIT(hp, tregs, 0);
/* Give it the PHY address. */
tmp = hp->paddr & 0xff;
for(i = 4; i >= 0; i--)
- BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+ BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));
/* Tell it what register we want to read. */
tmp = (reg & 0xff);
for(i = 4; i >= 0; i--)
- BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+ BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));
/* Close down the MIF BitBang outputs. */
- tregs->bb_oenab = 0;
+ hme_write32(hp, &tregs->bb_oenab, 0);
/* Now read in the value. */
- unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
+ unused = BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));
for(i = 15; i >= 0; i--)
- retval |= BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
- unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
- unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
- unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
+ retval |= BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));
+ unused = BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));
+ unused = BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));
+ unused = BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));
ASD(("value=%x\n", retval));
return retval;
}
@@ -153,37 +165,37 @@
ASD(("happy_meal_bb_write: reg=%d value=%x\n", reg, value));
/* Enable the MIF BitBang outputs. */
- tregs->bb_oenab = 1;
+ hme_write32(hp, &tregs->bb_oenab, 1);
/* Force BitBang into the idle state. */
for(i = 0; i < 32; i++)
- BB_PUT_BIT(tregs, 1);
+ BB_PUT_BIT(hp, tregs, 1);
/* Give it write sequence. */
- BB_PUT_BIT(tregs, 0);
- BB_PUT_BIT(tregs, 1);
- BB_PUT_BIT(tregs, 0);
- BB_PUT_BIT(tregs, 1);
+ BB_PUT_BIT(hp, tregs, 0);
+ BB_PUT_BIT(hp, tregs, 1);
+ BB_PUT_BIT(hp, tregs, 0);
+ BB_PUT_BIT(hp, tregs, 1);
/* Give it the PHY address. */
tmp = (hp->paddr & 0xff);
for(i = 4; i >= 0; i--)
- BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+ BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));
/* Tell it what register we will be writing. */
tmp = (reg & 0xff);
for(i = 4; i >= 0; i--)
- BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+ BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));
/* Tell it to become ready for the bits. */
- BB_PUT_BIT(tregs, 1);
- BB_PUT_BIT(tregs, 0);
+ BB_PUT_BIT(hp, tregs, 1);
+ BB_PUT_BIT(hp, tregs, 0);
for(i = 15; i >= 0; i--)
- BB_PUT_BIT(tregs, ((value >> i) & 1));
+ BB_PUT_BIT(hp, tregs, ((value >> i) & 1));
/* Close down the MIF BitBang outputs. */
- tregs->bb_oenab = 0;
+ hme_write32(hp, &tregs->bb_oenab, 0);
}
#define TCVR_READ_TRIES 16
@@ -205,14 +217,15 @@
return happy_meal_bb_read(hp, tregs, reg);
}
- tregs->frame = (FRAME_READ | (hp->paddr << 23) | ((reg & 0xff) << 18));
- while(!(tregs->frame & 0x10000) && --tries)
+ hme_write32(hp, &tregs->frame,
+ (FRAME_READ | (hp->paddr << 23) | ((reg & 0xff) << 18)));
+ while(!(hme_read32(hp, &tregs->frame) & 0x10000) && --tries)
udelay(20);
if(!tries) {
printk("happy meal: Aieee, transceiver MIF read bolixed\n");
return TCVR_FAILURE;
}
- retval = tregs->frame & 0xffff;
+ retval = hme_read32(hp, &tregs->frame) & 0xffff;
ASD(("value=%04x\n", retval));
return retval;
}
@@ -232,9 +245,10 @@
return happy_meal_bb_write(hp, tregs, reg, value);
/* Would you like fries with that? */
- tregs->frame = (FRAME_WRITE | (hp->paddr << 23) |
- ((reg & 0xff) << 18) | (value & 0xffff));
- while(!(tregs->frame & 0x10000) && --tries)
+ hme_write32(hp, &tregs->frame,
+ (FRAME_WRITE | (hp->paddr << 23) |
+ ((reg & 0xff) << 18) | (value & 0xffff)));
+ while(!(hme_read32(hp, &tregs->frame) & 0x10000) && --tries)
udelay(20);
/* Anything else? */
@@ -364,9 +378,13 @@
* XXX Happy Meal front end for this to work every time.
*/
if(full)
- hp->bigmacregs->tx_cfg |= BIGMAC_TXCFG_FULLDPLX;
+ hme_write32(hp, &hp->bigmacregs->tx_cfg,
+ hme_read32(hp, &hp->bigmacregs->tx_cfg) |
+ BIGMAC_TXCFG_FULLDPLX);
else
- hp->bigmacregs->tx_cfg &= ~(BIGMAC_TXCFG_FULLDPLX);
+ hme_write32(hp, &hp->bigmacregs->tx_cfg,
+ hme_read32(hp, &hp->bigmacregs->tx_cfg) &
+ ~(BIGMAC_TXCFG_FULLDPLX));
return 0;
no_response:
@@ -541,15 +559,16 @@
#define TX_RESET_TRIES 32
#define RX_RESET_TRIES 32
-static inline void happy_meal_tx_reset(struct hmeal_bigmacregs *bregs)
+static inline void happy_meal_tx_reset(struct happy_meal *hp,
+ struct hmeal_bigmacregs *bregs)
{
int tries = TX_RESET_TRIES;
HMD(("happy_meal_tx_reset: reset, "));
/* Would you like to try our SMCC Delux? */
- bregs->tx_swreset = 0;
- while((bregs->tx_swreset & 1) && --tries)
+ hme_write32(hp, &bregs->tx_swreset, 0);
+ while((hme_read32(hp, &bregs->tx_swreset) & 1) && --tries)
udelay(20);
/* Lettuce, tomato, buggy hardware (no extra charge)? */
@@ -560,15 +579,16 @@
HMD(("done\n"));
}
-static inline void happy_meal_rx_reset(struct hmeal_bigmacregs *bregs)
+static inline void happy_meal_rx_reset(struct happy_meal *hp,
+ struct hmeal_bigmacregs *bregs)
{
int tries = RX_RESET_TRIES;
HMD(("happy_meal_rx_reset: reset, "));
/* We have a special on GNU/Viking hardware bugs today. */
- bregs->rx_swreset = 0;
- while((bregs->rx_swreset & 1) && --tries)
+ hme_write32(hp, &bregs->rx_swreset, 0);
+ while((hme_read32(hp, &bregs->rx_swreset) & 1) && --tries)
udelay(20);
/* Will that be all? */
@@ -581,15 +601,16 @@
#define STOP_TRIES 16
-static inline void happy_meal_stop(struct hmeal_gregs *gregs)
+static inline void happy_meal_stop(struct happy_meal *hp,
+ struct hmeal_gregs *gregs)
{
int tries = STOP_TRIES;
HMD(("happy_meal_stop: reset, "));
/* We're consolidating our STB products, it's your lucky day. */
- gregs->sw_reset = GREG_RESET_ALL;
- while(gregs->sw_reset && --tries)
+ hme_write32(hp, &gregs->sw_reset, GREG_RESET_ALL);
+ while(hme_read32(hp, &gregs->sw_reset) && --tries)
udelay(20);
/* Come back next week when we are "Sun Microelectronics". */
@@ -605,19 +626,22 @@
{
struct net_device_stats *stats = &hp->net_stats;
- stats->rx_crc_errors += bregs->rcrce_ctr;
- bregs->rcrce_ctr = 0;
+ stats->rx_crc_errors += hme_read32(hp, &bregs->rcrce_ctr);
+ hme_write32(hp, &bregs->rcrce_ctr, 0);
- stats->rx_frame_errors += bregs->unale_ctr;
- bregs->unale_ctr = 0;
+ stats->rx_frame_errors += hme_read32(hp, &bregs->unale_ctr);
+ hme_write32(hp, &bregs->unale_ctr, 0);
- stats->rx_length_errors += bregs->gle_ctr;
- bregs->gle_ctr = 0;
+ stats->rx_length_errors += hme_read32(hp, &bregs->gle_ctr);
+ hme_write32(hp, &bregs->gle_ctr, 0);
- stats->tx_aborted_errors += bregs->ex_ctr;
-
- stats->collisions += (bregs->ex_ctr + bregs->lt_ctr);
- bregs->ex_ctr = bregs->lt_ctr = 0;
+ stats->tx_aborted_errors += hme_read32(hp, &bregs->ex_ctr);
+
+ stats->collisions +=
+ (hme_read32(hp, &bregs->ex_ctr) +
+ hme_read32(hp, &bregs->lt_ctr));
+ hme_write32(hp, &bregs->ex_ctr, 0);
+ hme_write32(hp, &bregs->lt_ctr, 0);
}
static inline void happy_meal_poll_start(struct happy_meal *hp,
@@ -634,12 +658,12 @@
/* Start the MIF polling on the external transceiver. */
ASD(("polling on, "));
- tmp = tregs->cfg;
+ tmp = hme_read32(hp, &tregs->cfg);
tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);
tmp |= ((hp->paddr & 0x1f) << 10);
tmp |= (TCV_PADDR_ETX << 3);
tmp |= TCV_CFG_PENABLE;
- tregs->cfg = tmp;
+ hme_write32(hp, &tregs->cfg, tmp);
/* Let the bits set. */
udelay(200);
@@ -660,9 +684,9 @@
/* Listen only for the MIF interrupts we want to hear. */
ASD(("mif ints on, "));
if(speed == 100)
- tregs->int_mask = 0xfffb;
+ hme_write32(hp, &tregs->int_mask, 0xfffb);
else
- tregs->int_mask = 0xfff9;
+ hme_write32(hp, &tregs->int_mask, 0xfff9);
ASD(("done\n"));
}
@@ -680,11 +704,12 @@
/* Shut up the MIF. */
ASD(("were polling, mif ints off, "));
- tregs->int_mask = 0xffff;
+ hme_write32(hp, &tregs->int_mask, 0xffff);
/* Turn off polling. */
ASD(("polling off, "));
- tregs->cfg &= ~(TCV_CFG_PENABLE);
+ hme_write32(hp, &tregs->cfg,
+ hme_read32(hp, &tregs->cfg) & ~(TCV_CFG_PENABLE));
/* We are no longer polling. */
hp->happy_flags &= ~(HFLAG_POLL);
@@ -706,11 +731,11 @@
unsigned long tconfig;
int result, tries = TCVR_RESET_TRIES;
- tconfig = tregs->cfg;
+ tconfig = hme_read32(hp, &tregs->cfg);
ASD(("happy_meal_tcvr_reset: tcfg<%08lx> ", tconfig));
if(hp->tcvr_type == external) {
ASD(("external<"));
- tregs->cfg = tconfig & ~(TCV_CFG_PSELECT);
+ hme_write32(hp, &tregs->cfg, tconfig & ~(TCV_CFG_PSELECT));
hp->tcvr_type = internal;
hp->paddr = TCV_PADDR_ITX;
ASD(("ISOLATE,"));
@@ -722,13 +747,13 @@
return -1;
}
ASD(("phyread_ok,PSELECT>"));
- tregs->cfg = tconfig | TCV_CFG_PSELECT;
+ hme_write32(hp, &tregs->cfg, tconfig | TCV_CFG_PSELECT);
hp->tcvr_type = external;
hp->paddr = TCV_PADDR_ETX;
} else {
if(tconfig & TCV_CFG_MDIO1) {
ASD(("internal<PSELECT,"));
- tregs->cfg = (tconfig | TCV_CFG_PSELECT);
+ hme_write32(hp, &tregs->cfg, (tconfig | TCV_CFG_PSELECT));
ASD(("ISOLATE,"));
happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,
(BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));
@@ -738,7 +763,7 @@
return -1;
}
ASD(("phyread_ok,~PSELECT>"));
- tregs->cfg = (tconfig & ~(TCV_CFG_PSELECT));
+ hme_write32(hp, &tregs->cfg, (tconfig & ~(TCV_CFG_PSELECT)));
hp->tcvr_type = internal;
hp->paddr = TCV_PADDR_ITX;
}
@@ -795,7 +820,7 @@
static void happy_meal_transceiver_check(struct happy_meal *hp,
struct hmeal_tcvregs *tregs)
{
- unsigned long tconfig = tregs->cfg;
+ unsigned long tconfig = hme_read32(hp, &tregs->cfg);
ASD(("happy_meal_transceiver_check: tcfg=%08lx ", tconfig));
if(hp->happy_flags & HFLAG_POLL) {
@@ -810,18 +835,20 @@
ASD(("<external>\n"));
tconfig &= ~(TCV_CFG_PENABLE);
tconfig |= TCV_CFG_PSELECT;
- tregs->cfg = tconfig;
+ hme_write32(hp, &tregs->cfg, tconfig);
}
} else {
if(hp->tcvr_type == external) {
ASD(("<external> "));
- if(!(tregs->status >> 16)) {
+ if(!(hme_read32(hp, &tregs->status) >> 16)) {
ASD(("<poll stop> "));
happy_meal_poll_stop(hp, tregs);
hp->paddr = TCV_PADDR_ITX;
hp->tcvr_type = internal;
ASD(("<internal>\n"));
- tregs->cfg &= ~(TCV_CFG_PSELECT);
+ hme_write32(hp, &tregs->cfg,
+ hme_read32(hp, &tregs->cfg) &
+ ~(TCV_CFG_PSELECT));
}
ASD(("\n"));
} else {
@@ -829,18 +856,19 @@
}
}
} else {
- unsigned long reread = tregs->cfg;
+ unsigned long reread = hme_read32(hp, &tregs->cfg);
/* Else we can just work off of the MDIO bits. */
ASD(("<not polling> "));
if(reread & TCV_CFG_MDIO1) {
- tregs->cfg = tconfig | TCV_CFG_PSELECT;
+ hme_write32(hp, &tregs->cfg, tconfig | TCV_CFG_PSELECT);
hp->paddr = TCV_PADDR_ETX;
hp->tcvr_type = external;
ASD(("<external>\n"));
} else {
if(reread & TCV_CFG_MDIO0) {
- tregs->cfg = tconfig & ~(TCV_CFG_PSELECT);
+ hme_write32(hp, &tregs->cfg,
+ tconfig & ~(TCV_CFG_PSELECT));
hp->paddr = TCV_PADDR_ITX;
hp->tcvr_type = internal;
ASD(("<internal>\n"));
@@ -946,11 +974,17 @@
/* Because we reserve afterwards. */
skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
- hb->happy_meal_rxd[i].rx_addr =
- (u32) ((unsigned long)skb->data);
+ if(hp->happy_flags & HFLAG_PCI) {
+ pcihme_write_rxd(&hb->happy_meal_rxd[i],
+ (RXFLAG_OWN |
+ ((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
+ (u32)virt_to_bus((volatile void *)skb->data));
+ } else {
+ hb->happy_meal_rxd[i].rx_addr = (u32)((unsigned long) skb->data);
+ hb->happy_meal_rxd[i].rx_flags =
+ (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+ }
skb_reserve(skb, RX_OFFSET);
- hb->happy_meal_rxd[i].rx_flags =
- (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
}
HMD(("init txring, "));
@@ -1097,7 +1131,8 @@
unsigned long regtmp;
unsigned char *e = &hp->dev->dev_addr[0];
- HMD(("happy_meal_init: "));
+ HMD(("happy_meal_init: happy_flags[%08x] ",
+ hp->happy_flags));
if(!(hp->happy_flags & HFLAG_INIT)) {
HMD(("set HFLAG_INIT, "));
hp->happy_flags |= HFLAG_INIT;
@@ -1110,7 +1145,7 @@
/* Stop transmitter and receiver. */
HMD(("happy_meal_init: to happy_meal_stop\n"));
- happy_meal_stop(gregs);
+ happy_meal_stop(hp, gregs);
/* Alloc and reset the tx/rx descriptor chains. */
HMD(("happy_meal_init: to happy_meal_init_rings\n"));
@@ -1120,16 +1155,21 @@
happy_meal_init_rings(hp, from_irq);
/* Shut up the MIF. */
- HMD(("happy_meal_init: Disable all MIF irqs, "));
- tregs->int_mask = 0xffff;
+ HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",
+ hme_read32(hp, &tregs->int_mask)));
+ hme_write32(hp, &tregs->int_mask, 0xffff);
/* See if we can enable the MIF frame on this card to speak to the DP83840. */
if(hp->happy_flags & HFLAG_FENABLE) {
- HMD(("use frame, "));
- tregs->cfg &= ~(TCV_CFG_BENABLE);
+ HMD(("use frame old[%08x], ",
+ hme_read32(hp, &tregs->cfg)));
+ hme_write32(hp, &tregs->cfg,
+ hme_read32(hp, &tregs->cfg) & ~(TCV_CFG_BENABLE));
} else {
- HMD(("use bitbang, "));
- tregs->cfg |= TCV_CFG_BENABLE;
+ HMD(("use bitbang old[%08x], ",
+ hme_read32(hp, &tregs->cfg)));
+ hme_write32(hp, &tregs->cfg,
+ hme_read32(hp, &tregs->cfg) | TCV_CFG_BENABLE);
}
/* Check the state of the transceiver. */
@@ -1147,13 +1187,13 @@
case internal:
/* Using the MII buffers. */
HMD(("internal, using MII, "));
- bregs->xif_cfg = 0;
+ hme_write32(hp, &bregs->xif_cfg, 0);
break;
case external:
/* Not using the MII, disable it. */
HMD(("external, disable MII, "));
- bregs->xif_cfg = BIGMAC_XCFG_MIIDISAB;
+ hme_write32(hp, &bregs->xif_cfg, BIGMAC_XCFG_MIIDISAB);
break;
};
@@ -1162,81 +1202,90 @@
/* Reset the Happy Meal Big Mac transceiver and the receiver. */
HMD(("tx/rx reset, "));
- happy_meal_tx_reset(bregs);
- happy_meal_rx_reset(bregs);
+ happy_meal_tx_reset(hp, bregs);
+ happy_meal_rx_reset(hp, bregs);
/* Set jam size and inter-packet gaps to reasonable defaults. */
HMD(("jsize/ipg1/ipg2, "));
- bregs->jsize = DEFAULT_JAMSIZE;
- bregs->ipkt_gap1 = DEFAULT_IPG1;
- bregs->ipkt_gap2 = DEFAULT_IPG2;
+ hme_write32(hp, &bregs->jsize, DEFAULT_JAMSIZE);
+ hme_write32(hp, &bregs->ipkt_gap1, DEFAULT_IPG1);
+ hme_write32(hp, &bregs->ipkt_gap2, DEFAULT_IPG2);
/* Load up the MAC address and random seed. */
HMD(("rseed/macaddr, "));
/* XXX use something less deterministic... */
- bregs->rand_seed = 0xbd;
+ hme_write32(hp, &bregs->rand_seed, 0xbd);
- bregs->mac_addr2 = ((e[4] << 8) | e[5]);
- bregs->mac_addr1 = ((e[2] << 8) | e[3]);
- bregs->mac_addr0 = ((e[0] << 8) | e[1]);
+ hme_write32(hp, &bregs->mac_addr2, ((e[4] << 8) | e[5]));
+ hme_write32(hp, &bregs->mac_addr1, ((e[2] << 8) | e[3]));
+ hme_write32(hp, &bregs->mac_addr0, ((e[0] << 8) | e[1]));
/* Ick, figure out how to properly program the hash table later... */
HMD(("htable, "));
- bregs->htable3 = 0;
- bregs->htable2 = 0;
- bregs->htable1 = 0;
- bregs->htable0 = 0;
+ hme_write32(hp, &bregs->htable3, 0);
+ hme_write32(hp, &bregs->htable2, 0);
+ hme_write32(hp, &bregs->htable1, 0);
+ hme_write32(hp, &bregs->htable0, 0);
/* Set the RX and TX ring ptrs. */
- HMD(("ring ptrs\n"));
- erxregs->rx_ring = hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0);
- etxregs->tx_ring = hp->hblock_dvma + hblock_offset(happy_meal_txd, 0);
-
- /* Set the supported SBUS burst sizes. */
- HMD(("happy_meal_init: bursts<"));
+ HMD(("ring ptrs rxr[%08x] txr[%08x]\n",
+ (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)),
+ (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))));
+ hme_write32(hp, &erxregs->rx_ring,
+ (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)));
+ hme_write32(hp, &etxregs->tx_ring,
+ (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
+
+ /* Set the supported burst sizes. */
+ HMD(("happy_meal_init: old[%08x] bursts<",
+ hme_read32(hp, &gregs->cfg)));
-#if 0 /* XXX take down huahaga and debug this... */
- /* Grrr... */
+#ifdef __sparc_v9__
if(hp->happy_bursts & DMA_BURST64) {
HMD(("64>"));
- gregs->cfg = GREG_CFG_BURST64;
+ hme_write32(hp, &gregs->cfg, GREG_CFG_BURST64);
} else
#endif
if(hp->happy_bursts & DMA_BURST32) {
HMD(("32>"));
- gregs->cfg = GREG_CFG_BURST32;
+ hme_write32(hp, &gregs->cfg, GREG_CFG_BURST32);
} else if(hp->happy_bursts & DMA_BURST16) {
HMD(("16>"));
- gregs->cfg = GREG_CFG_BURST16;
+ hme_write32(hp, &gregs->cfg, GREG_CFG_BURST16);
} else {
HMD(("XXX>"));
- gregs->cfg = 0;
+ hme_write32(hp, &gregs->cfg, 0);
}
/* Turn off interrupts we do not want to hear. */
HMD((", enable global interrupts, "));
- gregs->imask = (GREG_IMASK_GOTFRAME | GREG_IMASK_RCNTEXP |
- GREG_IMASK_SENTFRAME | GREG_IMASK_TXPERR);
+ hme_write32(hp, &gregs->imask,
+ (GREG_IMASK_GOTFRAME | GREG_IMASK_RCNTEXP |
+ GREG_IMASK_SENTFRAME | GREG_IMASK_TXPERR));
/* Set the transmit ring buffer size. */
- HMD(("tx rsize=%d, ", (int)TX_RING_SIZE));
- etxregs->tx_rsize = (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1;
+ HMD(("tx rsize=%d oreg[%08x], ", (int)TX_RING_SIZE,
+ hme_read32(hp, &etxregs->tx_rsize)));
+ hme_write32(hp, &etxregs->tx_rsize, (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1);
/* Enable transmitter DVMA. */
- HMD(("tx dma enable, "));
- etxregs->cfg |= ETX_CFG_DMAENABLE;
+ HMD(("tx dma enable old[%08x], ",
+ hme_read32(hp, &etxregs->cfg)));
+ hme_write32(hp, &etxregs->cfg,
+ hme_read32(hp, &etxregs->cfg) | ETX_CFG_DMAENABLE);
/* This chip really rots, for the receiver sometimes when you
* write to it's control registers not all the bits get there
* properly. I cannot think of a sane way to provide complete
* coverage for this hardware bug yet.
*/
- HMD(("erx regs bug\n"));
- erxregs->cfg = ERX_CFG_DEFAULT(RX_OFFSET);
- regtmp = erxregs->cfg;
- erxregs->cfg = ERX_CFG_DEFAULT(RX_OFFSET);
- if(erxregs->cfg != ERX_CFG_DEFAULT(RX_OFFSET)) {
+ HMD(("erx regs bug old[%08x]\n",
+ hme_read32(hp, &erxregs->cfg)));
+ hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET));
+ regtmp = hme_read32(hp, &erxregs->cfg);
+ hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET));
+ if(hme_read32(hp, &erxregs->cfg) != ERX_CFG_DEFAULT(RX_OFFSET)) {
printk("happy meal: Eieee, rx config register gets greasy fries.\n");
printk("happy meal: Trying to set %08x, reread gives %08lx\n",
ERX_CFG_DEFAULT(RX_OFFSET), regtmp);
@@ -1244,8 +1293,9 @@
}
/* Enable Big Mac hash table filter. */
- HMD(("happy_meal_init: enable hash, "));
- bregs->rx_cfg = BIGMAC_RXCFG_HENABLE;
+ HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ",
+ hme_read32(hp, &bregs->rx_cfg)));
+ hme_write32(hp, &bregs->rx_cfg, BIGMAC_RXCFG_HENABLE);
/* Let the bits settle in the chip. */
udelay(10);
@@ -1255,7 +1305,7 @@
regtmp = 0;
if(hp->happy_flags & HFLAG_FULL)
regtmp |= BIGMAC_TXCFG_FULLDPLX;
- bregs->tx_cfg = regtmp | BIGMAC_TXCFG_DGIVEUP;
+ hme_write32(hp, &bregs->tx_cfg, regtmp | BIGMAC_TXCFG_DGIVEUP);
/* Enable the output drivers no matter what. */
regtmp = BIGMAC_XCFG_ODENABLE;
@@ -1268,13 +1318,18 @@
if(hp->tcvr_type == external)
regtmp |= BIGMAC_XCFG_MIIDISAB;
- HMD(("XIF config, "));
- bregs->xif_cfg = regtmp;
+ HMD(("XIF config old[%08x], ",
+ hme_read32(hp, &bregs->xif_cfg)));
+ hme_write32(hp, &bregs->xif_cfg, regtmp);
/* Start things up. */
- HMD(("tx and rx ON!\n"));
- bregs->tx_cfg |= BIGMAC_TXCFG_ENABLE;
- bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE;
+ HMD(("tx old[%08x] and rx [%08x] ON!\n",
+ hme_read32(hp, &bregs->tx_cfg),
+ hme_read32(hp, &bregs->rx_cfg)));
+ hme_write32(hp, &bregs->tx_cfg,
+ hme_read32(hp, &bregs->tx_cfg) | BIGMAC_TXCFG_ENABLE);
+ hme_write32(hp, &bregs->rx_cfg,
+ hme_read32(hp, &bregs->rx_cfg) | BIGMAC_RXCFG_ENABLE);
/* Get the autonegotiation started, and the watch timer ticking. */
happy_meal_begin_auto_negotiation(hp, tregs);
@@ -1289,21 +1344,23 @@
struct hmeal_bigmacregs *bregs = hp->bigmacregs;
struct hmeal_gregs *gregs = hp->gregs;
- happy_meal_stop(gregs);
- tregs->int_mask = 0xffff;
+ happy_meal_stop(hp, gregs);
+ hme_write32(hp, &tregs->int_mask, 0xffff);
if(hp->happy_flags & HFLAG_FENABLE)
- tregs->cfg &= ~(TCV_CFG_BENABLE);
+ hme_write32(hp, &tregs->cfg,
+ hme_read32(hp, &tregs->cfg) & ~(TCV_CFG_BENABLE));
else
- tregs->cfg |= TCV_CFG_BENABLE;
+ hme_write32(hp, &tregs->cfg,
+ hme_read32(hp, &tregs->cfg) | TCV_CFG_BENABLE);
happy_meal_transceiver_check(hp, tregs);
switch(hp->tcvr_type) {
case none:
return;
case internal:
- bregs->xif_cfg = 0;
+ hme_write32(hp, &bregs->xif_cfg, 0);
break;
case external:
- bregs->xif_cfg = BIGMAC_XCFG_MIIDISAB;
+ hme_write32(hp, &bregs->xif_cfg, BIGMAC_XCFG_MIIDISAB);
break;
};
if(happy_meal_tcvr_reset(hp, tregs))
@@ -1544,6 +1601,13 @@
hp->tx_skbs[elem] = NULL;
hp->net_stats.tx_bytes+=skb->len;
+#ifdef NEED_DMA_SYNCHRONIZATION
+#ifdef CONFIG_PCI
+ if(!(hp->happy_flags & HFLAG_PCI))
+#endif
+ mmu_sync_dma(kva_to_hva(hp, skb->data),
+ skb->len, hp->happy_sbus_dev->my_bus);
+#endif
dev_kfree_skb(skb, FREE_WRITE);
hp->net_stats.tx_packets++;
@@ -1553,6 +1617,39 @@
TXD((">"));
}
+#ifdef CONFIG_PCI
+static inline void pci_happy_meal_tx(struct happy_meal *hp)
+{
+ struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
+ struct happy_meal_txd *this;
+ int elem = hp->tx_old;
+
+ TXD(("TX<"));
+ while(elem != hp->tx_new) {
+ struct sk_buff *skb;
+ unsigned int flags;
+
+ TXD(("[%d]", elem));
+ this = &txbase[elem];
+ __asm__ __volatile__("lduwa [%1] %2, %0"
+ : "=r" (flags)
+ : "r" (&this->tx_flags), "i" (ASI_PL));
+ if(flags & TXFLAG_OWN)
+ break;
+ skb = hp->tx_skbs[elem];
+ hp->tx_skbs[elem] = NULL;
+ hp->net_stats.tx_bytes+=skb->len;
+
+ dev_kfree_skb(skb, FREE_WRITE);
+
+ hp->net_stats.tx_packets++;
+ elem = NEXT_TX(elem);
+ }
+ hp->tx_old = elem;
+ TXD((">"));
+}
+#endif
+
static inline void sun4c_happy_meal_tx(struct happy_meal *hp)
{
struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
@@ -1616,13 +1713,19 @@
/* Return it to the Happy meal. */
drop_it:
hp->net_stats.rx_dropped++;
- this->rx_addr =
- (u32) ((unsigned long)hp->rx_skbs[elem]->data);
+ this->rx_addr = kva_to_hva(hp, hp->rx_skbs[elem]->data);
this->rx_flags =
(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
goto next;
}
skb = hp->rx_skbs[elem];
+#ifdef NEED_DMA_SYNCHRONIZATION
+#ifdef CONFIG_PCI
+ if(!(hp->happy_flags & HFLAG_PCI))
+#endif
+ mmu_sync_dma(kva_to_hva(hp, skb->data),
+ skb->len, hp->happy_sbus_dev->my_bus);
+#endif
if(len > RX_COPY_THRESHOLD) {
struct sk_buff *new_skb;
@@ -1636,8 +1739,7 @@
hp->rx_skbs[elem] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
- rxbase[elem].rx_addr =
- (u32) ((unsigned long)new_skb->data);
+ rxbase[elem].rx_addr = kva_to_hva(hp, new_skb->data);
skb_reserve(new_skb, RX_OFFSET);
rxbase[elem].rx_flags =
(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
@@ -1658,8 +1760,7 @@
memcpy(copy_skb->data, skb->data, len);
/* Reuse original ring buffer. */
- rxbase[elem].rx_addr =
- (u32) ((unsigned long)skb->data);
+ rxbase[elem].rx_addr = kva_to_hva(hp, skb->data);
rxbase[elem].rx_flags =
(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
@@ -1688,6 +1789,117 @@
RXD((">"));
}
+#ifdef CONFIG_PCI
+static inline void pci_happy_meal_rx(struct happy_meal *hp, struct device *dev,
+ struct hmeal_gregs *gregs)
+{
+ struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0];
+ struct happy_meal_rxd *this;
+ unsigned int flags;
+ int elem = hp->rx_new, drops = 0;
+
+ RXD(("RX<"));
+ this = &rxbase[elem];
+ __asm__ __volatile__("lduwa [%1] %2, %0"
+ : "=r" (flags)
+ : "r" (&this->rx_flags), "i" (ASI_PL));
+ while(!(flags & RXFLAG_OWN)) {
+ struct sk_buff *skb;
+ int len;
+ u16 csum;
+
+ RXD(("[%d ", elem));
+
+ len = flags >> 16;
+ csum = flags & RXFLAG_CSUM;
+
+ /* Check for errors. */
+ if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
+ RXD(("ERR(%08lx)]", flags));
+ hp->net_stats.rx_errors++;
+ if(len < ETH_ZLEN)
+ hp->net_stats.rx_length_errors++;
+ if(len & (RXFLAG_OVERFLOW >> 16)) {
+ hp->net_stats.rx_over_errors++;
+ hp->net_stats.rx_fifo_errors++;
+ }
+
+ /* Return it to the Happy meal. */
+ drop_it:
+ hp->net_stats.rx_dropped++;
+ pcihme_write_rxd(this,
+ (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
+ (u32) virt_to_bus((volatile void *)hp->rx_skbs[elem]->data));
+ goto next;
+ }
+ skb = hp->rx_skbs[elem];
+ if(len > RX_COPY_THRESHOLD) {
+ struct sk_buff *new_skb;
+
+ /* Now refill the entry, if we can. */
+ new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+ if(!new_skb) {
+ drops++;
+ goto drop_it;
+ }
+
+ hp->rx_skbs[elem] = new_skb;
+ new_skb->dev = dev;
+ skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
+ pcihme_write_rxd(&rxbase[elem],
+ (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
+ (u32)virt_to_bus((volatile void *)new_skb->data));
+ skb_reserve(new_skb, RX_OFFSET);
+
+ /* Trim the original skb for the netif. */
+ skb_trim(skb, len);
+ } else {
+ struct sk_buff *copy_skb = dev_alloc_skb(len+2);
+
+ if(!copy_skb) {
+ drops++;
+ goto drop_it;
+ }
+
+ copy_skb->dev = dev;
+ skb_reserve(copy_skb, 2);
+ skb_put(copy_skb, len);
+ memcpy(copy_skb->data, skb->data, len);
+
+ /* Reuse original ring buffer. */
+ pcihme_write_rxd(&rxbase[elem],
+ (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
+ (u32)virt_to_bus((volatile void *)skb->data));
+
+ skb = copy_skb;
+ }
+
+ /* This card is _fucking_ hot... */
+ if(!~(csum))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ RXD(("len=%d csum=%4x]", len, csum));
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+
+ hp->net_stats.rx_packets++;
+ hp->net_stats.rx_bytes+=len;
+ next:
+ elem = NEXT_RX(elem);
+ this = &rxbase[elem];
+ __asm__ __volatile__("lduwa [%1] %2, %0"
+ : "=r" (flags)
+ : "r" (&this->rx_flags), "i" (ASI_PL));
+ }
+ hp->rx_new = elem;
+ if(drops)
+ printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+ RXD((">"));
+}
+#endif
+
static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev,
struct hmeal_gregs *gregs)
{
@@ -1757,7 +1969,7 @@
struct happy_meal *hp = (struct happy_meal *) dev->priv;
struct hmeal_gregs *gregs = hp->gregs;
struct hmeal_tcvregs *tregs = hp->tcvregs;
- unsigned long happy_status = gregs->stat;
+ unsigned int happy_status = hme_read32(hp, &gregs->stat);
HMD(("happy_meal_interrupt: status=%08lx ", happy_status));
@@ -1795,13 +2007,59 @@
HMD(("done\n"));
}
+#ifdef CONFIG_PCI
+static void pci_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct happy_meal *hp = (struct happy_meal *) dev->priv;
+ struct hmeal_gregs *gregs = hp->gregs;
+ struct hmeal_tcvregs *tregs = hp->tcvregs;
+ unsigned int happy_status = readl((unsigned long)&gregs->stat);
+
+ HMD(("happy_meal_interrupt: status=%08lx ", happy_status));
+
+ dev->interrupt = 1;
+
+ if(happy_status & GREG_STAT_ERRORS) {
+ HMD(("ERRORS "));
+ if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) {
+ dev->interrupt = 0;
+ return;
+ }
+ }
+
+ if(happy_status & GREG_STAT_MIFIRQ) {
+ HMD(("MIFIRQ "));
+ happy_meal_mif_interrupt(hp, gregs, tregs);
+ }
+
+ if(happy_status & GREG_STAT_TXALL) {
+ HMD(("TXALL "));
+ pci_happy_meal_tx(hp);
+ }
+
+ if(happy_status & GREG_STAT_RXTOHOST) {
+ HMD(("RXTOHOST "));
+ pci_happy_meal_rx(hp, dev, gregs);
+ }
+
+ if(dev->tbusy && (TX_BUFFS_AVAIL(hp) >= 0)) {
+ hp->dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+
+ dev->interrupt = 0;
+ HMD(("done\n"));
+}
+#endif
+
static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *) dev_id;
struct happy_meal *hp = (struct happy_meal *) dev->priv;
struct hmeal_gregs *gregs = hp->gregs;
struct hmeal_tcvregs *tregs = hp->tcvregs;
- unsigned long happy_status = gregs->stat;
+ unsigned int happy_status = hme_read32(hp, &gregs->stat);
HMD(("happy_meal_interrupt: status=%08lx ", happy_status));
@@ -1852,7 +2110,41 @@
printk("happy meal: Can't order irq %d to go.\n", dev->irq);
return -EAGAIN;
}
- } else {
+ }
+#ifdef __sparc_v9__
+ else if(sparc_cpu_model == sun4u) {
+ struct devid_cookie dcookie;
+
+#ifdef CONFIG_PCI
+ if(hp->happy_flags & HFLAG_PCI) {
+ if(request_irq(dev->irq, &pci_happy_meal_interrupt,
+ SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
+ HMD(("EAGAIN\n"));
+ printk("happy_meal(PCI: Can't order irq %d to go.\n",
+ dev->irq);
+ return -EAGAIN;
+ }
+ goto v9_done;
+ }
+#endif
+ dcookie.real_dev_id = dev;
+ dcookie.imap = dcookie.iclr = 0;
+ dcookie.pil = -1;
+ dcookie.bus_cookie = hp->happy_sbus_dev->my_bus;
+ if(request_irq(dev->irq, &happy_meal_interrupt,
+ (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
+ "HAPPY MEAL", &dcookie)) {
+ HMD(("EAGAIN\n"));
+ printk("happy_meal(SBUS): Can't order irq %d to go.\n",
+ dev->irq);
+ return -EAGAIN;
+ }
+#ifdef CONFIG_PCI
+ v9_done:
+#endif
+ }
+#endif
+ else {
if(request_irq(dev->irq, &happy_meal_interrupt,
SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
HMD(("EAGAIN\n"));
@@ -1874,8 +2166,12 @@
{
struct happy_meal *hp = (struct happy_meal *) dev->priv;
- happy_meal_stop(hp->gregs);
+ happy_meal_stop(hp, hp->gregs);
happy_meal_clean_rings(hp);
+
+ /* If auto-negotiation timer is running, kill it. */
+ del_timer(&hp->happy_timer);
+
free_irq(dev->irq, (void *)dev);
MOD_DEC_USE_COUNT;
return 0;
@@ -1917,15 +2213,14 @@
SXD(("SX<l[%d]e[%d]>", len, entry));
hp->tx_skbs[entry] = skb;
- hp->happy_block->happy_meal_txd[entry].tx_addr =
- (u32) ((unsigned long)skb->data);
+ hp->happy_block->happy_meal_txd[entry].tx_addr = kva_to_hva(hp, skb->data);
hp->happy_block->happy_meal_txd[entry].tx_flags =
(TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE));
hp->tx_new = NEXT_TX(entry);
/* Get it going. */
dev->trans_start = jiffies;
- hp->etxregs->tx_pnding = ETX_TP_DMAWAKEUP;
+ hme_write32(hp, &hp->etxregs->tx_pnding, ETX_TP_DMAWAKEUP);
if(TX_BUFFS_AVAIL(hp))
dev->tbusy = 0;
@@ -1933,6 +2228,56 @@
return 0;
}
+#ifdef CONFIG_PCI
+static int pci_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct happy_meal *hp = (struct happy_meal *) dev->priv;
+ int len, entry;
+
+ if(dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+
+ if (tickssofar < 40) {
+ return 1;
+ } else {
+ printk ("%s: transmit timed out, resetting\n", dev->name);
+ hp->net_stats.tx_errors++;
+ happy_meal_init(hp, 0);
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ return 0;
+ }
+ }
+
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
+ printk("happy meal: Transmitter access conflict.\n");
+ return 1;
+ }
+
+ if(!TX_BUFFS_AVAIL(hp))
+ return 1;
+
+ len = skb->len;
+ entry = hp->tx_new;
+
+ SXD(("SX<l[%d]e[%d]>", len, entry));
+ hp->tx_skbs[entry] = skb;
+ pcihme_write_txd(&hp->happy_block->happy_meal_txd[entry],
+ (TXFLAG_OWN|TXFLAG_SOP|TXFLAG_EOP|(len & TXFLAG_SIZE)),
+ (u32) virt_to_bus((volatile void *)skb->data));
+ hp->tx_new = NEXT_TX(entry);
+
+ /* Get it going. */
+ dev->trans_start = jiffies;
+ writel(ETX_TP_DMAWAKEUP, (unsigned long)&hp->etxregs->tx_pnding);
+
+ if(TX_BUFFS_AVAIL(hp))
+ dev->tbusy = 0;
+
+ return 0;
+}
+#endif
+
static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct happy_meal *hp = (struct happy_meal *) dev->priv;
@@ -2023,12 +2368,13 @@
set_bit(0, (void *) &dev->tbusy);
if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
- bregs->htable0 = 0xffff;
- bregs->htable1 = 0xffff;
- bregs->htable2 = 0xffff;
- bregs->htable3 = 0xffff;
+ hme_write32(hp, &bregs->htable0, 0xffff);
+ hme_write32(hp, &bregs->htable1, 0xffff);
+ hme_write32(hp, &bregs->htable2, 0xffff);
+ hme_write32(hp, &bregs->htable3, 0xffff);
} else if(dev->flags & IFF_PROMISC) {
- bregs->rx_cfg |= BIGMAC_RXCFG_PMISC;
+ hme_write32(hp, &bregs->rx_cfg,
+ hme_read32(hp, &bregs->rx_cfg) | BIGMAC_RXCFG_PMISC);
} else {
u16 hash_table[4];
@@ -2056,19 +2402,20 @@
crc >>= 26;
hash_table[crc >> 4] |= 1 << (crc & 0xf);
}
- bregs->htable0 = hash_table[0];
- bregs->htable1 = hash_table[1];
- bregs->htable2 = hash_table[2];
- bregs->htable3 = hash_table[3];
+ hme_write32(hp, &bregs->htable0, hash_table[0]);
+ hme_write32(hp, &bregs->htable1, hash_table[1]);
+ hme_write32(hp, &bregs->htable2, hash_table[2]);
+ hme_write32(hp, &bregs->htable3, hash_table[3]);
}
/* Let us get going again. */
dev->tbusy = 0;
}
+static unsigned hme_version_printed = 0;
+
static inline int happy_meal_ether_init(struct device *dev, struct linux_sbus_device *sdev)
{
- static unsigned version_printed = 0;
struct happy_meal *hp;
int i;
@@ -2079,10 +2426,10 @@
if(dev->priv == NULL)
return -ENOMEM;
}
- if(version_printed++ == 0)
+ if(hme_version_printed++ == 0)
printk(version);
- printk("%s: HAPPY MEAL 10/100baseT Ethernet ", dev->name);
+ printk("%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", dev->name);
dev->base_addr = (long) sdev;
for(i = 0; i < 6; i++)
@@ -2095,6 +2442,9 @@
memset(hp, 0, sizeof(*hp));
hp->happy_sbus_dev = sdev;
+#ifdef CONFIG_PCI
+ hp->happy_pci_dev = NULL;
+#endif
if(sdev->num_registers != 5) {
printk("happymeal: Device does not have 5 regs, it has %d.\n",
@@ -2211,6 +2561,124 @@
return 0;
}
+#ifdef CONFIG_PCI
+__initfunc(int happy_meal_pci_init(struct device *dev, struct pci_dev *pdev))
+{
+ struct pcidev_cookie *pcp;
+ struct happy_meal *hp;
+ unsigned long hpreg_base;
+ unsigned short pci_command;
+ int i, node;
+
+ if(dev == NULL) {
+ dev = init_etherdev(0, sizeof(struct happy_meal));
+ } else {
+ dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL);
+ if(dev->priv == NULL)
+ return -ENOMEM;
+ }
+ if(hme_version_printed++ == 0)
+ printk(version);
+
+ printk("%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", dev->name);
+
+ dev->base_addr = (long) pdev;
+ for(i = 0; i < 6; i++)
+ printk("%2.2x%c",
+ dev->dev_addr[i] = idprom->id_ethaddr[i],
+ i == 5 ? ' ' : ':');
+
+ printk("\n");
+
+ hp = (struct happy_meal *)dev->priv;
+ memset(hp, 0, sizeof(*hp));
+
+ hp->happy_sbus_dev = NULL;
+ hp->happy_pci_dev = pdev;
+
+ hpreg_base = pdev->base_address[0];
+ if((hpreg_base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ printk("happymeal(PCI): Cannot find proper PCI device base address.\n");
+ return ENODEV;
+ }
+ hpreg_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ /* Now make sure pci_dev cookie is there. */
+ pcp = pdev->sysdata;
+ if(pcp == NULL || pcp->prom_node == -1) {
+ printk("happymeal(PCI): Some PCI device info missing\n");
+ return ENODEV;
+ }
+ node = pcp->prom_node;
+
+ /* Layout registers. */
+ hp->gregs = (struct hmeal_gregs *) (hpreg_base + 0x0000);
+ hp->etxregs = (struct hmeal_etxregs *) (hpreg_base + 0x2000);
+ hp->erxregs = (struct hmeal_erxregs *) (hpreg_base + 0x4000);
+ hp->bigmacregs = (struct hmeal_bigmacregs *) (hpreg_base + 0x6000);
+ hp->tcvregs = (struct hmeal_tcvregs *) (hpreg_base + 0x7000);
+
+ hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
+ if(hp->hm_revision == 0xff)
+ hp->hm_revision = 0xa0;
+
+ /* Now enable the feature flags we can. */
+ if(hp->hm_revision == 0x20 || hp->hm_revision == 0x21)
+ hp->happy_flags = HFLAG_20_21;
+ else if(hp->hm_revision != 0xa0)
+ hp->happy_flags = HFLAG_NOT_A0;
+
+ /* And of course, indicate this is PCI. */
+ hp->happy_flags |= HFLAG_PCI;
+
+ /* Assume PCI happy meals can handle all burst sizes. */
+ hp->happy_bursts = DMA_BURSTBITS;
+
+ hp->happy_block = (struct hmeal_init_block *) get_free_page(GFP_DMA);
+ if(!hp->happy_block) {
+ printk("happymeal(PCI): Cannot get hme init block.\n");
+ return ENODEV;
+ }
+
+ hp->hblock_dvma = (u32) virt_to_bus(hp->happy_block);
+ hp->sun4c_buffers = 0;
+
+ hp->linkcheck = 0;
+ hp->timer_state = asleep;
+ hp->timer_ticks = 0;
+ happy_meal_set_initial_advertisement(hp);
+
+ hp->dev = dev;
+ dev->open = &happy_meal_open;
+ dev->stop = &happy_meal_close;
+ dev->hard_start_xmit = &pci_happy_meal_start_xmit;
+ dev->get_stats = &happy_meal_get_stats;
+ dev->set_multicast_list = &happy_meal_set_multicast;
+ dev->irq = pdev->irq;
+ dev->dma = 0;
+ ether_setup(dev);
+
+ /* If we don't do this, nothing works. */
+ pcibios_read_config_word(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, pci_command);
+
+#ifdef MODULE
+ /* We are home free at this point, link us in to the happy
+ * module device list.
+ */
+ dev->ifindex = dev_new_index();
+ hp->next_module = root_happy_dev;
+ root_happy_dev = hp;
+#endif
+ return 0;
+}
+#endif
+
__initfunc(int happy_meal_probe(struct device *dev))
{
struct linux_sbus *bus;
@@ -2224,7 +2692,8 @@
for_each_sbus(bus) {
for_each_sbusdev(sdev, bus) {
- if(cards) dev = NULL;
+ if(cards)
+ dev = NULL;
if(!strcmp(sdev->prom_name, "SUNW,hme")) {
cards++;
if((v = happy_meal_ether_init(dev, sdev)))
@@ -2232,6 +2701,23 @@
}
}
}
+#ifdef CONFIG_PCI
+ if(pcibios_present()) {
+ struct pci_dev *pdev;
+
+ for(pdev = pci_devices; pdev; pdev = pdev->next) {
+ if(cards)
+ dev = NULL;
+ if((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL)) {
+ cards++;
+ if((v = happy_meal_pci_init(dev, pdev)))
+ return v;
+ }
+
+ }
+ }
+#endif
if(!cards)
return ENODEV;
return 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov