Merge refs/heads/upstream from master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6

This commit is contained in:
Linus Torvalds 2005-08-29 10:04:37 -07:00
Родитель 5be1d85c20 e13934563d
Коммит 3d963f5bb1
59 изменённых файлов: 8155 добавлений и 3771 удалений

Просмотреть файл

@ -0,0 +1,288 @@
-------
PHY Abstraction Layer
(Updated 2005-07-21)
Purpose
Most network devices consist of set of registers which provide an interface
to a MAC layer, which communicates with the physical connection through a
PHY. The PHY concerns itself with negotiating link parameters with the link
partner on the other side of the network connection (typically, an ethernet
cable), and provides a register interface to allow drivers to determine what
settings were chosen, and to configure what settings are allowed.
While these devices are distinct from the network devices, and conform to a
standard layout for the registers, it has been common practice to integrate
the PHY management code with the network driver. This has resulted in large
amounts of redundant code. Also, on embedded systems with multiple (and
sometimes quite different) ethernet controllers connected to the same
management bus, it is difficult to ensure safe use of the bus.
Since the PHYs are devices, and the management busses through which they are
accessed are, in fact, busses, the PHY Abstraction Layer treats them as such.
In doing so, it has these goals:
1) Increase code-reuse
2) Increase overall code-maintainability
3) Speed development time for new network drivers, and for new systems
Basically, this layer is meant to provide an interface to PHY devices which
allows network driver writers to write as little code as possible, while
still providing a full feature set.
The MDIO bus
Most network devices are connected to a PHY by means of a management bus.
Different devices use different busses (though some share common interfaces).
In order to take advantage of the PAL, each bus interface needs to be
registered as a distinct device.
1) read and write functions must be implemented. Their prototypes are:
int write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
int read(struct mii_bus *bus, int mii_id, int regnum);
mii_id is the address on the bus for the PHY, and regnum is the register
number. These functions are guaranteed not to be called from interrupt
time, so it is safe for them to block, waiting for an interrupt to signal
the operation is complete
2) A reset function is necessary. This is used to return the bus to an
initialized state.
3) A probe function is needed. This function should set up anything the bus
driver needs, setup the mii_bus structure, and register with the PAL using
mdiobus_register. Similarly, there's a remove function to undo all of
that (use mdiobus_unregister).
4) Like any driver, the device_driver structure must be configured, and init
exit functions are used to register the driver.
5) The bus must also be declared somewhere as a device, and registered.
As an example for how one driver implemented an mdio bus driver, see
drivers/net/gianfar_mii.c and arch/ppc/syslib/mpc85xx_devices.c
Connecting to a PHY
Sometime during startup, the network driver needs to establish a connection
between the PHY device, and the network device. At this time, the PHY's bus
and drivers need to all have been loaded, so it is ready for the connection.
At this point, there are several ways to connect to the PHY:
1) The PAL handles everything, and only calls the network driver when
the link state changes, so it can react.
2) The PAL handles everything except interrupts (usually because the
controller has the interrupt registers).
3) The PAL handles everything, but checks in with the driver every second,
allowing the network driver to react first to any changes before the PAL
does.
4) The PAL serves only as a library of functions, with the network device
manually calling functions to update status, and configure the PHY
Letting the PHY Abstraction Layer do Everything
If you choose option 1 (The hope is that every driver can, but to still be
useful to drivers that can't), connecting to the PHY is simple:
First, you need a function to react to changes in the link state. This
function follows this protocol:
static void adjust_link(struct net_device *dev);
Next, you need to know the device name of the PHY connected to this device.
The name will look something like, "phy0:0", where the first number is the
bus id, and the second is the PHY's address on that bus.
Now, to connect, just call this function:
phydev = phy_connect(dev, phy_name, &adjust_link, flags);
phydev is a pointer to the phy_device structure which represents the PHY. If
phy_connect is successful, it will return the pointer. dev, here, is the
pointer to your net_device. Once done, this function will have started the
PHY's software state machine, and registered for the PHY's interrupt, if it
has one. The phydev structure will be populated with information about the
current state, though the PHY will not yet be truly operational at this
point.
flags is a u32 which can optionally contain phy-specific flags.
This is useful if the system has put hardware restrictions on
the PHY/controller, of which the PHY needs to be aware.
Now just make sure that phydev->supported and phydev->advertising have any
values pruned from them which don't make sense for your controller (a 10/100
controller may be connected to a gigabit capable PHY, so you would need to
mask off SUPPORTED_1000baseT*). See include/linux/ethtool.h for definitions
for these bitfields. Note that you should not SET any bits, or the PHY may
get put into an unsupported state.
Lastly, once the controller is ready to handle network traffic, you call
phy_start(phydev). This tells the PAL that you are ready, and configures the
PHY to connect to the network. If you want to handle your own interrupts,
just set phydev->irq to PHY_IGNORE_INTERRUPT before you call phy_start.
Similarly, if you don't want to use interrupts, set phydev->irq to PHY_POLL.
When you want to disconnect from the network (even if just briefly), you call
phy_stop(phydev).
Keeping Close Tabs on the PAL
It is possible that the PAL's built-in state machine needs a little help to
keep your network device and the PHY properly in sync. If so, you can
register a helper function when connecting to the PHY, which will be called
every second before the state machine reacts to any changes. To do this, you
need to manually call phy_attach() and phy_prepare_link(), and then call
phy_start_machine() with the second argument set to point to your special
handler.
Currently there are no examples of how to use this functionality, and testing
on it has been limited because the author does not have any drivers which use
it (they all use option 1). So Caveat Emptor.
Doing it all yourself
There's a remote chance that the PAL's built-in state machine cannot track
the complex interactions between the PHY and your network device. If this is
so, you can simply call phy_attach(), and not call phy_start_machine or
phy_prepare_link(). This will mean that phydev->state is entirely yours to
handle (phy_start and phy_stop toggle between some of the states, so you
might need to avoid them).
An effort has been made to make sure that useful functionality can be
accessed without the state-machine running, and most of these functions are
descended from functions which did not interact with a complex state-machine.
However, again, no effort has been made so far to test running without the
state machine, so tryer beware.
Here is a brief rundown of the functions:
int phy_read(struct phy_device *phydev, u16 regnum);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
Simple read/write primitives. They invoke the bus's read/write function
pointers.
void phy_print_status(struct phy_device *phydev);
A convenience function to print out the PHY status neatly.
int phy_clear_interrupt(struct phy_device *phydev);
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
Clear the PHY's interrupt, and configure which ones are allowed,
respectively. Currently only supports all on, or all off.
int phy_enable_interrupts(struct phy_device *phydev);
int phy_disable_interrupts(struct phy_device *phydev);
Functions which enable/disable PHY interrupts, clearing them
before and after, respectively.
int phy_start_interrupts(struct phy_device *phydev);
int phy_stop_interrupts(struct phy_device *phydev);
Requests the IRQ for the PHY interrupts, then enables them for
start, or disables then frees them for stop.
struct phy_device * phy_attach(struct net_device *dev, const char *phy_id,
u32 flags);
Attaches a network device to a particular PHY, binding the PHY to a generic
driver if none was found during bus initialization. Passes in
any phy-specific flags as needed.
int phy_start_aneg(struct phy_device *phydev);
Using variables inside the phydev structure, either configures advertising
and resets autonegotiation, or disables autonegotiation, and configures
forced settings.
static inline int phy_read_status(struct phy_device *phydev);
Fills the phydev structure with up-to-date information about the current
settings in the PHY.
void phy_sanitize_settings(struct phy_device *phydev)
Resolves differences between currently desired settings, and
supported settings for the given PHY device. Does not make
the changes in the hardware, though.
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
Ethtool convenience functions.
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd);
The MII ioctl. Note that this function will completely screw up the state
machine if you write registers like BMCR, BMSR, ADVERTISE, etc. Best to
use this only to write registers which are not standard, and don't set off
a renegotiation.
PHY Device Drivers
With the PHY Abstraction Layer, adding support for new PHYs is
quite easy. In some cases, no work is required at all! However,
many PHYs require a little hand-holding to get up-and-running.
Generic PHY driver
If the desired PHY doesn't have any errata, quirks, or special
features you want to support, then it may be best to not add
support, and let the PHY Abstraction Layer's Generic PHY Driver
do all of the work.
Writing a PHY driver
If you do need to write a PHY driver, the first thing to do is
make sure it can be matched with an appropriate PHY device.
This is done during bus initialization by reading the device's
UID (stored in registers 2 and 3), then comparing it to each
driver's phy_id field by ANDing it with each driver's
phy_id_mask field. Also, it needs a name. Here's an example:
static struct phy_driver dm9161_driver = {
.phy_id = 0x0181b880,
.name = "Davicom DM9161E",
.phy_id_mask = 0x0ffffff0,
...
}
Next, you need to specify what features (speed, duplex, autoneg,
etc) your PHY device and driver support. Most PHYs support
PHY_BASIC_FEATURES, but you can look in include/mii.h for other
features.
Each driver consists of a number of function pointers:
config_init: configures PHY into a sane state after a reset.
For instance, a Davicom PHY requires descrambling disabled.
probe: Does any setup needed by the driver
suspend/resume: power management
config_aneg: Changes the speed/duplex/negotiation settings
read_status: Reads the current speed/duplex/negotiation settings
ack_interrupt: Clear a pending interrupt
config_intr: Enable or disable interrupts
remove: Does any driver take-down
Of these, only config_aneg and read_status are required to be
assigned by the driver code. The rest are optional. Also, it is
preferred to use the generic phy driver's versions of these two
functions if at all possible: genphy_read_status and
genphy_config_aneg. If this is not possible, it is likely that
you only need to perform some actions before and after invoking
these functions, and so your functions will wrap the generic
ones.
Feel free to look at the Marvell, Cicada, and Davicom drivers in
drivers/net/phy/ for examples (the lxt and qsemi drivers have
not been tested as of this writing)

Просмотреть файл

@ -131,6 +131,8 @@ config NET_SB1000
source "drivers/net/arcnet/Kconfig"
source "drivers/net/phy/Kconfig"
#
# Ethernet
#

Просмотреть файл

@ -65,6 +65,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
#
obj-$(CONFIG_MII) += mii.o
obj-$(CONFIG_PHYLIB) += phy/
obj-$(CONFIG_SUNDANCE) += sundance.o
obj-$(CONFIG_HAMACHI) += hamachi.o

Просмотреть файл

@ -87,7 +87,6 @@ extern struct net_device *mvme147lance_probe(int unit);
extern struct net_device *tc515_probe(int unit);
extern struct net_device *lance_probe(int unit);
extern struct net_device *mace_probe(int unit);
extern struct net_device *macsonic_probe(int unit);
extern struct net_device *mac8390_probe(int unit);
extern struct net_device *mac89x0_probe(int unit);
extern struct net_device *mc32_probe(int unit);
@ -284,9 +283,6 @@ static struct devprobe2 m68k_probes[] __initdata = {
#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */
{mace_probe, 0},
#endif
#ifdef CONFIG_MACSONIC /* Mac SONIC-based Ethernet of all sorts */
{macsonic_probe, 0},
#endif
#ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */
{mac8390_probe, 0},
#endif
@ -318,17 +314,9 @@ static void __init ethif_probe2(int unit)
#ifdef CONFIG_TR
/* Token-ring device probe */
extern int ibmtr_probe_card(struct net_device *);
extern struct net_device *sk_isa_probe(int unit);
extern struct net_device *proteon_probe(int unit);
extern struct net_device *smctr_probe(int unit);
static struct devprobe2 tr_probes2[] __initdata = {
#ifdef CONFIG_SKISA
{sk_isa_probe, 0},
#endif
#ifdef CONFIG_PROTEON
{proteon_probe, 0},
#endif
#ifdef CONFIG_SMCTR
{smctr_probe, 0},
#endif

Просмотреть файл

@ -1106,18 +1106,13 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
}
}
if (found) {
/* a slave was found that is using the mac address
* of the new slave
*/
printk(KERN_ERR DRV_NAME
": Error: the hw address of slave %s is not "
"unique - cannot enslave it!",
slave->dev->name);
return -EINVAL;
}
if (!found)
return 0;
return 0;
/* Try setting slave mac to bond address and fall-through
to code handling that situation below... */
alb_set_slave_mac_addr(slave, bond->dev->dev_addr,
bond->alb_info.rlb_enabled);
}
/* The slave's address is equal to the address of the bond.

Просмотреть файл

@ -1604,6 +1604,44 @@ static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_
return 0;
}
#define BOND_INTERSECT_FEATURES \
(NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
/*
* Compute the features available to the bonding device by
* intersection of all of the slave devices' BOND_INTERSECT_FEATURES.
* Call this after attaching or detaching a slave to update the
* bond's features.
*/
static int bond_compute_features(struct bonding *bond)
{
int i;
struct slave *slave;
struct net_device *bond_dev = bond->dev;
int features = bond->bond_features;
bond_for_each_slave(bond, slave, i) {
struct net_device * slave_dev = slave->dev;
if (i == 0) {
features |= BOND_INTERSECT_FEATURES;
}
features &=
~(~slave_dev->features & BOND_INTERSECT_FEATURES);
}
/* turn off NETIF_F_SG if we need a csum and h/w can't do it */
if ((features & NETIF_F_SG) &&
!(features & (NETIF_F_IP_CSUM |
NETIF_F_NO_CSUM |
NETIF_F_HW_CSUM))) {
features &= ~NETIF_F_SG;
}
bond_dev->features = features;
return 0;
}
/* enslave device <slave> to bond device <master> */
static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
{
@ -1811,6 +1849,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
new_slave->delay = 0;
new_slave->link_failure_count = 0;
bond_compute_features(bond);
if (bond->params.miimon && !bond->params.use_carrier) {
link_reporting = bond_check_dev_link(bond, slave_dev, 1);
@ -2015,7 +2055,7 @@ err_free:
err_undo_flags:
bond_dev->features = old_features;
return res;
}
@ -2100,6 +2140,8 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
/* release the slave from its bond */
bond_detach_slave(bond, slave);
bond_compute_features(bond);
if (bond->primary_slave == slave) {
bond->primary_slave = NULL;
}
@ -2243,6 +2285,8 @@ static int bond_release_all(struct net_device *bond_dev)
bond_alb_deinit_slave(bond, slave);
}
bond_compute_features(bond);
/* now that the slave is detached, unlock and perform
* all the undo steps that should not be called from
* within a lock.
@ -3588,6 +3632,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond
static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev)
{
struct net_device *bond_dev = slave_dev->master;
struct bonding *bond = bond_dev->priv;
switch (event) {
case NETDEV_UNREGISTER:
@ -3626,6 +3671,9 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
* TODO: handle changing the primary's name
*/
break;
case NETDEV_FEAT_CHANGE:
bond_compute_features(bond);
break;
default:
break;
}
@ -4526,6 +4574,11 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode)
}
}
static struct ethtool_ops bond_ethtool_ops = {
.get_tx_csum = ethtool_op_get_tx_csum,
.get_sg = ethtool_op_get_sg,
};
/*
* Does not allocate but creates a /proc entry.
* Allowed to fail.
@ -4555,6 +4608,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
bond_dev->stop = bond_close;
bond_dev->get_stats = bond_get_stats;
bond_dev->do_ioctl = bond_do_ioctl;
bond_dev->ethtool_ops = &bond_ethtool_ops;
bond_dev->set_multicast_list = bond_set_multicast_list;
bond_dev->change_mtu = bond_change_mtu;
bond_dev->set_mac_address = bond_set_mac_address;
@ -4591,6 +4645,8 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER);
bond->bond_features = bond_dev->features;
#ifdef CONFIG_PROC_FS
bond_create_proc_entry(bond);
#endif

Просмотреть файл

@ -211,6 +211,9 @@ struct bonding {
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
/* the features the bonding device supports, independently
* of any slaves */
int bond_features;
};
/**

Просмотреть файл

@ -2767,7 +2767,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
" next_to_use <%x>\n"
" next_to_clean <%x>\n"
"buffer_info[next_to_clean]\n"
" dma <%zx>\n"
" dma <%llx>\n"
" time_stamp <%lx>\n"
" next_to_watch <%x>\n"
" jiffies <%lx>\n"
@ -2776,7 +2776,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
E1000_READ_REG(&adapter->hw, TDT),
tx_ring->next_to_use,
i,
tx_ring->buffer_info[i].dma,
(unsigned long long)tx_ring->buffer_info[i].dma,
tx_ring->buffer_info[i].time_stamp,
eop,
jiffies,

Просмотреть файл

@ -1263,8 +1263,8 @@ speedo_init_rx_ring(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb;
skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
/* XXX: do we really want to call this before the NULL check? --hch */
rx_align(skb); /* Align IP on 16 byte boundary */
if (skb)
rx_align(skb); /* Align IP on 16 byte boundary */
sp->rx_skbuff[i] = skb;
if (skb == NULL)
break; /* OK. Just initially short of Rx bufs. */
@ -1654,8 +1654,8 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
struct sk_buff *skb;
/* Get a fresh skbuff to replace the consumed one. */
skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
/* XXX: do we really want to call this before the NULL check? --hch */
rx_align(skb); /* Align IP on 16 byte boundary */
if (skb)
rx_align(skb); /* Align IP on 16 byte boundary */
sp->rx_skbuff[entry] = skb;
if (skb == NULL) {
sp->rx_ringp[entry] = NULL;

Просмотреть файл

@ -85,6 +85,16 @@
* 0.33: 16 May 2005: Support for MCP51 added.
* 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
* 0.35: 26 Jun 2005: Support for MCP55 added.
* 0.36: 28 Jun 2005: Add jumbo frame support.
* 0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list
* 0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of
* per-packet flags.
* 0.39: 18 Jul 2005: Add 64bit descriptor support.
* 0.40: 19 Jul 2005: Add support for mac address change.
* 0.41: 30 Jul 2005: Write back original MAC in nv_close instead
* of nv_remove
* 0.42: 06 Aug 2005: Fix lack of link speed initialization
* in the second (and later) nv_open call
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@ -96,7 +106,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
#define FORCEDETH_VERSION "0.35"
#define FORCEDETH_VERSION "0.41"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@ -131,11 +141,10 @@
* Hardware access:
*/
#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */
#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */
#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */
#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */
#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */
#define DEV_NEED_TIMERIRQ 0x0001 /* set the timer irq flag in the irq mask */
#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */
#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */
#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */
enum {
NvRegIrqStatus = 0x000,
@ -146,13 +155,16 @@ enum {
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERR 0x0008
#define NVREG_IRQ_TX2 0x0010
#define NVREG_IRQ_TX_OK 0x0010
#define NVREG_IRQ_TIMER 0x0020
#define NVREG_IRQ_LINK 0x0040
#define NVREG_IRQ_TX_ERROR 0x0080
#define NVREG_IRQ_TX1 0x0100
#define NVREG_IRQMASK_WANTED_1 0x005f
#define NVREG_IRQMASK_WANTED_2 0x0147
#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
#define NVREG_IRQMASK_WANTED 0x00df
#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \
NVREG_IRQ_TX1))
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
@ -286,6 +298,18 @@ struct ring_desc {
u32 FlagLen;
};
struct ring_desc_ex {
u32 PacketBufferHigh;
u32 PacketBufferLow;
u32 Reserved;
u32 FlagLen;
};
typedef union _ring_type {
struct ring_desc* orig;
struct ring_desc_ex* ex;
} ring_type;
#define FLAG_MASK_V1 0xffff0000
#define FLAG_MASK_V2 0xffffc000
#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
@ -293,7 +317,7 @@ struct ring_desc {
#define NV_TX_LASTPACKET (1<<16)
#define NV_TX_RETRYERROR (1<<19)
#define NV_TX_LASTPACKET1 (1<<24)
#define NV_TX_FORCED_INTERRUPT (1<<24)
#define NV_TX_DEFERRED (1<<26)
#define NV_TX_CARRIERLOST (1<<27)
#define NV_TX_LATECOLLISION (1<<28)
@ -303,7 +327,7 @@ struct ring_desc {
#define NV_TX2_LASTPACKET (1<<29)
#define NV_TX2_RETRYERROR (1<<18)
#define NV_TX2_LASTPACKET1 (1<<23)
#define NV_TX2_FORCED_INTERRUPT (1<<30)
#define NV_TX2_DEFERRED (1<<25)
#define NV_TX2_CARRIERLOST (1<<26)
#define NV_TX2_LATECOLLISION (1<<27)
@ -379,9 +403,13 @@ struct ring_desc {
#define TX_LIMIT_START 62
/* rx/tx mac addr + type + vlan + align + slack*/
#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64)
/* even more slack */
#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128)
#define NV_RX_HEADERS (64)
/* even more slack. */
#define NV_RX_ALLOC_PAD (64)
/* maximum mtu size */
#define NV_PKTLIMIT_1 ETH_DATA_LEN /* hard limit not known */
#define NV_PKTLIMIT_2 9100 /* Actual limit according to NVidia: 9202 */
#define OOM_REFILL (1+HZ/20)
#define POLL_WAIT (1+HZ/100)
@ -396,6 +424,7 @@ struct ring_desc {
*/
#define DESC_VER_1 0x0
#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK)
/* PHY defines */
#define PHY_OUI_MARVELL 0x5043
@ -468,11 +497,12 @@ struct fe_priv {
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
struct ring_desc *rx_ring;
ring_type rx_ring;
unsigned int cur_rx, refill_rx;
struct sk_buff *rx_skbuff[RX_RING];
dma_addr_t rx_dma[RX_RING];
unsigned int rx_buf_sz;
unsigned int pkt_limit;
struct timer_list oom_kick;
struct timer_list nic_poll;
@ -484,7 +514,7 @@ struct fe_priv {
/*
* tx specific fields.
*/
struct ring_desc *tx_ring;
ring_type tx_ring;
unsigned int next_tx, nic_tx;
struct sk_buff *tx_skbuff[TX_RING];
dma_addr_t tx_dma[TX_RING];
@ -519,6 +549,11 @@ static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
& ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
}
static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
{
return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
}
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
int delay, int delaymax, const char *msg)
{
@ -792,7 +827,7 @@ static int nv_alloc_rx(struct net_device *dev)
nr = refill_rx % RX_RING;
if (np->rx_skbuff[nr] == NULL) {
skb = dev_alloc_skb(RX_ALLOC_BUFSIZE);
skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
if (!skb)
break;
@ -803,9 +838,16 @@ static int nv_alloc_rx(struct net_device *dev)
}
np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len,
PCI_DMA_FROMDEVICE);
np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
wmb();
np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
wmb();
np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
} else {
np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
wmb();
np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
}
dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
dev->name, refill_rx);
refill_rx++;
@ -831,19 +873,37 @@ static void nv_do_rx_refill(unsigned long data)
enable_irq(dev->irq);
}
static int nv_init_ring(struct net_device *dev)
static void nv_init_rx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int i;
np->cur_rx = RX_RING;
np->refill_rx = 0;
for (i = 0; i < RX_RING; i++)
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->rx_ring.orig[i].FlagLen = 0;
else
np->rx_ring.ex[i].FlagLen = 0;
}
static void nv_init_tx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int i;
np->next_tx = np->nic_tx = 0;
for (i = 0; i < TX_RING; i++)
np->tx_ring[i].FlagLen = 0;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
np->tx_ring.ex[i].FlagLen = 0;
}
np->cur_rx = RX_RING;
np->refill_rx = 0;
for (i = 0; i < RX_RING; i++)
np->rx_ring[i].FlagLen = 0;
static int nv_init_ring(struct net_device *dev)
{
nv_init_tx(dev);
nv_init_rx(dev);
return nv_alloc_rx(dev);
}
@ -852,7 +912,10 @@ static void nv_drain_tx(struct net_device *dev)
struct fe_priv *np = get_nvpriv(dev);
int i;
for (i = 0; i < TX_RING; i++) {
np->tx_ring[i].FlagLen = 0;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
np->tx_ring.ex[i].FlagLen = 0;
if (np->tx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->tx_dma[i],
np->tx_skbuff[i]->len,
@ -869,7 +932,10 @@ static void nv_drain_rx(struct net_device *dev)
struct fe_priv *np = get_nvpriv(dev);
int i;
for (i = 0; i < RX_RING; i++) {
np->rx_ring[i].FlagLen = 0;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->rx_ring.orig[i].FlagLen = 0;
else
np->rx_ring.ex[i].FlagLen = 0;
wmb();
if (np->rx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->rx_dma[i],
@ -900,11 +966,19 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
PCI_DMA_TODEVICE);
np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
else {
np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
}
spin_lock_irq(&np->lock);
wmb();
np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
else
np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n",
dev->name, np->next_tx);
{
@ -942,7 +1016,10 @@ static void nv_tx_done(struct net_device *dev)
while (np->nic_tx != np->next_tx) {
i = np->nic_tx % TX_RING;
Flags = le32_to_cpu(np->tx_ring[i].FlagLen);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
else
Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
dev->name, np->nic_tx, Flags);
@ -993,9 +1070,56 @@ static void nv_tx_timeout(struct net_device *dev)
struct fe_priv *np = get_nvpriv(dev);
u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name,
printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK);
{
int i;
printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
dev->name, (unsigned long)np->ring_addr,
np->next_tx, np->nic_tx);
printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
for (i=0;i<0x400;i+= 32) {
printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
i,
readl(base + i + 0), readl(base + i + 4),
readl(base + i + 8), readl(base + i + 12),
readl(base + i + 16), readl(base + i + 20),
readl(base + i + 24), readl(base + i + 28));
}
printk(KERN_INFO "%s: Dumping tx ring\n", dev->name);
for (i=0;i<TX_RING;i+= 4) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
i,
le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
le32_to_cpu(np->tx_ring.orig[i].FlagLen),
le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
} else {
printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
i,
le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
le32_to_cpu(np->tx_ring.ex[i].FlagLen),
le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
}
}
}
spin_lock_irq(&np->lock);
/* 1) stop tx engine */
@ -1009,7 +1133,10 @@ static void nv_tx_timeout(struct net_device *dev)
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
nv_drain_tx(dev);
np->next_tx = np->nic_tx = 0;
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
else
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
netif_wake_queue(dev);
}
@ -1084,8 +1211,13 @@ static void nv_rx_process(struct net_device *dev)
break; /* we scanned the whole ring - do not continue */
i = np->cur_rx % RX_RING;
Flags = le32_to_cpu(np->rx_ring[i].FlagLen);
len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
} else {
Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
}
dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
dev->name, np->cur_rx, Flags);
@ -1207,15 +1339,133 @@ next_pkt:
}
}
static void set_bufsize(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
if (dev->mtu <= ETH_DATA_LEN)
np->rx_buf_sz = ETH_DATA_LEN + NV_RX_HEADERS;
else
np->rx_buf_sz = dev->mtu + NV_RX_HEADERS;
}
/*
* nv_change_mtu: dev->change_mtu function
* Called with dev_base_lock held for read.
*/
static int nv_change_mtu(struct net_device *dev, int new_mtu)
{
if (new_mtu > ETH_DATA_LEN)
struct fe_priv *np = get_nvpriv(dev);
int old_mtu;
if (new_mtu < 64 || new_mtu > np->pkt_limit)
return -EINVAL;
old_mtu = dev->mtu;
dev->mtu = new_mtu;
/* return early if the buffer sizes will not change */
if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN)
return 0;
if (old_mtu == new_mtu)
return 0;
/* synchronized against open : rtnl_lock() held by caller */
if (netif_running(dev)) {
u8 *base = get_hwbase(dev);
/*
* It seems that the nic preloads valid ring entries into an
* internal buffer. The procedure for flushing everything is
* guessed, there is probably a simpler approach.
* Changing the MTU is a rare event, it shouldn't matter.
*/
disable_irq(dev->irq);
spin_lock_bh(&dev->xmit_lock);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
nv_txrx_reset(dev);
/* drain rx queue */
nv_drain_rx(dev);
nv_drain_tx(dev);
/* reinit driver view of the rx queue */
nv_init_rx(dev);
nv_init_tx(dev);
/* alloc new rx buffers */
set_bufsize(dev);
if (nv_alloc_rx(dev)) {
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
}
/* reinit nic view of the rx queue */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
else
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
pci_push(base);
/* restart rx engine */
nv_start_rx(dev);
nv_start_tx(dev);
spin_unlock(&np->lock);
spin_unlock_bh(&dev->xmit_lock);
enable_irq(dev->irq);
}
return 0;
}
static void nv_copy_mac_to_hw(struct net_device *dev)
{
u8 *base = get_hwbase(dev);
u32 mac[2];
mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
(dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
writel(mac[0], base + NvRegMacAddrA);
writel(mac[1], base + NvRegMacAddrB);
}
/*
* nv_set_mac_address: dev->set_mac_address function
* Called with rtnl_lock() held.
*/
static int nv_set_mac_address(struct net_device *dev, void *addr)
{
struct fe_priv *np = get_nvpriv(dev);
struct sockaddr *macaddr = (struct sockaddr*)addr;
if(!is_valid_ether_addr(macaddr->sa_data))
return -EADDRNOTAVAIL;
/* synchronized against open : rtnl_lock() held by caller */
memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
if (netif_running(dev)) {
spin_lock_bh(&dev->xmit_lock);
spin_lock_irq(&np->lock);
/* stop rx engine */
nv_stop_rx(dev);
/* set mac address */
nv_copy_mac_to_hw(dev);
/* restart rx engine */
nv_start_rx(dev);
spin_unlock_irq(&np->lock);
spin_unlock_bh(&dev->xmit_lock);
} else {
nv_copy_mac_to_hw(dev);
}
return 0;
}
@ -1470,7 +1720,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
if (!(events & np->irqmask))
break;
if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) {
spin_lock(&np->lock);
nv_tx_done(dev);
spin_unlock(&np->lock);
@ -1761,6 +2011,50 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return 0;
}
#define FORCEDETH_REGS_VER 1
#define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */
static int nv_get_regs_len(struct net_device *dev)
{
return FORCEDETH_REGS_SIZE;
}
static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
{
struct fe_priv *np = get_nvpriv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 *rbuf = buf;
int i;
regs->version = FORCEDETH_REGS_VER;
spin_lock_irq(&np->lock);
for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++)
rbuf[i] = readl(base + i*sizeof(u32));
spin_unlock_irq(&np->lock);
}
static int nv_nway_reset(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
int ret;
spin_lock_irq(&np->lock);
if (np->autoneg) {
int bmcr;
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
ret = 0;
} else {
ret = -EINVAL;
}
spin_unlock_irq(&np->lock);
return ret;
}
static struct ethtool_ops ops = {
.get_drvinfo = nv_get_drvinfo,
.get_link = ethtool_op_get_link,
@ -1768,6 +2062,9 @@ static struct ethtool_ops ops = {
.set_wol = nv_set_wol,
.get_settings = nv_get_settings,
.set_settings = nv_set_settings,
.get_regs_len = nv_get_regs_len,
.get_regs = nv_get_regs,
.nway_reset = nv_nway_reset,
};
static int nv_open(struct net_device *dev)
@ -1792,6 +2089,7 @@ static int nv_open(struct net_device *dev)
writel(0, base + NvRegAdapterControl);
/* 2) initialize descriptor rings */
set_bufsize(dev);
oom = nv_init_ring(dev);
writel(0, base + NvRegLinkSpeed);
@ -1802,20 +2100,14 @@ static int nv_open(struct net_device *dev)
np->in_shutdown = 0;
/* 3) set mac address */
{
u32 mac[2];
mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
(dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
writel(mac[0], base + NvRegMacAddrA);
writel(mac[1], base + NvRegMacAddrB);
}
nv_copy_mac_to_hw(dev);
/* 4) give hw rings */
writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
else
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
@ -1837,7 +2129,7 @@ static int nv_open(struct net_device *dev)
writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig);
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
get_random_bytes(&i, sizeof(i));
@ -1888,6 +2180,9 @@ static int nv_open(struct net_device *dev)
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
}
/* set linkspeed to invalid value, thus force nv_update_linkspeed
* to init hw */
np->linkspeed = 0;
ret = nv_update_linkspeed(dev);
nv_start_rx(dev);
nv_start_tx(dev);
@ -1942,6 +2237,12 @@ static int nv_close(struct net_device *dev)
if (np->wolenabled)
nv_start_rx(dev);
/* special op: write back the misordered MAC address - otherwise
* the next nv_probe would see a wrong address.
*/
writel(np->orig_mac[0], base + NvRegMacAddrA);
writel(np->orig_mac[1], base + NvRegMacAddrB);
/* FIXME: power down nic */
return 0;
@ -2006,32 +2307,55 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
}
/* handle different descriptor versions */
if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||
pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
np->desc_ver = DESC_VER_1;
else
if (id->driver_data & DEV_HAS_HIGH_DMA) {
/* packet format 3: supports 40-bit addressing */
np->desc_ver = DESC_VER_3;
if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
pci_name(pci_dev));
}
} else if (id->driver_data & DEV_HAS_LARGEDESC) {
/* packet format 2: supports jumbo frames */
np->desc_ver = DESC_VER_2;
} else {
/* original packet format */
np->desc_ver = DESC_VER_1;
}
np->pkt_limit = NV_PKTLIMIT_1;
if (id->driver_data & DEV_HAS_LARGEDESC)
np->pkt_limit = NV_PKTLIMIT_2;
err = -ENOMEM;
np->base = ioremap(addr, NV_PCI_REGSZ);
if (!np->base)
goto out_relreg;
dev->base_addr = (unsigned long)np->base;
dev->irq = pci_dev->irq;
np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
&np->ring_addr);
if (!np->rx_ring)
goto out_unmap;
np->tx_ring = &np->rx_ring[RX_RING];
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = pci_alloc_consistent(pci_dev,
sizeof(struct ring_desc) * (RX_RING + TX_RING),
&np->ring_addr);
if (!np->rx_ring.orig)
goto out_unmap;
np->tx_ring.orig = &np->rx_ring.orig[RX_RING];
} else {
np->rx_ring.ex = pci_alloc_consistent(pci_dev,
sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
&np->ring_addr);
if (!np->rx_ring.ex)
goto out_unmap;
np->tx_ring.ex = &np->rx_ring.ex[RX_RING];
}
dev->open = nv_open;
dev->stop = nv_close;
dev->hard_start_xmit = nv_start_xmit;
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_mac_address = nv_set_mac_address;
dev->set_multicast_list = nv_set_multicast;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
@ -2080,17 +2404,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (np->desc_ver == DESC_VER_1) {
np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID;
if (id->driver_data & DEV_NEED_LASTPACKET1)
np->tx_flags |= NV_TX_LASTPACKET1;
} else {
np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID;
if (id->driver_data & DEV_NEED_LASTPACKET1)
np->tx_flags |= NV_TX2_LASTPACKET1;
}
if (id->driver_data & DEV_IRQMASK_1)
np->irqmask = NVREG_IRQMASK_WANTED_1;
if (id->driver_data & DEV_IRQMASK_2)
np->irqmask = NVREG_IRQMASK_WANTED_2;
np->irqmask = NVREG_IRQMASK_WANTED;
if (id->driver_data & DEV_NEED_TIMERIRQ)
np->irqmask |= NVREG_IRQ_TIMER;
if (id->driver_data & DEV_NEED_LINKTIMER) {
@ -2155,8 +2472,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
return 0;
out_freering:
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
np->rx_ring, np->ring_addr);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
np->rx_ring.orig, np->ring_addr);
else
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
np->rx_ring.ex, np->ring_addr);
pci_set_drvdata(pci_dev, NULL);
out_unmap:
iounmap(get_hwbase(dev));
@ -2174,18 +2495,14 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
struct fe_priv *np = get_nvpriv(dev);
u8 __iomem *base = get_hwbase(dev);
unregister_netdev(dev);
/* special op: write back the misordered MAC address - otherwise
* the next nv_probe would see a wrong address.
*/
writel(np->orig_mac[0], base + NvRegMacAddrA);
writel(np->orig_mac[1], base + NvRegMacAddrB);
/* free all structures */
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr);
else
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr);
iounmap(get_hwbase(dev));
pci_release_regions(pci_dev);
pci_disable_device(pci_dev);
@ -2195,109 +2512,64 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
static struct pci_device_id pci_tbl[] = {
{ /* nForce Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* nForce2 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_3,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
},
{ /* CK804 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
},
{ /* CK804 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
},
{ /* MCP04 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
},
{ /* MCP04 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
},
{ /* MCP51 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
},
{ /* MCP51 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
},
{ /* MCP55 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
},
{ /* MCP55 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
},
{0,},
};

Просмотреть файл

@ -1,6 +1,6 @@
config MKISS
tristate "Serial port KISS driver"
depends on AX25 && BROKEN_ON_SMP
depends on AX25
---help---
KISS is a protocol used for the exchange of data between a computer
and a Terminal Node Controller (a small embedded system commonly

Просмотреть файл

@ -54,6 +54,7 @@
#include <linux/kmod.h>
#include <linux/hdlcdrv.h>
#include <linux/baycom.h>
#include <linux/jiffies.h>
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
/* prototypes for ax25_encapsulate and ax25_rebuild_header */
#include <net/ax25.h>
@ -287,7 +288,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
* measure the interrupt frequency
*/
bc->debug_vals.cur_intcnt++;
if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
bc->debug_vals.last_jiffies = cur_jiffies;
bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
bc->debug_vals.cur_intcnt = 0;

Просмотреть файл

@ -84,6 +84,7 @@
#include <linux/baycom.h>
#include <linux/parport.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <asm/bug.h>
#include <asm/system.h>
@ -165,7 +166,7 @@ static void __inline__ baycom_int_freq(struct baycom_state *bc)
* measure the interrupt frequency
*/
bc->debug_vals.cur_intcnt++;
if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
bc->debug_vals.last_jiffies = cur_jiffies;
bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
bc->debug_vals.cur_intcnt = 0;

Просмотреть файл

@ -79,6 +79,7 @@
#include <asm/io.h>
#include <linux/hdlcdrv.h>
#include <linux/baycom.h>
#include <linux/jiffies.h>
/* --------------------------------------------------------------------- */
@ -159,7 +160,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
* measure the interrupt frequency
*/
bc->debug_vals.cur_intcnt++;
if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
bc->debug_vals.last_jiffies = cur_jiffies;
bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
bc->debug_vals.cur_intcnt = 0;

Просмотреть файл

@ -69,6 +69,7 @@
#include <asm/io.h>
#include <linux/hdlcdrv.h>
#include <linux/baycom.h>
#include <linux/jiffies.h>
/* --------------------------------------------------------------------- */
@ -150,7 +151,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
* measure the interrupt frequency
*/
bc->debug_vals.cur_intcnt++;
if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
bc->debug_vals.last_jiffies = cur_jiffies;
bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
bc->debug_vals.cur_intcnt = 0;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -119,7 +119,7 @@ struct ixgb_adapter;
* so a DMA handle can be stored along with the buffer */
struct ixgb_buffer {
struct sk_buff *skb;
uint64_t dma;
dma_addr_t dma;
unsigned long time_stamp;
uint16_t length;
uint16_t next_to_watch;

Просмотреть файл

@ -565,24 +565,6 @@ ixgb_get_ee_mac_addr(struct ixgb_hw *hw,
}
}
/******************************************************************************
* return the compatibility flags from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* compatibility flags if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint16_t
ixgb_get_ee_compatibility(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->compatibility));
return(0);
}
/******************************************************************************
* return the Printed Board Assembly number from EEPROM
@ -602,81 +584,6 @@ ixgb_get_ee_pba_number(struct ixgb_hw *hw)
return(0);
}
/******************************************************************************
* return the Initialization Control Word 1 from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* Initialization Control Word 1 if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint16_t
ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->init_ctrl_reg_1));
return(0);
}
/******************************************************************************
* return the Initialization Control Word 2 from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* Initialization Control Word 2 if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint16_t
ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->init_ctrl_reg_2));
return(0);
}
/******************************************************************************
* return the Subsystem Id from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* Subsystem Id if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint16_t
ixgb_get_ee_subsystem_id(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->subsystem_id));
return(0);
}
/******************************************************************************
* return the Sub Vendor Id from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* Sub Vendor Id if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint16_t
ixgb_get_ee_subvendor_id(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->subvendor_id));
return(0);
}
/******************************************************************************
* return the Device Id from EEPROM
@ -694,81 +601,6 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw)
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->device_id));
return(0);
return (0);
}
/******************************************************************************
* return the Vendor Id from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* Device Id if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint16_t
ixgb_get_ee_vendor_id(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->vendor_id));
return(0);
}
/******************************************************************************
* return the Software Defined Pins Register from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* SDP Register if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint16_t
ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->swdpins_reg));
return(0);
}
/******************************************************************************
* return the D3 Power Management Bits from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* D3 Power Management Bits if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint8_t
ixgb_get_ee_d3_power(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->d3_power));
return(0);
}
/******************************************************************************
* return the D0 Power Management Bits from EEPROM
*
* hw - Struct containing variables accessed by shared code
*
* Returns:
* D0 Power Management Bits if EEPROM contents are valid, 0 otherwise
******************************************************************************/
uint8_t
ixgb_get_ee_d0_power(struct ixgb_hw *hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
return (le16_to_cpu(ee_map->d0_power));
return(0);
}

Просмотреть файл

@ -98,10 +98,10 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
static int
ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
ecmd->port = PORT_FIBRE;
ecmd->transceiver = XCVR_EXTERNAL;
@ -120,7 +120,7 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
static int
ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
if(ecmd->autoneg == AUTONEG_ENABLE ||
ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
@ -130,6 +130,12 @@ ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ixgb_down(adapter, TRUE);
ixgb_reset(adapter);
ixgb_up(adapter);
/* be optimistic about our link, since we were up before */
adapter->link_speed = 10000;
adapter->link_duplex = FULL_DUPLEX;
netif_carrier_on(netdev);
netif_wake_queue(netdev);
} else
ixgb_reset(adapter);
@ -140,7 +146,7 @@ static void
ixgb_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
pause->autoneg = AUTONEG_DISABLE;
@ -159,7 +165,7 @@ static int
ixgb_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
if(pause->autoneg == AUTONEG_ENABLE)
@ -177,6 +183,11 @@ ixgb_set_pauseparam(struct net_device *netdev,
if(netif_running(adapter->netdev)) {
ixgb_down(adapter, TRUE);
ixgb_up(adapter);
/* be optimistic about our link, since we were up before */
adapter->link_speed = 10000;
adapter->link_duplex = FULL_DUPLEX;
netif_carrier_on(netdev);
netif_wake_queue(netdev);
} else
ixgb_reset(adapter);
@ -186,19 +197,26 @@ ixgb_set_pauseparam(struct net_device *netdev,
static uint32_t
ixgb_get_rx_csum(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
return adapter->rx_csum;
}
static int
ixgb_set_rx_csum(struct net_device *netdev, uint32_t data)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
adapter->rx_csum = data;
if(netif_running(netdev)) {
ixgb_down(adapter,TRUE);
ixgb_up(adapter);
/* be optimistic about our link, since we were up before */
adapter->link_speed = 10000;
adapter->link_duplex = FULL_DUPLEX;
netif_carrier_on(netdev);
netif_wake_queue(netdev);
} else
ixgb_reset(adapter);
return 0;
@ -246,14 +264,15 @@ static void
ixgb_get_regs(struct net_device *netdev,
struct ethtool_regs *regs, void *p)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
uint32_t *reg = p;
uint32_t *reg_start = reg;
uint8_t i;
/* the 1 (one) below indicates an attempt at versioning, if the
* interface in ethtool or the driver this 1 should be incremented */
* interface in ethtool or the driver changes, this 1 should be
* incremented */
regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id;
/* General Registers */
@ -283,7 +302,8 @@ ixgb_get_regs(struct net_device *netdev,
*reg++ = IXGB_READ_REG(hw, RAIDC); /* 19 */
*reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */
for (i = 0; i < IXGB_RAR_ENTRIES; i++) {
/* there are 16 RAR entries in hardware, we only use 3 */
for(i = 0; i < 16; i++) {
*reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */
*reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */
}
@ -391,7 +411,7 @@ static int
ixgb_get_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, uint8_t *bytes)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
int i, max_len, first_word, last_word;
@ -439,7 +459,7 @@ static int
ixgb_set_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, uint8_t *bytes)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
void *ptr;
@ -497,7 +517,7 @@ static void
ixgb_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
strncpy(drvinfo->driver, ixgb_driver_name, 32);
strncpy(drvinfo->version, ixgb_driver_version, 32);
@ -512,7 +532,7 @@ static void
ixgb_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_desc_ring *txdr = &adapter->tx_ring;
struct ixgb_desc_ring *rxdr = &adapter->rx_ring;
@ -530,7 +550,7 @@ static int
ixgb_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_desc_ring *txdr = &adapter->tx_ring;
struct ixgb_desc_ring *rxdr = &adapter->rx_ring;
struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new;
@ -573,6 +593,11 @@ ixgb_set_ringparam(struct net_device *netdev,
adapter->tx_ring = tx_new;
if((err = ixgb_up(adapter)))
return err;
/* be optimistic about our link, since we were up before */
adapter->link_speed = 10000;
adapter->link_duplex = FULL_DUPLEX;
netif_carrier_on(netdev);
netif_wake_queue(netdev);
}
return 0;
@ -607,7 +632,7 @@ ixgb_led_blink_callback(unsigned long data)
static int
ixgb_phys_id(struct net_device *netdev, uint32_t data)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
@ -643,7 +668,7 @@ static void
ixgb_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
int i;
ixgb_update_stats(adapter);

Просмотреть файл

@ -822,17 +822,8 @@ extern void ixgb_clear_vfta(struct ixgb_hw *hw);
/* Access functions to eeprom data */
void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr);
uint16_t ixgb_get_ee_compatibility(struct ixgb_hw *hw);
uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_subsystem_id(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_subvendor_id(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_vendor_id(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw);
uint8_t ixgb_get_ee_d3_power(struct ixgb_hw *hw);
uint8_t ixgb_get_ee_d0_power(struct ixgb_hw *hw);
boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw);
uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);

Просмотреть файл

@ -29,6 +29,11 @@
#include "ixgb.h"
/* Change Log
* 1.0.96 04/19/05
* - Make needlessly global code static -- bunk@stusta.de
* - ethtool cleanup -- shemminger@osdl.org
* - Support for MODULE_VERSION -- linville@tuxdriver.com
* - add skb_header_cloned check to the tso path -- herbert@apana.org.au
* 1.0.88 01/05/05
* - include fix to the condition that determines when to quit NAPI - Robert Olsson
* - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down
@ -47,10 +52,9 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
#define DRV_VERSION "1.0.95-k2"DRIVERNAPI
#define DRV_VERSION "1.0.100-k2"DRIVERNAPI
char ixgb_driver_version[] = DRV_VERSION;
char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
/* ixgb_pci_tbl - PCI Device ID Table
*
@ -145,10 +149,12 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
/* some defines for controlling descriptor fetches in h/w */
#define RXDCTL_PTHRESH_DEFAULT 128 /* chip considers prefech below this */
#define RXDCTL_HTHRESH_DEFAULT 16 /* chip will only prefetch if tail is
pushed this many descriptors from head */
#define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */
#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below
* this */
#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail
* is pushed this many descriptors
* from head */
/**
* ixgb_init_module - Driver Registration Routine
@ -376,7 +382,7 @@ ixgb_probe(struct pci_dev *pdev,
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
adapter = netdev->priv;
adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->hw.back = adapter;
@ -512,7 +518,7 @@ static void __devexit
ixgb_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
unregister_netdev(netdev);
@ -583,7 +589,7 @@ ixgb_sw_init(struct ixgb_adapter *adapter)
static int
ixgb_open(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
int err;
/* allocate transmit descriptors */
@ -626,7 +632,7 @@ err_setup_tx:
static int
ixgb_close(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
ixgb_down(adapter, TRUE);
@ -1017,7 +1023,7 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter)
static int
ixgb_set_mac(struct net_device *netdev, void *p)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
if(!is_valid_ether_addr(addr->sa_data))
@ -1043,7 +1049,7 @@ ixgb_set_mac(struct net_device *netdev, void *p)
static void
ixgb_set_multi(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
uint32_t rctl;
@ -1371,7 +1377,7 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags)
static int
ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
unsigned int first;
unsigned int tx_flags = 0;
unsigned long flags;
@ -1425,7 +1431,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
static void
ixgb_tx_timeout(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
/* Do the reset outside of interrupt context */
schedule_work(&adapter->tx_timeout_task);
@ -1434,7 +1440,7 @@ ixgb_tx_timeout(struct net_device *netdev)
static void
ixgb_tx_timeout_task(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
ixgb_down(adapter, TRUE);
ixgb_up(adapter);
@ -1451,7 +1457,7 @@ ixgb_tx_timeout_task(struct net_device *netdev)
static struct net_device_stats *
ixgb_get_stats(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
return &adapter->net_stats;
}
@ -1467,7 +1473,7 @@ ixgb_get_stats(struct net_device *netdev)
static int
ixgb_change_mtu(struct net_device *netdev, int new_mtu)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
int max_frame = new_mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
int old_max_frame = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
@ -1522,7 +1528,8 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32);
/* fix up multicast stats by removing broadcasts */
multi -= bcast;
if(multi >= bcast)
multi -= bcast;
adapter->stats.mprcl += (multi & 0xFFFFFFFF);
adapter->stats.mprch += (multi >> 32);
@ -1641,7 +1648,7 @@ static irqreturn_t
ixgb_intr(int irq, void *data, struct pt_regs *regs)
{
struct net_device *netdev = data;
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
uint32_t icr = IXGB_READ_REG(hw, ICR);
#ifndef CONFIG_IXGB_NAPI
@ -1688,7 +1695,7 @@ ixgb_intr(int irq, void *data, struct pt_regs *regs)
static int
ixgb_clean(struct net_device *netdev, int *budget)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
int work_to_do = min(*budget, netdev->quota);
int tx_cleaned;
int work_done = 0;
@ -2017,7 +2024,7 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter)
static void
ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl, rctl;
ixgb_irq_disable(adapter);
@ -2055,7 +2062,7 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
static void
ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
uint32_t vfta, index;
/* add VID to filter table */
@ -2069,7 +2076,7 @@ ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
static void
ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
{
struct ixgb_adapter *adapter = netdev->priv;
struct ixgb_adapter *adapter = netdev_priv(netdev);
uint32_t vfta, index;
ixgb_irq_disable(adapter);

Просмотреть файл

@ -1,5 +1,10 @@
/*
* sonic.c
* jazzsonic.c
*
* (C) 2005 Finn Thain
*
* Converted to DMA API, and (from the mac68k project) introduced
* dhd's support for 16-bit cards.
*
* (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
*
@ -28,8 +33,8 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@ -44,22 +49,20 @@ static struct platform_device *jazz_sonic_device;
#define SONIC_MEM_SIZE 0x100
#define SREGS_PAD(n) u16 n;
#include "sonic.h"
/*
* Macros to access SONIC registers
*/
#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg))
#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
#define SONIC_WRITE(reg,val) \
do { \
*((volatile unsigned int *)base_addr+(reg)) = (val); \
*((volatile unsigned int *)dev->base_addr+(reg)) = (val); \
} while (0)
/* use 0 for production, 1 for verification, >2 for debug */
/* use 0 for production, 1 for verification, >1 for debug */
#ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG;
#else
@ -85,18 +88,18 @@ static unsigned short known_revisions[] =
0xffff /* end of list */
};
static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
unsigned int irq)
static int __init sonic_probe1(struct net_device *dev)
{
static unsigned version_printed;
unsigned int silicon_revision;
unsigned int val;
struct sonic_local *lp;
struct sonic_local *lp = netdev_priv(dev);
int err = -ENODEV;
int i;
if (!request_mem_region(base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
return -EBUSY;
/*
* get the Silicon Revision ID. If this is one of the known
* one assume that we found a SONIC ethernet controller at
@ -120,11 +123,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
if (sonic_debug && version_printed++ == 0)
printk(version);
printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr);
/* Fill in the 'dev' fields. */
dev->base_addr = base_addr;
dev->irq = irq;
printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr);
/*
* Put the sonic into software reset, then
@ -138,84 +137,44 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
dev->dev_addr[i*2+1] = val >> 8;
}
printk("HW Address ");
for (i = 0; i < 6; i++) {
printk("%2.2x", dev->dev_addr[i]);
if (i<5)
printk(":");
}
printk(" IRQ %d\n", irq);
err = -ENOMEM;
/* Initialize the device structure. */
if (dev->priv == NULL) {
/*
* the memory be located in the same 64kb segment
*/
lp = NULL;
i = 0;
do {
lp = kmalloc(sizeof(*lp), GFP_KERNEL);
if ((unsigned long) lp >> 16
!= ((unsigned long)lp + sizeof(*lp) ) >> 16) {
/* FIXME, free the memory later */
kfree(lp);
lp = NULL;
}
} while (lp == NULL && i++ < 20);
if (lp == NULL) {
printk("%s: couldn't allocate memory for descriptors\n",
dev->name);
goto out;
}
lp->dma_bitmode = SONIC_BITMODE32;
memset(lp, 0, sizeof(struct sonic_local));
/* get the virtual dma address */
lp->cda_laddr = vdma_alloc(CPHYSADDR(lp),sizeof(*lp));
if (lp->cda_laddr == ~0UL) {
printk("%s: couldn't get DMA page entry for "
"descriptors\n", dev->name);
goto out1;
}
lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
/* allocate receive buffer area */
/* FIXME, maybe we should use skbs */
lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL);
if (!lp->rba) {
printk("%s: couldn't allocate receive buffers\n",
dev->name);
goto out2;
}
/* get virtual dma address */
lp->rba_laddr = vdma_alloc(CPHYSADDR(lp->rba),
SONIC_NUM_RRS * SONIC_RBSIZE);
if (lp->rba_laddr == ~0UL) {
printk("%s: couldn't get DMA page entry for receive "
"buffers\n",dev->name);
goto out3;
}
/* now convert pointer to KSEG1 pointer */
lp->rba = (char *)KSEG1ADDR(lp->rba);
flush_cache_all();
dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64K boundary. */
if ((lp->descriptors = dma_alloc_coherent(lp->device,
SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
&lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
goto out;
}
lp = (struct sonic_local *)dev->priv;
/* Now set up the pointers to point to the appropriate places */
lp->cda = lp->descriptors;
lp->tda = lp->cda + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->cda_laddr = lp->descriptors_laddr;
lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
dev->open = sonic_open;
dev->stop = sonic_close;
dev->hard_start_xmit = sonic_send_packet;
dev->get_stats = sonic_get_stats;
dev->get_stats = sonic_get_stats;
dev->set_multicast_list = &sonic_multicast_list;
dev->tx_timeout = sonic_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
/*
@ -226,14 +185,8 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
SONIC_WRITE(SONIC_MPT,0xffff);
return 0;
out3:
kfree(lp->rba);
out2:
vdma_free(lp->cda_laddr);
out1:
kfree(lp);
out:
release_region(base_addr, SONIC_MEM_SIZE);
release_region(dev->base_addr, SONIC_MEM_SIZE);
return err;
}
@ -245,7 +198,6 @@ static int __init jazz_sonic_probe(struct device *device)
{
struct net_device *dev;
struct sonic_local *lp;
unsigned long base_addr;
int err = 0;
int i;
@ -255,21 +207,26 @@ static int __init jazz_sonic_probe(struct device *device)
if (mips_machgroup != MACH_GROUP_JAZZ)
return -ENODEV;
dev = alloc_etherdev(0);
dev = alloc_etherdev(sizeof(struct sonic_local));
if (!dev)
return -ENOMEM;
netdev_boot_setup_check(dev);
base_addr = dev->base_addr;
lp = netdev_priv(dev);
lp->device = device;
SET_NETDEV_DEV(dev, device);
SET_MODULE_OWNER(dev);
if (base_addr >= KSEG0) { /* Check a single specified location. */
err = sonic_probe1(dev, base_addr, dev->irq);
} else if (base_addr != 0) { /* Don't probe at all. */
netdev_boot_setup_check(dev);
if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
err = sonic_probe1(dev);
} else if (dev->base_addr != 0) { /* Don't probe at all. */
err = -ENXIO;
} else {
for (i = 0; sonic_portlist[i].port; i++) {
int io = sonic_portlist[i].port;
if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0)
dev->base_addr = sonic_portlist[i].port;
dev->irq = sonic_portlist[i].irq;
if (sonic_probe1(dev) == 0)
break;
}
if (!sonic_portlist[i].port)
@ -281,14 +238,17 @@ static int __init jazz_sonic_probe(struct device *device)
if (err)
goto out1;
printk("%s: MAC ", dev->name);
for (i = 0; i < 6; i++) {
printk("%2.2x", dev->dev_addr[i]);
if (i < 5)
printk(":");
}
printk(" IRQ %d\n", dev->irq);
return 0;
out1:
lp = dev->priv;
vdma_free(lp->rba_laddr);
kfree(lp->rba);
vdma_free(lp->cda_laddr);
kfree(lp);
release_region(dev->base_addr, SONIC_MEM_SIZE);
out:
free_netdev(dev);
@ -296,21 +256,22 @@ out:
return err;
}
/*
* SONIC uses a normal IRQ
*/
#define sonic_request_irq request_irq
#define sonic_free_irq free_irq
MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
#define sonic_chiptomem(x) KSEG1ADDR(vdma_log2phys(x))
#define SONIC_IRQ_FLAG SA_INTERRUPT
#include "sonic.c"
static int __devexit jazz_sonic_device_remove (struct device *device)
{
struct net_device *dev = device->driver_data;
struct sonic_local* lp = netdev_priv(dev);
unregister_netdev (dev);
dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
lp->descriptors, lp->descriptors_laddr);
release_region (dev->base_addr, SONIC_MEM_SIZE);
free_netdev (dev);
@ -323,7 +284,7 @@ static struct device_driver jazz_sonic_driver = {
.probe = jazz_sonic_probe,
.remove = __devexit_p(jazz_sonic_device_remove),
};
static void jazz_sonic_platform_release (struct device *device)
{
struct platform_device *pldev;
@ -336,10 +297,11 @@ static void jazz_sonic_platform_release (struct device *device)
static int __init jazz_sonic_init_module(void)
{
struct platform_device *pldev;
int err;
if (driver_register(&jazz_sonic_driver)) {
if ((err = driver_register(&jazz_sonic_driver))) {
printk(KERN_ERR "Driver registration failed\n");
return -ENOMEM;
return err;
}
jazz_sonic_device = NULL;

Просмотреть файл

@ -68,6 +68,7 @@ static DEFINE_PER_CPU(struct net_device_stats, loopback_stats);
* of largesending device modulo TCP checksum, which is ignored for loopback.
*/
#ifdef LOOPBACK_TSO
static void emulate_large_send_offload(struct sk_buff *skb)
{
struct iphdr *iph = skb->nh.iph;
@ -119,6 +120,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
dev_kfree_skb(skb);
}
#endif /* LOOPBACK_TSO */
/*
* The higher levels take care of making this non-reentrant (it's
@ -130,12 +132,13 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
skb_orphan(skb);
skb->protocol=eth_type_trans(skb,dev);
skb->dev=dev;
skb->protocol = eth_type_trans(skb,dev);
skb->dev = dev;
#ifndef LOOPBACK_MUST_CHECKSUM
skb->ip_summed = CHECKSUM_UNNECESSARY;
#endif
#ifdef LOOPBACK_TSO
if (skb_shinfo(skb)->tso_size) {
BUG_ON(skb->protocol != htons(ETH_P_IP));
BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
@ -143,14 +146,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
emulate_large_send_offload(skb);
return 0;
}
#endif
dev->last_rx = jiffies;
lb_stats = &per_cpu(loopback_stats, get_cpu());
lb_stats->rx_bytes += skb->len;
lb_stats->tx_bytes += skb->len;
lb_stats->tx_bytes = lb_stats->rx_bytes;
lb_stats->rx_packets++;
lb_stats->tx_packets++;
lb_stats->tx_packets = lb_stats->rx_packets;
put_cpu();
netif_rx(skb);
@ -208,9 +211,12 @@ struct net_device loopback_dev = {
.type = ARPHRD_LOOPBACK, /* 0x0001*/
.rebuild_header = eth_rebuild_header,
.flags = IFF_LOOPBACK,
.features = NETIF_F_SG|NETIF_F_FRAGLIST
|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA
|NETIF_F_LLTX,
.features = NETIF_F_SG | NETIF_F_FRAGLIST
#ifdef LOOPBACK_TSO
| NETIF_F_TSO
#endif
| NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
| NETIF_F_LLTX,
.ethtool_ops = &loopback_ethtool_ops,
};

Просмотреть файл

@ -1,6 +1,12 @@
/*
* macsonic.c
*
* (C) 2005 Finn Thain
*
* Converted to DMA API, converted to unified driver model, made it work as
* a module again, and from the mac68k project, introduced more 32-bit cards
* and dhd's support for 16-bit cards.
*
* (C) 1998 Alan Cox
*
* Debugging Andreas Ehliar, Michael Schmitz
@ -26,8 +32,8 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@ -41,8 +47,8 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@ -54,25 +60,28 @@
#include <asm/macints.h>
#include <asm/mac_via.h>
#define SREGS_PAD(n) u16 n;
static char mac_sonic_string[] = "macsonic";
static struct platform_device *mac_sonic_device;
#include "sonic.h"
#define SONIC_READ(reg) \
nubus_readl(base_addr+(reg))
#define SONIC_WRITE(reg,val) \
nubus_writel((val), base_addr+(reg))
#define sonic_read(dev, reg) \
nubus_readl((dev)->base_addr+(reg))
#define sonic_write(dev, reg, val) \
nubus_writel((val), (dev)->base_addr+(reg))
/* These should basically be bus-size and endian independent (since
the SONIC is at least smart enough that it uses the same endianness
as the host, unlike certain less enlightened Macintosh NICs) */
#define SONIC_READ(reg) (nubus_readw(dev->base_addr + (reg * 4) \
+ lp->reg_offset))
#define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \
+ lp->reg_offset))
/* use 0 for production, 1 for verification, >1 for debug */
#ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG;
#else
static unsigned int sonic_debug = 1;
#endif
static int sonic_debug;
static int sonic_version_printed;
static int reg_offset;
extern int mac_onboard_sonic_probe(struct net_device* dev);
extern int mac_nubus_sonic_probe(struct net_device* dev);
@ -108,40 +117,6 @@ enum macsonic_type {
#define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr)
struct net_device * __init macsonic_probe(int unit)
{
struct net_device *dev = alloc_etherdev(0);
int err;
if (!dev)
return ERR_PTR(-ENOMEM);
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
SET_MODULE_OWNER(dev);
/* This will catch fatal stuff like -ENOMEM as well as success */
err = mac_onboard_sonic_probe(dev);
if (err == 0)
goto found;
if (err != -ENODEV)
goto out;
err = mac_nubus_sonic_probe(dev);
if (err)
goto out;
found:
err = register_netdev(dev);
if (err)
goto out1;
return dev;
out1:
kfree(dev->priv);
out:
free_netdev(dev);
return ERR_PTR(err);
}
/*
* For reversing the PROM address
*/
@ -160,103 +135,55 @@ static inline void bit_reverse_addr(unsigned char addr[6])
int __init macsonic_init(struct net_device* dev)
{
struct sonic_local* lp = NULL;
int i;
struct sonic_local* lp = netdev_priv(dev);
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64K boundary. */
for (i = 0; i < 20; i++) {
unsigned long desc_base, desc_top;
if((lp = kmalloc(sizeof(struct sonic_local), GFP_KERNEL | GFP_DMA)) == NULL) {
printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name);
return -ENOMEM;
}
desc_base = (unsigned long) lp;
desc_top = desc_base + sizeof(struct sonic_local);
if ((desc_top & 0xffff) >= (desc_base & 0xffff))
break;
/* Hmm. try again (FIXME: does this actually work?) */
kfree(lp);
printk(KERN_DEBUG
"%s: didn't get continguous chunk [%08lx - %08lx], trying again\n",
dev->name, desc_base, desc_top);
}
if (lp == NULL) {
printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n",
dev->name);
if ((lp->descriptors = dma_alloc_coherent(lp->device,
SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
&lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
return -ENOMEM;
}
dev->priv = lp;
#if 0
/* this code is only here as a curiousity... mainly, where the
fuck did SONIC_BUS_SCALE come from, and what was it supposed
to do? the normal allocation works great for 32 bit stuffs.. */
}
/* Now set up the pointers to point to the appropriate places */
lp->cda = lp->sonic_desc;
lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode));
lp->cda = lp->descriptors;
lp->tda = lp->cda + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
* SONIC_BUS_SCALE(lp->dma_bitmode));
#endif
memset(lp, 0, sizeof(struct sonic_local));
lp->cda_laddr = (unsigned int)&(lp->cda);
lp->tda_laddr = (unsigned int)lp->tda;
lp->rra_laddr = (unsigned int)lp->rra;
lp->rda_laddr = (unsigned int)lp->rda;
/* FIXME, maybe we should use skbs */
if ((lp->rba = (char *)
kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) {
printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
dev->priv = NULL;
kfree(lp);
return -ENOMEM;
}
lp->rba_laddr = (unsigned int)lp->rba;
{
int rs, ds;
/* almost always 12*4096, but let's not take chances */
rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096;
/* almost always under a page, but let's not take chances */
ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096;
kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER);
kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER);
}
#if 0
flush_cache_all();
#endif
lp->cda_laddr = lp->descriptors_laddr;
lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
dev->open = sonic_open;
dev->stop = sonic_close;
dev->hard_start_xmit = sonic_send_packet;
dev->get_stats = sonic_get_stats;
dev->set_multicast_list = &sonic_multicast_list;
dev->tx_timeout = sonic_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
/*
* clear tally counter
*/
sonic_write(dev, SONIC_CRCT, 0xffff);
sonic_write(dev, SONIC_FAET, 0xffff);
sonic_write(dev, SONIC_MPT, 0xffff);
SONIC_WRITE(SONIC_CRCT, 0xffff);
SONIC_WRITE(SONIC_FAET, 0xffff);
SONIC_WRITE(SONIC_MPT, 0xffff);
return 0;
}
int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
{
struct sonic_local *lp = netdev_priv(dev);
const int prom_addr = ONBOARD_SONIC_PROM_BASE;
int i;
@ -270,6 +197,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
why this is so. */
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
memcmp(dev->dev_addr, "\x00\x05\x02", 3))
bit_reverse_addr(dev->dev_addr);
else
@ -281,22 +209,23 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
the card... */
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
memcmp(dev->dev_addr, "\x00\x05\x02", 3))
{
unsigned short val;
printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
sonic_write(dev, SONIC_CEP, 15);
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_CEP, 15);
val = sonic_read(dev, SONIC_CAP2);
val = SONIC_READ(SONIC_CAP2);
dev->dev_addr[5] = val >> 8;
dev->dev_addr[4] = val & 0xff;
val = sonic_read(dev, SONIC_CAP1);
val = SONIC_READ(SONIC_CAP1);
dev->dev_addr[3] = val >> 8;
dev->dev_addr[2] = val & 0xff;
val = sonic_read(dev, SONIC_CAP0);
val = SONIC_READ(SONIC_CAP0);
dev->dev_addr[1] = val >> 8;
dev->dev_addr[0] = val & 0xff;
@ -311,6 +240,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
memcmp(dev->dev_addr, "\x00\x05\x02", 3))
{
/*
@ -325,8 +255,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
{
/* Bwahahaha */
static int once_is_more_than_enough;
int i;
int dma_bitmode;
struct sonic_local* lp = netdev_priv(dev);
int sr;
int commslot = 0;
if (once_is_more_than_enough)
return -ENODEV;
@ -335,20 +266,18 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
if (!MACH_IS_MAC)
return -ENODEV;
printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
if (macintosh_config->ether_type != MAC_ETHER_SONIC)
{
printk("none.\n");
return -ENODEV;
}
printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
/* Bogus probing, on the models which may or may not have
Ethernet (BTW, the Ethernet *is* always at the same
address, and nothing else lives there, at least if Apple's
documentation is to be believed) */
if (macintosh_config->ident == MAC_MODEL_Q630 ||
macintosh_config->ident == MAC_MODEL_P588 ||
macintosh_config->ident == MAC_MODEL_P575 ||
macintosh_config->ident == MAC_MODEL_C610) {
unsigned long flags;
int card_present;
@ -361,13 +290,13 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
printk("none.\n");
return -ENODEV;
}
commslot = 1;
}
printk("yes\n");
/* Danger! My arms are flailing wildly! You *must* set this
before using sonic_read() */
/* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
* and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
dev->base_addr = ONBOARD_SONIC_REGISTERS;
if (via_alt_mapping)
dev->irq = IRQ_AUTO_3;
@ -379,84 +308,66 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
sonic_version_printed = 1;
}
printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n",
dev->name, dev->base_addr);
/* Now do a song and dance routine in an attempt to determine
the bus width */
lp->device->bus_id, dev->base_addr);
/* The PowerBook's SONIC is 16 bit always. */
if (macintosh_config->ident == MAC_MODEL_PB520) {
reg_offset = 0;
dma_bitmode = 0;
} else if (macintosh_config->ident == MAC_MODEL_C610) {
reg_offset = 0;
dma_bitmode = 1;
} else {
lp->reg_offset = 0;
lp->dma_bitmode = SONIC_BITMODE16;
sr = SONIC_READ(SONIC_SR);
} else if (commslot) {
/* Some of the comm-slot cards are 16 bit. But some
of them are not. The 32-bit cards use offset 2 and
pad with zeroes or sometimes ones (I think...)
Therefore, if we try offset 0 and get a silicon
revision of 0, we assume 16 bit. */
int sr;
of them are not. The 32-bit cards use offset 2 and
have known revisions, we try reading the revision
register at offset 2, if we don't get a known revision
we assume 16 bit at offset 0. */
lp->reg_offset = 2;
lp->dma_bitmode = SONIC_BITMODE16;
/* Technically this is not necessary since we zeroed
it above */
reg_offset = 0;
dma_bitmode = 0;
sr = sonic_read(dev, SONIC_SR);
if (sr == 0 || sr == 0xffff) {
reg_offset = 2;
/* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */
sr = sonic_read(dev, SONIC_SR);
dma_bitmode = 1;
sr = SONIC_READ(SONIC_SR);
if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101)
/* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */
lp->dma_bitmode = SONIC_BITMODE32;
else {
lp->dma_bitmode = SONIC_BITMODE16;
lp->reg_offset = 0;
sr = SONIC_READ(SONIC_SR);
}
printk(KERN_INFO
"%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
dev->name, sr, dma_bitmode?32:16, reg_offset);
} else {
/* All onboard cards are at offset 2 with 32 bit DMA. */
lp->reg_offset = 2;
lp->dma_bitmode = SONIC_BITMODE32;
sr = SONIC_READ(SONIC_SR);
}
printk(KERN_INFO
"%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
lp->device->bus_id, sr, lp->dma_bitmode?32:16, lp->reg_offset);
/* this carries my sincere apologies -- by the time I got to updating
the driver, support for "reg_offsets" appeares nowhere in the sonic
code, going back for over a year. Fortunately, my Mac does't seem
to use whatever this was.
#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id,
SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
#endif
If you know how this is supposed to be implemented, either fix it,
or contact me (sammy@oh.verio.com) to explain what it is. --Sam */
if(reg_offset) {
printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name);
return -ENODEV;
}
/* Software reset, then initialize control registers. */
sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS |
SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS |
(dma_bitmode ? SONIC_DCR_DW : 0));
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_DCR, SONIC_DCR_EXBUS | SONIC_DCR_BMS |
SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
(lp->dma_bitmode ? SONIC_DCR_DW : 0));
/* This *must* be written back to in order to restore the
extended programmable output bits */
sonic_write(dev, SONIC_DCR2, 0);
* extended programmable output bits, as it may not have been
* initialised since the hardware reset. */
SONIC_WRITE(SONIC_DCR2, 0);
/* Clear *and* disable interrupts to be on the safe side */
sonic_write(dev, SONIC_ISR,0x7fff);
sonic_write(dev, SONIC_IMR,0);
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
/* Now look for the MAC address. */
if (mac_onboard_sonic_ethernet_addr(dev) != 0)
return -ENODEV;
printk(KERN_INFO "MAC ");
for (i = 0; i < 6; i++) {
printk("%2.2x", dev->dev_addr[i]);
if (i < 5)
printk(":");
}
printk(" IRQ %d\n", dev->irq);
/* Shared init code */
return macsonic_init(dev);
}
@ -468,8 +379,10 @@ int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev,
int i;
for(i = 0; i < 6; i++)
dev->dev_addr[i] = SONIC_READ_PROM(i);
/* For now we are going to assume that they're all bit-reversed */
bit_reverse_addr(dev->dev_addr);
/* Some of the addresses are bit-reversed */
if (id != MACSONIC_DAYNA)
bit_reverse_addr(dev->dev_addr);
return 0;
}
@ -487,6 +400,15 @@ int __init macsonic_ident(struct nubus_dev* ndev)
else
return MACSONIC_APPLE;
}
if (ndev->dr_hw == NUBUS_DRHW_SMC9194 &&
ndev->dr_sw == NUBUS_DRSW_DAYNA)
return MACSONIC_DAYNA;
if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC &&
ndev->dr_sw == 0) { /* huh? */
return MACSONIC_APPLE16;
}
return -1;
}
@ -494,12 +416,12 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
{
static int slots;
struct nubus_dev* ndev = NULL;
struct sonic_local* lp = netdev_priv(dev);
unsigned long base_addr, prom_addr;
u16 sonic_dcr;
int id;
int i;
int dma_bitmode;
int id = -1;
int reg_offset, dma_bitmode;
/* Find the first SONIC that hasn't been initialized already */
while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
NUBUS_TYPE_ETHERNET, ndev)) != NULL)
@ -521,51 +443,52 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
case MACSONIC_DUODOCK:
base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE;
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1
| SONIC_DCR_TFT0;
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 |
SONIC_DCR_TFT0;
reg_offset = 2;
dma_bitmode = 1;
dma_bitmode = SONIC_BITMODE32;
break;
case MACSONIC_APPLE:
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0;
reg_offset = 0;
dma_bitmode = 1;
dma_bitmode = SONIC_BITMODE32;
break;
case MACSONIC_APPLE16:
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
sonic_dcr = SONIC_DCR_EXBUS
| SONIC_DCR_RFT1 | SONIC_DCR_TFT0
| SONIC_DCR_PO1 | SONIC_DCR_BMS;
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
SONIC_DCR_PO1 | SONIC_DCR_BMS;
reg_offset = 0;
dma_bitmode = 0;
dma_bitmode = SONIC_BITMODE16;
break;
case MACSONIC_DAYNALINK:
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE;
sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0
| SONIC_DCR_PO1 | SONIC_DCR_BMS;
sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
SONIC_DCR_PO1 | SONIC_DCR_BMS;
reg_offset = 0;
dma_bitmode = 0;
dma_bitmode = SONIC_BITMODE16;
break;
case MACSONIC_DAYNA:
base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR;
sonic_dcr = SONIC_DCR_BMS
| SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1;
sonic_dcr = SONIC_DCR_BMS |
SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1;
reg_offset = 0;
dma_bitmode = 0;
dma_bitmode = SONIC_BITMODE16;
break;
default:
printk(KERN_ERR "macsonic: WTF, id is %d\n", id);
return -ENODEV;
}
/* Danger! My arms are flailing wildly! You *must* set this
before using sonic_read() */
/* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
* and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
dev->base_addr = base_addr;
lp->reg_offset = reg_offset;
lp->dma_bitmode = dma_bitmode;
dev->irq = SLOT2IRQ(ndev->board->slot);
if (!sonic_version_printed) {
@ -573,29 +496,66 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
sonic_version_printed = 1;
}
printk(KERN_INFO "%s: %s in slot %X\n",
dev->name, ndev->board->name, ndev->board->slot);
lp->device->bus_id, ndev->board->name, ndev->board->slot);
printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset);
lp->device->bus_id, SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset);
if(reg_offset) {
printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name);
return -ENODEV;
}
#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id,
SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
#endif
/* Software reset, then initialize control registers. */
sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
sonic_write(dev, SONIC_DCR, sonic_dcr
| (dma_bitmode ? SONIC_DCR_DW : 0));
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_DCR, sonic_dcr | (dma_bitmode ? SONIC_DCR_DW : 0));
/* This *must* be written back to in order to restore the
* extended programmable output bits, since it may not have been
* initialised since the hardware reset. */
SONIC_WRITE(SONIC_DCR2, 0);
/* Clear *and* disable interrupts to be on the safe side */
sonic_write(dev, SONIC_ISR,0x7fff);
sonic_write(dev, SONIC_IMR,0);
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
/* Now look for the MAC address. */
if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0)
return -ENODEV;
printk(KERN_INFO "MAC ");
/* Shared init code */
return macsonic_init(dev);
}
static int __init mac_sonic_probe(struct device *device)
{
struct net_device *dev;
struct sonic_local *lp;
int err;
int i;
dev = alloc_etherdev(sizeof(struct sonic_local));
if (!dev)
return -ENOMEM;
lp = netdev_priv(dev);
lp->device = device;
SET_NETDEV_DEV(dev, device);
SET_MODULE_OWNER(dev);
/* This will catch fatal stuff like -ENOMEM as well as success */
err = mac_onboard_sonic_probe(dev);
if (err == 0)
goto found;
if (err != -ENODEV)
goto out;
err = mac_nubus_sonic_probe(dev);
if (err)
goto out;
found:
err = register_netdev(dev);
if (err)
goto out;
printk("%s: MAC ", dev->name);
for (i = 0; i < 6; i++) {
printk("%2.2x", dev->dev_addr[i]);
if (i < 5)
@ -603,55 +563,95 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
}
printk(" IRQ %d\n", dev->irq);
/* Shared init code */
return macsonic_init(dev);
return 0;
out:
free_netdev(dev);
return err;
}
#ifdef MODULE
static struct net_device *dev_macsonic;
MODULE_PARM(sonic_debug, "i");
MODULE_DESCRIPTION("Macintosh SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
int
init_module(void)
{
dev_macsonic = macsonic_probe(-1);
if (IS_ERR(dev_macsonic)) {
printk(KERN_WARNING "macsonic.c: No card found\n");
return PTR_ERR(dev_macsonic);
}
return 0;
}
void
cleanup_module(void)
{
unregister_netdev(dev_macsonic);
kfree(dev_macsonic->priv);
free_netdev(dev_macsonic);
}
#endif /* MODULE */
#define vdma_alloc(foo, bar) ((u32)foo)
#define vdma_free(baz)
#define sonic_chiptomem(bat) (bat)
#define PHYSADDR(quux) (quux)
#define CPHYSADDR(quux) (quux)
#define sonic_request_irq request_irq
#define sonic_free_irq free_irq
#define SONIC_IRQ_FLAG IRQ_FLG_FAST
#include "sonic.c"
/*
* Local variables:
* compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o macsonic.o macsonic.c"
* version-control: t
* kept-new-versions: 5
* c-indent-level: 8
* tab-width: 8
* End:
*
*/
static int __devexit mac_sonic_device_remove (struct device *device)
{
struct net_device *dev = device->driver_data;
struct sonic_local* lp = netdev_priv(dev);
unregister_netdev (dev);
dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
lp->descriptors, lp->descriptors_laddr);
free_netdev (dev);
return 0;
}
static struct device_driver mac_sonic_driver = {
.name = mac_sonic_string,
.bus = &platform_bus_type,
.probe = mac_sonic_probe,
.remove = __devexit_p(mac_sonic_device_remove),
};
static void mac_sonic_platform_release(struct device *device)
{
struct platform_device *pldev;
/* free device */
pldev = to_platform_device (device);
kfree (pldev);
}
static int __init mac_sonic_init_module(void)
{
struct platform_device *pldev;
int err;
if ((err = driver_register(&mac_sonic_driver))) {
printk(KERN_ERR "Driver registration failed\n");
return err;
}
mac_sonic_device = NULL;
if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
goto out_unregister;
}
memset(pldev, 0, sizeof (*pldev));
pldev->name = mac_sonic_string;
pldev->id = 0;
pldev->dev.release = mac_sonic_platform_release;
mac_sonic_device = pldev;
if (platform_device_register (pldev)) {
kfree(pldev);
mac_sonic_device = NULL;
}
return 0;
out_unregister:
platform_device_unregister(pldev);
return -ENOMEM;
}
static void __exit mac_sonic_cleanup_module(void)
{
driver_unregister(&mac_sonic_driver);
if (mac_sonic_device) {
platform_device_unregister(mac_sonic_device);
mac_sonic_device = NULL;
}
}
module_init(mac_sonic_init_module);
module_exit(mac_sonic_cleanup_module);

Просмотреть файл

@ -1157,16 +1157,20 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb_shinfo(skb)->nr_frags) {
linear:
if (skb->ip_summed != CHECKSUM_HW) {
/* Errata BTS #50, IHL must be 5 if no HW checksum */
pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC;
ETH_TX_FIRST_DESC |
ETH_TX_LAST_DESC |
5 << ETH_TX_IHL_SHIFT;
pkt_info.l4i_chk = 0;
} else {
u32 ipheader = skb->nh.iph->ihl << 11;
pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC |
ETH_GEN_TCP_UDP_CHECKSUM |
ETH_GEN_IP_V_4_CHECKSUM | ipheader;
ETH_TX_FIRST_DESC |
ETH_TX_LAST_DESC |
ETH_GEN_TCP_UDP_CHECKSUM |
ETH_GEN_IP_V_4_CHECKSUM |
skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
/* CPU already calculated pseudo header checksum. */
if (skb->nh.iph->protocol == IPPROTO_UDP) {
pkt_info.cmd_sts |= ETH_UDP_FRAME;
@ -1193,7 +1197,6 @@ linear:
stats->tx_bytes += pkt_info.byte_cnt;
} else {
unsigned int frag;
u32 ipheader;
/* Since hardware can't handle unaligned fragments smaller
* than 9 bytes, if we find any, we linearize the skb
@ -1222,12 +1225,16 @@ linear:
DMA_TO_DEVICE);
pkt_info.l4i_chk = 0;
pkt_info.return_info = 0;
pkt_info.cmd_sts = ETH_TX_FIRST_DESC;
if (skb->ip_summed == CHECKSUM_HW) {
ipheader = skb->nh.iph->ihl << 11;
pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
ETH_GEN_IP_V_4_CHECKSUM | ipheader;
if (skb->ip_summed != CHECKSUM_HW)
/* Errata BTS #50, IHL must be 5 if no HW checksum */
pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
5 << ETH_TX_IHL_SHIFT;
else {
pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
ETH_GEN_TCP_UDP_CHECKSUM |
ETH_GEN_IP_V_4_CHECKSUM |
skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
/* CPU already calculated pseudo header checksum. */
if (skb->nh.iph->protocol == IPPROTO_UDP) {
pkt_info.cmd_sts |= ETH_UDP_FRAME;

Просмотреть файл

@ -49,7 +49,7 @@
/* Checksum offload for Tx works for most packets, but
* fails if previous packet sent did not use hw csum
*/
#undef MV643XX_CHECKSUM_OFFLOAD_TX
#define MV643XX_CHECKSUM_OFFLOAD_TX
#define MV643XX_NAPI
#define MV643XX_TX_FAST_REFILL
#undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */
@ -217,6 +217,8 @@
#define ETH_TX_ENABLE_INTERRUPT (BIT23)
#define ETH_AUTO_MODE (BIT30)
#define ETH_TX_IHL_SHIFT 11
/* typedefs */
typedef enum _eth_func_ret_status {

Просмотреть файл

@ -486,9 +486,9 @@ struct netdrv_private {
MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_PARM (multicast_filter_limit, "i");
MODULE_PARM (max_interrupt_work, "i");
MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
module_param(multicast_filter_limit, int, 0);
module_param(max_interrupt_work, int, 0);
module_param_array(media, int, NULL, 0);
MODULE_PARM_DESC (multicast_filter_limit, "pci-skeleton maximum number of filtered multicast addresses");
MODULE_PARM_DESC (max_interrupt_work, "pci-skeleton maximum events handled per interrupt");
MODULE_PARM_DESC (media, "pci-skeleton: Bits 0-3: media type, bit 17: full duplex");

Просмотреть файл

@ -134,7 +134,7 @@ typedef struct local_info_t {
u_char mc_filter[8];
} local_info_t;
#define MC_FILTERBREAK 64
#define MC_FILTERBREAK 8
/*====================================================================*/
/*
@ -1012,7 +1012,7 @@ static void fjn_reset(struct net_device *dev)
outb(BANK_1U, ioaddr + CONFIG_1);
/* set the multicast table to accept none. */
for (i = 0; i < 6; i++)
for (i = 0; i < 8; i++)
outb(0x00, ioaddr + MAR_ADR + i);
/* Switch to bank 2 (runtime mode) */
@ -1269,6 +1269,16 @@ static void set_rx_mode(struct net_device *dev)
u_long flags;
int i;
int saved_config_0 = inb(ioaddr + CONFIG_0);
local_irq_save(flags);
/* Disable Tx and Rx */
if (sram_config == 0)
outb(CONFIG0_RST, ioaddr + CONFIG_0);
else
outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
if (dev->flags & IFF_PROMISC) {
/* Unconditionally log net taps. */
printk("%s: Promiscuous mode enabled.\n", dev->name);
@ -1290,20 +1300,23 @@ static void set_rx_mode(struct net_device *dev)
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
unsigned int bit =
ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;
mc_filter[bit >> 3] |= (1 << bit);
ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit >> 3] |= (1 << (bit & 7));
}
outb(2, ioaddr + RX_MODE); /* Use normal mode. */
}
local_irq_save(flags);
if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
int saved_bank = inb(ioaddr + CONFIG_1);
/* Switch to bank 1 and set the multicast table. */
outb(0xe4, ioaddr + CONFIG_1);
for (i = 0; i < 8; i++)
outb(mc_filter[i], ioaddr + 8 + i);
outb(mc_filter[i], ioaddr + MAR_ADR + i);
memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
outb(saved_bank, ioaddr + CONFIG_1);
}
outb(saved_config_0, ioaddr + CONFIG_0);
local_irq_restore(flags);
}

57
drivers/net/phy/Kconfig Normal file
Просмотреть файл

@ -0,0 +1,57 @@
#
# PHY Layer Configuration
#
menu "PHY device support"
config PHYLIB
tristate "PHY Device support and infrastructure"
depends on NET_ETHERNET
help
Ethernet controllers are usually attached to PHY
devices. This option provides infrastructure for
managing PHY devices.
config PHYCONTROL
bool " Support for automatically handling PHY state changes"
depends on PHYLIB
help
Adds code to perform all the work for keeping PHY link
state (speed/duplex/etc) up-to-date. Also handles
interrupts.
comment "MII PHY device drivers"
depends on PHYLIB
config MARVELL_PHY
tristate "Drivers for Marvell PHYs"
depends on PHYLIB
---help---
Currently has a driver for the 88E1011S
config DAVICOM_PHY
tristate "Drivers for Davicom PHYs"
depends on PHYLIB
---help---
Currently supports dm9161e and dm9131
config QSEMI_PHY
tristate "Drivers for Quality Semiconductor PHYs"
depends on PHYLIB
---help---
Currently supports the qs6612
config LXT_PHY
tristate "Drivers for the Intel LXT PHYs"
depends on PHYLIB
---help---
Currently supports the lxt970, lxt971
config CICADA_PHY
tristate "Drivers for the Cicada PHYs"
depends on PHYLIB
---help---
Currently supports the cis8204
endmenu

10
drivers/net/phy/Makefile Normal file
Просмотреть файл

@ -0,0 +1,10 @@
# Makefile for Linux PHY drivers
libphy-objs := phy.o phy_device.o mdio_bus.o
obj-$(CONFIG_PHYLIB) += libphy.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_CICADA_PHY) += cicada.o
obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o

134
drivers/net/phy/cicada.c Normal file
Просмотреть файл

@ -0,0 +1,134 @@
/*
* drivers/net/phy/cicada.c
*
* Driver for Cicada PHYs
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
/* Cicada Extended Control Register 1 */
#define MII_CIS8201_EXT_CON1 0x17
#define MII_CIS8201_EXTCON1_INIT 0x0000
/* Cicada Interrupt Mask Register */
#define MII_CIS8201_IMASK 0x19
#define MII_CIS8201_IMASK_IEN 0x8000
#define MII_CIS8201_IMASK_SPEED 0x4000
#define MII_CIS8201_IMASK_LINK 0x2000
#define MII_CIS8201_IMASK_DUPLEX 0x1000
#define MII_CIS8201_IMASK_MASK 0xf000
/* Cicada Interrupt Status Register */
#define MII_CIS8201_ISTAT 0x1a
#define MII_CIS8201_ISTAT_STATUS 0x8000
#define MII_CIS8201_ISTAT_SPEED 0x4000
#define MII_CIS8201_ISTAT_LINK 0x2000
#define MII_CIS8201_ISTAT_DUPLEX 0x1000
/* Cicada Auxiliary Control/Status Register */
#define MII_CIS8201_AUX_CONSTAT 0x1c
#define MII_CIS8201_AUXCONSTAT_INIT 0x0004
#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020
#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018
#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010
#define MII_CIS8201_AUXCONSTAT_100 0x0008
MODULE_DESCRIPTION("Cicadia PHY driver");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
static int cis820x_config_init(struct phy_device *phydev)
{
int err;
err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT,
MII_CIS8201_AUXCONSTAT_INIT);
if (err < 0)
return err;
err = phy_write(phydev, MII_CIS8201_EXT_CON1,
MII_CIS8201_EXTCON1_INIT);
return err;
}
static int cis820x_ack_interrupt(struct phy_device *phydev)
{
int err = phy_read(phydev, MII_CIS8201_ISTAT);
return (err < 0) ? err : 0;
}
static int cis820x_config_intr(struct phy_device *phydev)
{
int err;
if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_CIS8201_IMASK,
MII_CIS8201_IMASK_MASK);
else
err = phy_write(phydev, MII_CIS8201_IMASK, 0);
return err;
}
/* Cicada 820x */
static struct phy_driver cis8204_driver = {
.phy_id = 0x000fc440,
.name = "Cicada Cis8204",
.phy_id_mask = 0x000fffc0,
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = &cis820x_config_init,
.config_aneg = &genphy_config_aneg,
.read_status = &genphy_read_status,
.ack_interrupt = &cis820x_ack_interrupt,
.config_intr = &cis820x_config_intr,
.driver = { .owner = THIS_MODULE,},
};
static int __init cis8204_init(void)
{
return phy_driver_register(&cis8204_driver);
}
static void __exit cis8204_exit(void)
{
phy_driver_unregister(&cis8204_driver);
}
module_init(cis8204_init);
module_exit(cis8204_exit);

195
drivers/net/phy/davicom.c Normal file
Просмотреть файл

@ -0,0 +1,195 @@
/*
* drivers/net/phy/davicom.c
*
* Driver for Davicom PHYs
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#define MII_DM9161_SCR 0x10
#define MII_DM9161_SCR_INIT 0x0610
/* DM9161 Interrupt Register */
#define MII_DM9161_INTR 0x15
#define MII_DM9161_INTR_PEND 0x8000
#define MII_DM9161_INTR_DPLX_MASK 0x0800
#define MII_DM9161_INTR_SPD_MASK 0x0400
#define MII_DM9161_INTR_LINK_MASK 0x0200
#define MII_DM9161_INTR_MASK 0x0100
#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
#define MII_DM9161_INTR_SPD_CHANGE 0x0008
#define MII_DM9161_INTR_LINK_CHANGE 0x0004
#define MII_DM9161_INTR_INIT 0x0000
#define MII_DM9161_INTR_STOP \
(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
| MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
/* DM9161 10BT Configuration/Status */
#define MII_DM9161_10BTCSR 0x12
#define MII_DM9161_10BTCSR_INIT 0x7800
MODULE_DESCRIPTION("Davicom PHY driver");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
#define DM9161_DELAY 1
static int dm9161_config_intr(struct phy_device *phydev)
{
int temp;
temp = phy_read(phydev, MII_DM9161_INTR);
if (temp < 0)
return temp;
if(PHY_INTERRUPT_ENABLED == phydev->interrupts )
temp &= ~(MII_DM9161_INTR_STOP);
else
temp |= MII_DM9161_INTR_STOP;
temp = phy_write(phydev, MII_DM9161_INTR, temp);
return temp;
}
static int dm9161_config_aneg(struct phy_device *phydev)
{
int err;
/* Isolate the PHY */
err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
if (err < 0)
return err;
/* Configure the new settings */
err = genphy_config_aneg(phydev);
if (err < 0)
return err;
return 0;
}
static int dm9161_config_init(struct phy_device *phydev)
{
int err;
/* Isolate the PHY */
err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
if (err < 0)
return err;
/* Do not bypass the scrambler/descrambler */
err = phy_write(phydev, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
if (err < 0)
return err;
/* Clear 10BTCSR to default */
err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT);
if (err < 0)
return err;
/* Reconnect the PHY, and enable Autonegotiation */
err = phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
if (err < 0)
return err;
return 0;
}
static int dm9161_ack_interrupt(struct phy_device *phydev)
{
int err = phy_read(phydev, MII_DM9161_INTR);
return (err < 0) ? err : 0;
}
static struct phy_driver dm9161_driver = {
.phy_id = 0x0181b880,
.name = "Davicom DM9161E",
.phy_id_mask = 0x0ffffff0,
.features = PHY_BASIC_FEATURES,
.config_init = dm9161_config_init,
.config_aneg = dm9161_config_aneg,
.read_status = genphy_read_status,
.driver = { .owner = THIS_MODULE,},
};
static struct phy_driver dm9131_driver = {
.phy_id = 0x00181b80,
.name = "Davicom DM9131",
.phy_id_mask = 0x0ffffff0,
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = dm9161_ack_interrupt,
.config_intr = dm9161_config_intr,
.driver = { .owner = THIS_MODULE,},
};
static int __init davicom_init(void)
{
int ret;
ret = phy_driver_register(&dm9161_driver);
if (ret)
goto err1;
ret = phy_driver_register(&dm9131_driver);
if (ret)
goto err2;
return 0;
err2:
phy_driver_unregister(&dm9161_driver);
err1:
return ret;
}
static void __exit davicom_exit(void)
{
phy_driver_unregister(&dm9161_driver);
phy_driver_unregister(&dm9131_driver);
}
module_init(davicom_init);
module_exit(davicom_exit);

179
drivers/net/phy/lxt.c Normal file
Просмотреть файл

@ -0,0 +1,179 @@
/*
* drivers/net/phy/lxt.c
*
* Driver for Intel LXT PHYs
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
/* The Level one LXT970 is used by many boards */
#define MII_LXT970_IER 17 /* Interrupt Enable Register */
#define MII_LXT970_IER_IEN 0x0002
#define MII_LXT970_ISR 18 /* Interrupt Status Register */
#define MII_LXT970_CONFIG 19 /* Configuration Register */
/* ------------------------------------------------------------------------- */
/* The Level one LXT971 is used on some of my custom boards */
/* register definitions for the 971 */
#define MII_LXT971_IER 18 /* Interrupt Enable Register */
#define MII_LXT971_IER_IEN 0x00f2
#define MII_LXT971_ISR 19 /* Interrupt Status Register */
MODULE_DESCRIPTION("Intel LXT PHY driver");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
static int lxt970_ack_interrupt(struct phy_device *phydev)
{
int err;
err = phy_read(phydev, MII_BMSR);
if (err < 0)
return err;
err = phy_read(phydev, MII_LXT970_ISR);
if (err < 0)
return err;
return 0;
}
static int lxt970_config_intr(struct phy_device *phydev)
{
int err;
if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN);
else
err = phy_write(phydev, MII_LXT970_IER, 0);
return err;
}
static int lxt970_config_init(struct phy_device *phydev)
{
int err;
err = phy_write(phydev, MII_LXT970_CONFIG, 0);
return err;
}
static int lxt971_ack_interrupt(struct phy_device *phydev)
{
int err = phy_read(phydev, MII_LXT971_ISR);
if (err < 0)
return err;
return 0;
}
static int lxt971_config_intr(struct phy_device *phydev)
{
int err;
if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN);
else
err = phy_write(phydev, MII_LXT971_IER, 0);
return err;
}
static struct phy_driver lxt970_driver = {
.phy_id = 0x07810000,
.name = "LXT970",
.phy_id_mask = 0x0fffffff,
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = lxt970_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = lxt970_ack_interrupt,
.config_intr = lxt970_config_intr,
.driver = { .owner = THIS_MODULE,},
};
static struct phy_driver lxt971_driver = {
.phy_id = 0x0001378e,
.name = "LXT971",
.phy_id_mask = 0x0fffffff,
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = lxt971_ack_interrupt,
.config_intr = lxt971_config_intr,
.driver = { .owner = THIS_MODULE,},
};
static int __init lxt_init(void)
{
int ret;
ret = phy_driver_register(&lxt970_driver);
if (ret)
goto err1;
ret = phy_driver_register(&lxt971_driver);
if (ret)
goto err2;
return 0;
err2:
phy_driver_unregister(&lxt970_driver);
err1:
return ret;
}
static void __exit lxt_exit(void)
{
phy_driver_unregister(&lxt970_driver);
phy_driver_unregister(&lxt971_driver);
}
module_init(lxt_init);
module_exit(lxt_exit);

140
drivers/net/phy/marvell.c Normal file
Просмотреть файл

@ -0,0 +1,140 @@
/*
* drivers/net/phy/marvell.c
*
* Driver for Marvell PHYs
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#define MII_M1011_IEVENT 0x13
#define MII_M1011_IEVENT_CLEAR 0x0000
#define MII_M1011_IMASK 0x12
#define MII_M1011_IMASK_INIT 0x6400
#define MII_M1011_IMASK_CLEAR 0x0000
MODULE_DESCRIPTION("Marvell PHY driver");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
static int marvell_ack_interrupt(struct phy_device *phydev)
{
int err;
/* Clear the interrupts by reading the reg */
err = phy_read(phydev, MII_M1011_IEVENT);
if (err < 0)
return err;
return 0;
}
static int marvell_config_intr(struct phy_device *phydev)
{
int err;
if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
else
err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
return err;
}
static int marvell_config_aneg(struct phy_device *phydev)
{
int err;
/* The Marvell PHY has an errata which requires
* that certain registers get written in order
* to restart autonegotiation */
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
return err;
err = phy_write(phydev, 0x1d, 0x1f);
if (err < 0)
return err;
err = phy_write(phydev, 0x1e, 0x200c);
if (err < 0)
return err;
err = phy_write(phydev, 0x1d, 0x5);
if (err < 0)
return err;
err = phy_write(phydev, 0x1e, 0);
if (err < 0)
return err;
err = phy_write(phydev, 0x1e, 0x100);
if (err < 0)
return err;
err = genphy_config_aneg(phydev);
return err;
}
static struct phy_driver m88e1101_driver = {
.phy_id = 0x01410c00,
.phy_id_mask = 0xffffff00,
.name = "Marvell 88E1101",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = &marvell_config_aneg,
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
.driver = { .owner = THIS_MODULE,},
};
static int __init marvell_init(void)
{
return phy_driver_register(&m88e1101_driver);
}
static void __exit marvell_exit(void)
{
phy_driver_unregister(&m88e1101_driver);
}
module_init(marvell_init);
module_exit(marvell_exit);

176
drivers/net/phy/mdio_bus.c Normal file
Просмотреть файл

@ -0,0 +1,176 @@
/*
* drivers/net/phy/mdio_bus.c
*
* MDIO Bus interface
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
/* mdiobus_register
*
* description: Called by a bus driver to bring up all the PHYs
* on a given bus, and attach them to the bus
*/
int mdiobus_register(struct mii_bus *bus)
{
int i;
int err = 0;
spin_lock_init(&bus->mdio_lock);
if (NULL == bus || NULL == bus->name ||
NULL == bus->read ||
NULL == bus->write)
return -EINVAL;
if (bus->reset)
bus->reset(bus);
for (i = 0; i < PHY_MAX_ADDR; i++) {
struct phy_device *phydev;
phydev = get_phy_device(bus, i);
if (IS_ERR(phydev))
return PTR_ERR(phydev);
/* There's a PHY at this address
* We need to set:
* 1) IRQ
* 2) bus_id
* 3) parent
* 4) bus
* 5) mii_bus
* And, we need to register it */
if (phydev) {
phydev->irq = bus->irq[i];
phydev->dev.parent = bus->dev;
phydev->dev.bus = &mdio_bus_type;
sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i);
phydev->bus = bus;
err = device_register(&phydev->dev);
if (err)
printk(KERN_ERR "phy %d failed to register\n",
i);
}
bus->phy_map[i] = phydev;
}
pr_info("%s: probed\n", bus->name);
return err;
}
EXPORT_SYMBOL(mdiobus_register);
void mdiobus_unregister(struct mii_bus *bus)
{
int i;
for (i = 0; i < PHY_MAX_ADDR; i++) {
if (bus->phy_map[i]) {
device_unregister(&bus->phy_map[i]->dev);
kfree(bus->phy_map[i]);
}
}
}
EXPORT_SYMBOL(mdiobus_unregister);
/* mdio_bus_match
*
* description: Given a PHY device, and a PHY driver, return 1 if
* the driver supports the device. Otherwise, return 0
*/
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
struct phy_device *phydev = to_phy_device(dev);
struct phy_driver *phydrv = to_phy_driver(drv);
return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask));
}
/* Suspend and resume. Copied from platform_suspend and
* platform_resume
*/
static int mdio_bus_suspend(struct device * dev, u32 state)
{
int ret = 0;
struct device_driver *drv = dev->driver;
if (drv && drv->suspend) {
ret = drv->suspend(dev, state, SUSPEND_DISABLE);
if (ret == 0)
ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE);
if (ret == 0)
ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN);
}
return ret;
}
static int mdio_bus_resume(struct device * dev)
{
int ret = 0;
struct device_driver *drv = dev->driver;
if (drv && drv->resume) {
ret = drv->resume(dev, RESUME_POWER_ON);
if (ret == 0)
ret = drv->resume(dev, RESUME_RESTORE_STATE);
if (ret == 0)
ret = drv->resume(dev, RESUME_ENABLE);
}
return ret;
}
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
.suspend = mdio_bus_suspend,
.resume = mdio_bus_resume,
};
int __init mdio_bus_init(void)
{
return bus_register(&mdio_bus_type);
}
void __exit mdio_bus_exit(void)
{
bus_unregister(&mdio_bus_type);
}

871
drivers/net/phy/phy.c Normal file
Просмотреть файл

@ -0,0 +1,871 @@
/*
* drivers/net/phy/phy.c
*
* Framework for configuring and reading PHY devices
* Based on code in sungem_phy.c and gianfar_phy.c
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
/* Convenience function to print out the current phy status
*/
void phy_print_status(struct phy_device *phydev)
{
pr_info("%s: Link is %s", phydev->dev.bus_id,
phydev->link ? "Up" : "Down");
if (phydev->link)
printk(" - %d/%s", phydev->speed,
DUPLEX_FULL == phydev->duplex ?
"Full" : "Half");
printk("\n");
}
EXPORT_SYMBOL(phy_print_status);
/* Convenience functions for reading/writing a given PHY
* register. They MUST NOT be called from interrupt context,
* because the bus read/write functions may wait for an interrupt
* to conclude the operation. */
int phy_read(struct phy_device *phydev, u16 regnum)
{
int retval;
struct mii_bus *bus = phydev->bus;
spin_lock_bh(&bus->mdio_lock);
retval = bus->read(bus, phydev->addr, regnum);
spin_unlock_bh(&bus->mdio_lock);
return retval;
}
EXPORT_SYMBOL(phy_read);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
{
int err;
struct mii_bus *bus = phydev->bus;
spin_lock_bh(&bus->mdio_lock);
err = bus->write(bus, phydev->addr, regnum, val);
spin_unlock_bh(&bus->mdio_lock);
return err;
}
EXPORT_SYMBOL(phy_write);
int phy_clear_interrupt(struct phy_device *phydev)
{
int err = 0;
if (phydev->drv->ack_interrupt)
err = phydev->drv->ack_interrupt(phydev);
return err;
}
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
{
int err = 0;
phydev->interrupts = interrupts;
if (phydev->drv->config_intr)
err = phydev->drv->config_intr(phydev);
return err;
}
/* phy_aneg_done
*
* description: Reads the status register and returns 0 either if
* auto-negotiation is incomplete, or if there was an error.
* Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
*/
static inline int phy_aneg_done(struct phy_device *phydev)
{
int retval;
retval = phy_read(phydev, MII_BMSR);
return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
}
/* A structure for mapping a particular speed and duplex
* combination to a particular SUPPORTED and ADVERTISED value */
struct phy_setting {
int speed;
int duplex;
u32 setting;
};
/* A mapping of all SUPPORTED settings to speed/duplex */
static struct phy_setting settings[] = {
{
.speed = 10000,
.duplex = DUPLEX_FULL,
.setting = SUPPORTED_10000baseT_Full,
},
{
.speed = SPEED_1000,
.duplex = DUPLEX_FULL,
.setting = SUPPORTED_1000baseT_Full,
},
{
.speed = SPEED_1000,
.duplex = DUPLEX_HALF,
.setting = SUPPORTED_1000baseT_Half,
},
{
.speed = SPEED_100,
.duplex = DUPLEX_FULL,
.setting = SUPPORTED_100baseT_Full,
},
{
.speed = SPEED_100,
.duplex = DUPLEX_HALF,
.setting = SUPPORTED_100baseT_Half,
},
{
.speed = SPEED_10,
.duplex = DUPLEX_FULL,
.setting = SUPPORTED_10baseT_Full,
},
{
.speed = SPEED_10,
.duplex = DUPLEX_HALF,
.setting = SUPPORTED_10baseT_Half,
},
};
#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
/* phy_find_setting
*
* description: Searches the settings array for the setting which
* matches the desired speed and duplex, and returns the index
* of that setting. Returns the index of the last setting if
* none of the others match.
*/
static inline int phy_find_setting(int speed, int duplex)
{
int idx = 0;
while (idx < ARRAY_SIZE(settings) &&
(settings[idx].speed != speed ||
settings[idx].duplex != duplex))
idx++;
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
/* phy_find_valid
* idx: The first index in settings[] to search
* features: A mask of the valid settings
*
* description: Returns the index of the first valid setting less
* than or equal to the one pointed to by idx, as determined by
* the mask in features. Returns the index of the last setting
* if nothing else matches.
*/
static inline int phy_find_valid(int idx, u32 features)
{
while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
idx++;
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
/* phy_sanitize_settings
*
* description: Make sure the PHY is set to supported speeds and
* duplexes. Drop down by one in this order: 1000/FULL,
* 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
*/
void phy_sanitize_settings(struct phy_device *phydev)
{
u32 features = phydev->supported;
int idx;
/* Sanitize settings based on PHY capabilities */
if ((features & SUPPORTED_Autoneg) == 0)
phydev->autoneg = 0;
idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
features);
phydev->speed = settings[idx].speed;
phydev->duplex = settings[idx].duplex;
}
EXPORT_SYMBOL(phy_sanitize_settings);
/* phy_ethtool_sset:
* A generic ethtool sset function. Handles all the details
*
* A few notes about parameter checking:
* - We don't set port or transceiver, so we don't care what they
* were set to.
* - phy_start_aneg() will make sure forced settings are sane, and
* choose the next best ones from the ones selected, so we don't
* care if ethtool tries to give us bad values
*
* A note about the PHYCONTROL Layer. If you turn off
* CONFIG_PHYCONTROL, you will need to read the PHY status
* registers after this function completes, and update your
* controller manually.
*/
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
if (cmd->phy_address != phydev->addr)
return -EINVAL;
/* We make sure that we don't pass unsupported
* values in to the PHY */
cmd->advertising &= phydev->supported;
/* Verify the settings we care about. */
if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
return -EINVAL;
if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
return -EINVAL;
if (cmd->autoneg == AUTONEG_DISABLE
&& ((cmd->speed != SPEED_1000
&& cmd->speed != SPEED_100
&& cmd->speed != SPEED_10)
|| (cmd->duplex != DUPLEX_HALF
&& cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
phydev->autoneg = cmd->autoneg;
phydev->speed = cmd->speed;
phydev->advertising = cmd->advertising;
if (AUTONEG_ENABLE == cmd->autoneg)
phydev->advertising |= ADVERTISED_Autoneg;
else
phydev->advertising &= ~ADVERTISED_Autoneg;
phydev->duplex = cmd->duplex;
/* Restart the PHY */
phy_start_aneg(phydev);
return 0;
}
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
cmd->supported = phydev->supported;
cmd->advertising = phydev->advertising;
cmd->speed = phydev->speed;
cmd->duplex = phydev->duplex;
cmd->port = PORT_MII;
cmd->phy_address = phydev->addr;
cmd->transceiver = XCVR_EXTERNAL;
cmd->autoneg = phydev->autoneg;
return 0;
}
/* Note that this function is currently incompatible with the
* PHYCONTROL layer. It changes registers without regard to
* current state. Use at own risk
*/
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd)
{
u16 val = mii_data->val_in;
switch (cmd) {
case SIOCGMIIPHY:
mii_data->phy_id = phydev->addr;
break;
case SIOCGMIIREG:
mii_data->val_out = phy_read(phydev, mii_data->reg_num);
break;
case SIOCSMIIREG:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (mii_data->phy_id == phydev->addr) {
switch(mii_data->reg_num) {
case MII_BMCR:
if (val & (BMCR_RESET|BMCR_ANENABLE))
phydev->autoneg = AUTONEG_DISABLE;
else
phydev->autoneg = AUTONEG_ENABLE;
if ((!phydev->autoneg) && (val & BMCR_FULLDPLX))
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
break;
case MII_ADVERTISE:
phydev->advertising = val;
break;
default:
/* do nothing */
break;
}
}
phy_write(phydev, mii_data->reg_num, val);
if (mii_data->reg_num == MII_BMCR
&& val & BMCR_RESET
&& phydev->drv->config_init)
phydev->drv->config_init(phydev);
break;
}
return 0;
}
/* phy_start_aneg
*
* description: Sanitizes the settings (if we're not
* autonegotiating them), and then calls the driver's
* config_aneg function. If the PHYCONTROL Layer is operating,
* we change the state to reflect the beginning of
* Auto-negotiation or forcing.
*/
int phy_start_aneg(struct phy_device *phydev)
{
int err;
spin_lock(&phydev->lock);
if (AUTONEG_DISABLE == phydev->autoneg)
phy_sanitize_settings(phydev);
err = phydev->drv->config_aneg(phydev);
#ifdef CONFIG_PHYCONTROL
if (err < 0)
goto out_unlock;
if (phydev->state != PHY_HALTED) {
if (AUTONEG_ENABLE == phydev->autoneg) {
phydev->state = PHY_AN;
phydev->link_timeout = PHY_AN_TIMEOUT;
} else {
phydev->state = PHY_FORCING;
phydev->link_timeout = PHY_FORCE_TIMEOUT;
}
}
out_unlock:
#endif
spin_unlock(&phydev->lock);
return err;
}
EXPORT_SYMBOL(phy_start_aneg);
#ifdef CONFIG_PHYCONTROL
static void phy_change(void *data);
static void phy_timer(unsigned long data);
/* phy_start_machine:
*
* description: The PHY infrastructure can run a state machine
* which tracks whether the PHY is starting up, negotiating,
* etc. This function starts the timer which tracks the state
* of the PHY. If you want to be notified when the state
* changes, pass in the callback, otherwise, pass NULL. If you
* want to maintain your own state machine, do not call this
* function. */
void phy_start_machine(struct phy_device *phydev,
void (*handler)(struct net_device *))
{
phydev->adjust_state = handler;
init_timer(&phydev->phy_timer);
phydev->phy_timer.function = &phy_timer;
phydev->phy_timer.data = (unsigned long) phydev;
mod_timer(&phydev->phy_timer, jiffies + HZ);
}
/* phy_stop_machine
*
* description: Stops the state machine timer, sets the state to
* UP (unless it wasn't up yet), and then frees the interrupt,
* if it is in use. This function must be called BEFORE
* phy_detach.
*/
void phy_stop_machine(struct phy_device *phydev)
{
del_timer_sync(&phydev->phy_timer);
spin_lock(&phydev->lock);
if (phydev->state > PHY_UP)
phydev->state = PHY_UP;
spin_unlock(&phydev->lock);
if (phydev->irq != PHY_POLL)
phy_stop_interrupts(phydev);
phydev->adjust_state = NULL;
}
/* phy_force_reduction
*
* description: Reduces the speed/duplex settings by
* one notch. The order is so:
* 1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
* 10/FULL, 10/HALF. The function bottoms out at 10/HALF.
*/
static void phy_force_reduction(struct phy_device *phydev)
{
int idx;
idx = phy_find_setting(phydev->speed, phydev->duplex);
idx++;
idx = phy_find_valid(idx, phydev->supported);
phydev->speed = settings[idx].speed;
phydev->duplex = settings[idx].duplex;
pr_info("Trying %d/%s\n", phydev->speed,
DUPLEX_FULL == phydev->duplex ?
"FULL" : "HALF");
}
/* phy_error:
*
* Moves the PHY to the HALTED state in response to a read
* or write error, and tells the controller the link is down.
* Must not be called from interrupt context, or while the
* phydev->lock is held.
*/
void phy_error(struct phy_device *phydev)
{
spin_lock(&phydev->lock);
phydev->state = PHY_HALTED;
spin_unlock(&phydev->lock);
}
/* phy_interrupt
*
* description: When a PHY interrupt occurs, the handler disables
* interrupts, and schedules a work task to clear the interrupt.
*/
static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs)
{
struct phy_device *phydev = phy_dat;
/* The MDIO bus is not allowed to be written in interrupt
* context, so we need to disable the irq here. A work
* queue will write the PHY to disable and clear the
* interrupt, and then reenable the irq line. */
disable_irq_nosync(irq);
schedule_work(&phydev->phy_queue);
return IRQ_HANDLED;
}
/* Enable the interrupts from the PHY side */
int phy_enable_interrupts(struct phy_device *phydev)
{
int err;
err = phy_clear_interrupt(phydev);
if (err < 0)
return err;
err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
return err;
}
EXPORT_SYMBOL(phy_enable_interrupts);
/* Disable the PHY interrupts from the PHY side */
int phy_disable_interrupts(struct phy_device *phydev)
{
int err;
/* Disable PHY interrupts */
err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
if (err)
goto phy_err;
/* Clear the interrupt */
err = phy_clear_interrupt(phydev);
if (err)
goto phy_err;
return 0;
phy_err:
phy_error(phydev);
return err;
}
EXPORT_SYMBOL(phy_disable_interrupts);
/* phy_start_interrupts
*
* description: Request the interrupt for the given PHY. If
* this fails, then we set irq to PHY_POLL.
* Otherwise, we enable the interrupts in the PHY.
* Returns 0 on success.
* This should only be called with a valid IRQ number.
*/
int phy_start_interrupts(struct phy_device *phydev)
{
int err = 0;
INIT_WORK(&phydev->phy_queue, phy_change, phydev);
if (request_irq(phydev->irq, phy_interrupt,
SA_SHIRQ,
"phy_interrupt",
phydev) < 0) {
printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n",
phydev->bus->name,
phydev->irq);
phydev->irq = PHY_POLL;
return 0;
}
err = phy_enable_interrupts(phydev);
return err;
}
EXPORT_SYMBOL(phy_start_interrupts);
int phy_stop_interrupts(struct phy_device *phydev)
{
int err;
err = phy_disable_interrupts(phydev);
if (err)
phy_error(phydev);
free_irq(phydev->irq, phydev);
return err;
}
EXPORT_SYMBOL(phy_stop_interrupts);
/* Scheduled by the phy_interrupt/timer to handle PHY changes */
static void phy_change(void *data)
{
int err;
struct phy_device *phydev = data;
err = phy_disable_interrupts(phydev);
if (err)
goto phy_err;
spin_lock(&phydev->lock);
if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
phydev->state = PHY_CHANGELINK;
spin_unlock(&phydev->lock);
enable_irq(phydev->irq);
/* Reenable interrupts */
err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
if (err)
goto irq_enable_err;
return;
irq_enable_err:
disable_irq(phydev->irq);
phy_err:
phy_error(phydev);
}
/* Bring down the PHY link, and stop checking the status. */
void phy_stop(struct phy_device *phydev)
{
spin_lock(&phydev->lock);
if (PHY_HALTED == phydev->state)
goto out_unlock;
if (phydev->irq != PHY_POLL) {
/* Clear any pending interrupts */
phy_clear_interrupt(phydev);
/* Disable PHY Interrupts */
phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
}
phydev->state = PHY_HALTED;
out_unlock:
spin_unlock(&phydev->lock);
}
/* phy_start
*
* description: Indicates the attached device's readiness to
* handle PHY-related work. Used during startup to start the
* PHY, and after a call to phy_stop() to resume operation.
* Also used to indicate the MDIO bus has cleared an error
* condition.
*/
void phy_start(struct phy_device *phydev)
{
spin_lock(&phydev->lock);
switch (phydev->state) {
case PHY_STARTING:
phydev->state = PHY_PENDING;
break;
case PHY_READY:
phydev->state = PHY_UP;
break;
case PHY_HALTED:
phydev->state = PHY_RESUMING;
default:
break;
}
spin_unlock(&phydev->lock);
}
EXPORT_SYMBOL(phy_stop);
EXPORT_SYMBOL(phy_start);
/* PHY timer which handles the state machine */
static void phy_timer(unsigned long data)
{
struct phy_device *phydev = (struct phy_device *)data;
int needs_aneg = 0;
int err = 0;
spin_lock(&phydev->lock);
if (phydev->adjust_state)
phydev->adjust_state(phydev->attached_dev);
switch(phydev->state) {
case PHY_DOWN:
case PHY_STARTING:
case PHY_READY:
case PHY_PENDING:
break;
case PHY_UP:
needs_aneg = 1;
phydev->link_timeout = PHY_AN_TIMEOUT;
break;
case PHY_AN:
/* Check if negotiation is done. Break
* if there's an error */
err = phy_aneg_done(phydev);
if (err < 0)
break;
/* If auto-negotiation is done, we change to
* either RUNNING, or NOLINK */
if (err > 0) {
err = phy_read_status(phydev);
if (err)
break;
if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
netif_carrier_off(phydev->attached_dev);
}
phydev->adjust_link(phydev->attached_dev);
} else if (0 == phydev->link_timeout--) {
/* The counter expired, so either we
* switch to forced mode, or the
* magic_aneg bit exists, and we try aneg
* again */
if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) {
int idx;
/* We'll start from the
* fastest speed, and work
* our way down */
idx = phy_find_valid(0,
phydev->supported);
phydev->speed = settings[idx].speed;
phydev->duplex = settings[idx].duplex;
phydev->autoneg = AUTONEG_DISABLE;
phydev->state = PHY_FORCING;
phydev->link_timeout =
PHY_FORCE_TIMEOUT;
pr_info("Trying %d/%s\n",
phydev->speed,
DUPLEX_FULL ==
phydev->duplex ?
"FULL" : "HALF");
}
needs_aneg = 1;
}
break;
case PHY_NOLINK:
err = phy_read_status(phydev);
if (err)
break;
if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
}
break;
case PHY_FORCING:
err = phy_read_status(phydev);
if (err)
break;
if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
if (0 == phydev->link_timeout--) {
phy_force_reduction(phydev);
needs_aneg = 1;
}
}
phydev->adjust_link(phydev->attached_dev);
break;
case PHY_RUNNING:
/* Only register a CHANGE if we are
* polling */
if (PHY_POLL == phydev->irq)
phydev->state = PHY_CHANGELINK;
break;
case PHY_CHANGELINK:
err = phy_read_status(phydev);
if (err)
break;
if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
netif_carrier_off(phydev->attached_dev);
}
phydev->adjust_link(phydev->attached_dev);
if (PHY_POLL != phydev->irq)
err = phy_config_interrupt(phydev,
PHY_INTERRUPT_ENABLED);
break;
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
}
break;
case PHY_RESUMING:
err = phy_clear_interrupt(phydev);
if (err)
break;
err = phy_config_interrupt(phydev,
PHY_INTERRUPT_ENABLED);
if (err)
break;
if (AUTONEG_ENABLE == phydev->autoneg) {
err = phy_aneg_done(phydev);
if (err < 0)
break;
/* err > 0 if AN is done.
* Otherwise, it's 0, and we're
* still waiting for AN */
if (err > 0) {
phydev->state = PHY_RUNNING;
} else {
phydev->state = PHY_AN;
phydev->link_timeout = PHY_AN_TIMEOUT;
}
} else
phydev->state = PHY_RUNNING;
break;
}
spin_unlock(&phydev->lock);
if (needs_aneg)
err = phy_start_aneg(phydev);
if (err < 0)
phy_error(phydev);
mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
}
#endif /* CONFIG_PHYCONTROL */

Просмотреть файл

@ -0,0 +1,696 @@
/*
* drivers/net/phy/phy_device.c
*
* Framework for finding and configuring PHYs.
* Also contains generic PHY driver
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
static struct phy_driver genphy_driver;
extern int mdio_bus_init(void);
extern void mdio_bus_exit(void);
/* get_phy_device
*
* description: Reads the ID registers of the PHY at addr on the
* bus, then allocates and returns the phy_device to
* represent it.
*/
struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
{
int phy_reg;
u32 phy_id;
struct phy_device *dev = NULL;
/* Grab the bits from PHYIR1, and put them
* in the upper half */
phy_reg = bus->read(bus, addr, MII_PHYSID1);
if (phy_reg < 0)
return ERR_PTR(phy_reg);
phy_id = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = bus->read(bus, addr, MII_PHYSID2);
if (phy_reg < 0)
return ERR_PTR(phy_reg);
phy_id |= (phy_reg & 0xffff);
/* If the phy_id is all Fs, there is no device there */
if (0xffffffff == phy_id)
return NULL;
/* Otherwise, we allocate the device, and initialize the
* default values */
dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
if (NULL == dev)
return ERR_PTR(-ENOMEM);
dev->speed = 0;
dev->duplex = -1;
dev->pause = dev->asym_pause = 0;
dev->link = 1;
dev->autoneg = AUTONEG_ENABLE;
dev->addr = addr;
dev->phy_id = phy_id;
dev->bus = bus;
dev->state = PHY_DOWN;
spin_lock_init(&dev->lock);
return dev;
}
#ifdef CONFIG_PHYCONTROL
/* phy_prepare_link:
*
* description: Tells the PHY infrastructure to handle the
* gory details on monitoring link status (whether through
* polling or an interrupt), and to call back to the
* connected device driver when the link status changes.
* If you want to monitor your own link state, don't call
* this function */
void phy_prepare_link(struct phy_device *phydev,
void (*handler)(struct net_device *))
{
phydev->adjust_link = handler;
}
/* phy_connect:
*
* description: Convenience function for connecting ethernet
* devices to PHY devices. The default behavior is for
* the PHY infrastructure to handle everything, and only notify
* the connected driver when the link status changes. If you
* don't want, or can't use the provided functionality, you may
* choose to call only the subset of functions which provide
* the desired functionality.
*/
struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
void (*handler)(struct net_device *), u32 flags)
{
struct phy_device *phydev;
phydev = phy_attach(dev, phy_id, flags);
if (IS_ERR(phydev))
return phydev;
phy_prepare_link(phydev, handler);
phy_start_machine(phydev, NULL);
if (phydev->irq > 0)
phy_start_interrupts(phydev);
return phydev;
}
EXPORT_SYMBOL(phy_connect);
void phy_disconnect(struct phy_device *phydev)
{
if (phydev->irq > 0)
phy_stop_interrupts(phydev);
phy_stop_machine(phydev);
phydev->adjust_link = NULL;
phy_detach(phydev);
}
EXPORT_SYMBOL(phy_disconnect);
#endif /* CONFIG_PHYCONTROL */
/* phy_attach:
*
* description: Called by drivers to attach to a particular PHY
* device. The phy_device is found, and properly hooked up
* to the phy_driver. If no driver is attached, then the
* genphy_driver is used. The phy_device is given a ptr to
* the attaching device, and given a callback for link status
* change. The phy_device is returned to the attaching
* driver.
*/
static int phy_compare_id(struct device *dev, void *data)
{
return strcmp((char *)data, dev->bus_id) ? 0 : 1;
}
struct phy_device *phy_attach(struct net_device *dev,
const char *phy_id, u32 flags)
{
struct bus_type *bus = &mdio_bus_type;
struct phy_device *phydev;
struct device *d;
/* Search the list of PHY devices on the mdio bus for the
* PHY with the requested name */
d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id);
if (d) {
phydev = to_phy_device(d);
} else {
printk(KERN_ERR "%s not found\n", phy_id);
return ERR_PTR(-ENODEV);
}
/* Assume that if there is no driver, that it doesn't
* exist, and we should use the genphy driver. */
if (NULL == d->driver) {
int err;
down_write(&d->bus->subsys.rwsem);
d->driver = &genphy_driver.driver;
err = d->driver->probe(d);
if (err < 0)
return ERR_PTR(err);
device_bind_driver(d);
up_write(&d->bus->subsys.rwsem);
}
if (phydev->attached_dev) {
printk(KERN_ERR "%s: %s already attached\n",
dev->name, phy_id);
return ERR_PTR(-EBUSY);
}
phydev->attached_dev = dev;
phydev->dev_flags = flags;
return phydev;
}
EXPORT_SYMBOL(phy_attach);
void phy_detach(struct phy_device *phydev)
{
phydev->attached_dev = NULL;
/* If the device had no specific driver before (i.e. - it
* was using the generic driver), we unbind the device
* from the generic driver so that there's a chance a
* real driver could be loaded */
if (phydev->dev.driver == &genphy_driver.driver) {
down_write(&phydev->dev.bus->subsys.rwsem);
device_release_driver(&phydev->dev);
up_write(&phydev->dev.bus->subsys.rwsem);
}
}
EXPORT_SYMBOL(phy_detach);
/* Generic PHY support and helper functions */
/* genphy_config_advert
*
* description: Writes MII_ADVERTISE with the appropriate values,
* after sanitizing the values to make sure we only advertise
* what is supported
*/
int genphy_config_advert(struct phy_device *phydev)
{
u32 advertise;
int adv;
int err;
/* Only allow advertising what
* this PHY supports */
phydev->advertising &= phydev->supported;
advertise = phydev->advertising;
/* Setup standard advertisement */
adv = phy_read(phydev, MII_ADVERTISE);
if (adv < 0)
return adv;
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
if (advertise & ADVERTISED_10baseT_Half)
adv |= ADVERTISE_10HALF;
if (advertise & ADVERTISED_10baseT_Full)
adv |= ADVERTISE_10FULL;
if (advertise & ADVERTISED_100baseT_Half)
adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
if (advertise & ADVERTISED_Pause)
adv |= ADVERTISE_PAUSE_CAP;
if (advertise & ADVERTISED_Asym_Pause)
adv |= ADVERTISE_PAUSE_ASYM;
err = phy_write(phydev, MII_ADVERTISE, adv);
if (err < 0)
return err;
/* Configure gigabit if it's supported */
if (phydev->supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full)) {
adv = phy_read(phydev, MII_CTRL1000);
if (adv < 0)
return adv;
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
if (advertise & SUPPORTED_1000baseT_Half)
adv |= ADVERTISE_1000HALF;
if (advertise & SUPPORTED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
err = phy_write(phydev, MII_CTRL1000, adv);
if (err < 0)
return err;
}
return adv;
}
EXPORT_SYMBOL(genphy_config_advert);
/* genphy_setup_forced
*
* description: Configures MII_BMCR to force speed/duplex
* to the values in phydev. Assumes that the values are valid.
* Please see phy_sanitize_settings() */
int genphy_setup_forced(struct phy_device *phydev)
{
int ctl = BMCR_RESET;
phydev->pause = phydev->asym_pause = 0;
if (SPEED_1000 == phydev->speed)
ctl |= BMCR_SPEED1000;
else if (SPEED_100 == phydev->speed)
ctl |= BMCR_SPEED100;
if (DUPLEX_FULL == phydev->duplex)
ctl |= BMCR_FULLDPLX;
ctl = phy_write(phydev, MII_BMCR, ctl);
if (ctl < 0)
return ctl;
/* We just reset the device, so we'd better configure any
* settings the PHY requires to operate */
if (phydev->drv->config_init)
ctl = phydev->drv->config_init(phydev);
return ctl;
}
/* Enable and Restart Autonegotiation */
int genphy_restart_aneg(struct phy_device *phydev)
{
int ctl;
ctl = phy_read(phydev, MII_BMCR);
if (ctl < 0)
return ctl;
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
/* Don't isolate the PHY if we're negotiating */
ctl &= ~(BMCR_ISOLATE);
ctl = phy_write(phydev, MII_BMCR, ctl);
return ctl;
}
/* genphy_config_aneg
*
* description: If auto-negotiation is enabled, we configure the
* advertising, and then restart auto-negotiation. If it is not
* enabled, then we write the BMCR
*/
int genphy_config_aneg(struct phy_device *phydev)
{
int err = 0;
if (AUTONEG_ENABLE == phydev->autoneg) {
err = genphy_config_advert(phydev);
if (err < 0)
return err;
err = genphy_restart_aneg(phydev);
} else
err = genphy_setup_forced(phydev);
return err;
}
EXPORT_SYMBOL(genphy_config_aneg);
/* genphy_update_link
*
* description: Update the value in phydev->link to reflect the
* current link value. In order to do this, we need to read
* the status register twice, keeping the second value
*/
int genphy_update_link(struct phy_device *phydev)
{
int status;
/* Do a fake read */
status = phy_read(phydev, MII_BMSR);
if (status < 0)
return status;
/* Read link and autonegotiation status */
status = phy_read(phydev, MII_BMSR);
if (status < 0)
return status;
if ((status & BMSR_LSTATUS) == 0)
phydev->link = 0;
else
phydev->link = 1;
return 0;
}
/* genphy_read_status
*
* description: Check the link, then figure out the current state
* by comparing what we advertise with what the link partner
* advertises. Start by checking the gigabit possibilities,
* then move on to 10/100.
*/
int genphy_read_status(struct phy_device *phydev)
{
int adv;
int err;
int lpa;
int lpagb = 0;
/* Update the link, but return if there
* was an error */
err = genphy_update_link(phydev);
if (err)
return err;
if (AUTONEG_ENABLE == phydev->autoneg) {
if (phydev->supported & (SUPPORTED_1000baseT_Half
| SUPPORTED_1000baseT_Full)) {
lpagb = phy_read(phydev, MII_STAT1000);
if (lpagb < 0)
return lpagb;
adv = phy_read(phydev, MII_CTRL1000);
if (adv < 0)
return adv;
lpagb &= adv << 2;
}
lpa = phy_read(phydev, MII_LPA);
if (lpa < 0)
return lpa;
adv = phy_read(phydev, MII_ADVERTISE);
if (adv < 0)
return adv;
lpa &= adv;
phydev->speed = SPEED_10;
phydev->duplex = DUPLEX_HALF;
phydev->pause = phydev->asym_pause = 0;
if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
phydev->speed = SPEED_1000;
if (lpagb & LPA_1000FULL)
phydev->duplex = DUPLEX_FULL;
} else if (lpa & (LPA_100FULL | LPA_100HALF)) {
phydev->speed = SPEED_100;
if (lpa & LPA_100FULL)
phydev->duplex = DUPLEX_FULL;
} else
if (lpa & LPA_10FULL)
phydev->duplex = DUPLEX_FULL;
if (phydev->duplex == DUPLEX_FULL){
phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
}
} else {
int bmcr = phy_read(phydev, MII_BMCR);
if (bmcr < 0)
return bmcr;
if (bmcr & BMCR_FULLDPLX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
if (bmcr & BMCR_SPEED1000)
phydev->speed = SPEED_1000;
else if (bmcr & BMCR_SPEED100)
phydev->speed = SPEED_100;
else
phydev->speed = SPEED_10;
phydev->pause = phydev->asym_pause = 0;
}
return 0;
}
EXPORT_SYMBOL(genphy_read_status);
static int genphy_config_init(struct phy_device *phydev)
{
u32 val;
u32 features;
/* For now, I'll claim that the generic driver supports
* all possible port types */
features = (SUPPORTED_TP | SUPPORTED_MII
| SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC);
/* Do we support autonegotiation? */
val = phy_read(phydev, MII_BMSR);
if (val < 0)
return val;
if (val & BMSR_ANEGCAPABLE)
features |= SUPPORTED_Autoneg;
if (val & BMSR_100FULL)
features |= SUPPORTED_100baseT_Full;
if (val & BMSR_100HALF)
features |= SUPPORTED_100baseT_Half;
if (val & BMSR_10FULL)
features |= SUPPORTED_10baseT_Full;
if (val & BMSR_10HALF)
features |= SUPPORTED_10baseT_Half;
if (val & BMSR_ESTATEN) {
val = phy_read(phydev, MII_ESTATUS);
if (val < 0)
return val;
if (val & ESTATUS_1000_TFULL)
features |= SUPPORTED_1000baseT_Full;
if (val & ESTATUS_1000_THALF)
features |= SUPPORTED_1000baseT_Half;
}
phydev->supported = features;
phydev->advertising = features;
return 0;
}
/* phy_probe
*
* description: Take care of setting up the phy_device structure,
* set the state to READY (the driver's init function should
* set it to STARTING if needed).
*/
static int phy_probe(struct device *dev)
{
struct phy_device *phydev;
struct phy_driver *phydrv;
struct device_driver *drv;
int err = 0;
phydev = to_phy_device(dev);
/* Make sure the driver is held.
* XXX -- Is this correct? */
drv = get_driver(phydev->dev.driver);
phydrv = to_phy_driver(drv);
phydev->drv = phydrv;
/* Disable the interrupt if the PHY doesn't support it */
if (!(phydrv->flags & PHY_HAS_INTERRUPT))
phydev->irq = PHY_POLL;
spin_lock(&phydev->lock);
/* Start out supporting everything. Eventually,
* a controller will attach, and may modify one
* or both of these values */
phydev->supported = phydrv->features;
phydev->advertising = phydrv->features;
/* Set the state to READY by default */
phydev->state = PHY_READY;
if (phydev->drv->probe)
err = phydev->drv->probe(phydev);
spin_unlock(&phydev->lock);
if (err < 0)
return err;
if (phydev->drv->config_init)
err = phydev->drv->config_init(phydev);
return err;
}
static int phy_remove(struct device *dev)
{
struct phy_device *phydev;
phydev = to_phy_device(dev);
spin_lock(&phydev->lock);
phydev->state = PHY_DOWN;
spin_unlock(&phydev->lock);
if (phydev->drv->remove)
phydev->drv->remove(phydev);
put_driver(dev->driver);
phydev->drv = NULL;
return 0;
}
int phy_driver_register(struct phy_driver *new_driver)
{
int retval;
memset(&new_driver->driver, 0, sizeof(new_driver->driver));
new_driver->driver.name = new_driver->name;
new_driver->driver.bus = &mdio_bus_type;
new_driver->driver.probe = phy_probe;
new_driver->driver.remove = phy_remove;
retval = driver_register(&new_driver->driver);
if (retval) {
printk(KERN_ERR "%s: Error %d in registering driver\n",
new_driver->name, retval);
return retval;
}
pr_info("%s: Registered new driver\n", new_driver->name);
return 0;
}
EXPORT_SYMBOL(phy_driver_register);
void phy_driver_unregister(struct phy_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL(phy_driver_unregister);
static struct phy_driver genphy_driver = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic PHY",
.config_init = genphy_config_init,
.features = 0,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.driver = {.owner= THIS_MODULE, },
};
static int __init phy_init(void)
{
int rc;
rc = mdio_bus_init();
if (rc)
return rc;
rc = phy_driver_register(&genphy_driver);
if (rc)
mdio_bus_exit();
return rc;
}
static void __exit phy_exit(void)
{
phy_driver_unregister(&genphy_driver);
mdio_bus_exit();
}
subsys_initcall(phy_init);
module_exit(phy_exit);

143
drivers/net/phy/qsemi.c Normal file
Просмотреть файл

@ -0,0 +1,143 @@
/*
* drivers/net/phy/qsemi.c
*
* Driver for Quality Semiconductor PHYs
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
/* ------------------------------------------------------------------------- */
/* The Quality Semiconductor QS6612 is used on the RPX CLLF */
/* register definitions */
#define MII_QS6612_MCR 17 /* Mode Control Register */
#define MII_QS6612_FTR 27 /* Factory Test Register */
#define MII_QS6612_MCO 28 /* Misc. Control Register */
#define MII_QS6612_ISR 29 /* Interrupt Source Register */
#define MII_QS6612_IMR 30 /* Interrupt Mask Register */
#define MII_QS6612_IMR_INIT 0x003a
#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */
#define QS6612_PCR_AN_COMPLETE 0x1000
#define QS6612_PCR_RLBEN 0x0200
#define QS6612_PCR_DCREN 0x0100
#define QS6612_PCR_4B5BEN 0x0040
#define QS6612_PCR_TX_ISOLATE 0x0020
#define QS6612_PCR_MLT3_DIS 0x0002
#define QS6612_PCR_SCRM_DESCRM 0x0001
MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
/* Returns 0, unless there's a write error */
static int qs6612_config_init(struct phy_device *phydev)
{
/* The PHY powers up isolated on the RPX,
* so send a command to allow operation.
* XXX - My docs indicate this should be 0x0940
* ...or something. The current value sets three
* reserved bits, bit 11, which specifies it should be
* set to one, bit 10, which specifies it should be set
* to 0, and bit 7, which doesn't specify. However, my
* docs are preliminary, and I will leave it like this
* until someone more knowledgable corrects me or it.
* -- Andy Fleming
*/
return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
}
static int qs6612_ack_interrupt(struct phy_device *phydev)
{
int err;
err = phy_read(phydev, MII_QS6612_ISR);
if (err < 0)
return err;
err = phy_read(phydev, MII_BMSR);
if (err < 0)
return err;
err = phy_read(phydev, MII_EXPANSION);
if (err < 0)
return err;
return 0;
}
static int qs6612_config_intr(struct phy_device *phydev)
{
int err;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_QS6612_IMR,
MII_QS6612_IMR_INIT);
else
err = phy_write(phydev, MII_QS6612_IMR, 0);
return err;
}
static struct phy_driver qs6612_driver = {
.phy_id = 0x00181440,
.name = "QS6612",
.phy_id_mask = 0xfffffff0,
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = qs6612_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = qs6612_ack_interrupt,
.config_intr = qs6612_config_intr,
.driver = { .owner = THIS_MODULE,},
};
static int __init qs6612_init(void)
{
return phy_driver_register(&qs6612_driver);
}
static void __exit qs6612_exit(void)
{
phy_driver_unregister(&qs6612_driver);
}
module_init(qs6612_init);
module_exit(qs6612_exit);

Просмотреть файл

@ -187,6 +187,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), },
{ PCI_DEVICE(0x16ec, 0x0116), },
{ PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, },
{0,},
};

Просмотреть файл

@ -62,6 +62,7 @@ typedef struct _XENA_dev_config {
#define ADAPTER_STATUS_RMAC_REMOTE_FAULT BIT(6)
#define ADAPTER_STATUS_RMAC_LOCAL_FAULT BIT(7)
#define ADAPTER_STATUS_RMAC_PCC_IDLE vBIT(0xFF,8,8)
#define ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE vBIT(0x0F,8,8)
#define ADAPTER_STATUS_RC_PRC_QUIESCENT vBIT(0xFF,16,8)
#define ADAPTER_STATUS_MC_DRAM_READY BIT(24)
#define ADAPTER_STATUS_MC_QUEUES_READY BIT(25)
@ -77,21 +78,34 @@ typedef struct _XENA_dev_config {
#define ADAPTER_ECC_EN BIT(55)
u64 serr_source;
#define SERR_SOURCE_PIC BIT(0)
#define SERR_SOURCE_TXDMA BIT(1)
#define SERR_SOURCE_RXDMA BIT(2)
#define SERR_SOURCE_PIC BIT(0)
#define SERR_SOURCE_TXDMA BIT(1)
#define SERR_SOURCE_RXDMA BIT(2)
#define SERR_SOURCE_MAC BIT(3)
#define SERR_SOURCE_MC BIT(4)
#define SERR_SOURCE_XGXS BIT(5)
#define SERR_SOURCE_ANY (SERR_SOURCE_PIC | \
SERR_SOURCE_TXDMA | \
SERR_SOURCE_RXDMA | \
SERR_SOURCE_MAC | \
SERR_SOURCE_MC | \
SERR_SOURCE_XGXS)
#define SERR_SOURCE_ANY (SERR_SOURCE_PIC | \
SERR_SOURCE_TXDMA | \
SERR_SOURCE_RXDMA | \
SERR_SOURCE_MAC | \
SERR_SOURCE_MC | \
SERR_SOURCE_XGXS)
u64 pci_mode;
#define GET_PCI_MODE(val) ((val & vBIT(0xF, 0, 4)) >> 60)
#define PCI_MODE_PCI_33 0
#define PCI_MODE_PCI_66 0x1
#define PCI_MODE_PCIX_M1_66 0x2
#define PCI_MODE_PCIX_M1_100 0x3
#define PCI_MODE_PCIX_M1_133 0x4
#define PCI_MODE_PCIX_M2_66 0x5
#define PCI_MODE_PCIX_M2_100 0x6
#define PCI_MODE_PCIX_M2_133 0x7
#define PCI_MODE_UNSUPPORTED BIT(0)
#define PCI_MODE_32_BITS BIT(8)
#define PCI_MODE_UNKNOWN_MODE BIT(9)
u8 unused_0[0x800 - 0x120];
u8 unused_0[0x800 - 0x128];
/* PCI-X Controller registers */
u64 pic_int_status;
@ -153,7 +167,11 @@ typedef struct _XENA_dev_config {
u8 unused4[0x08];
u64 gpio_int_reg;
#define GPIO_INT_REG_LINK_DOWN BIT(1)
#define GPIO_INT_REG_LINK_UP BIT(2)
u64 gpio_int_mask;
#define GPIO_INT_MASK_LINK_DOWN BIT(1)
#define GPIO_INT_MASK_LINK_UP BIT(2)
u64 gpio_alarms;
u8 unused5[0x38];
@ -223,19 +241,16 @@ typedef struct _XENA_dev_config {
u64 xmsi_data;
u64 rx_mat;
#define RX_MAT_SET(ring, msi) vBIT(msi, (8 * ring), 8)
u8 unused6[0x8];
u64 tx_mat0_7;
u64 tx_mat8_15;
u64 tx_mat16_23;
u64 tx_mat24_31;
u64 tx_mat32_39;
u64 tx_mat40_47;
u64 tx_mat48_55;
u64 tx_mat56_63;
u64 tx_mat0_n[0x8];
#define TX_MAT_SET(fifo, msi) vBIT(msi, (8 * fifo), 8)
u8 unused_1[0x10];
u8 unused_1[0x8];
u64 stat_byte_cnt;
#define STAT_BC(n) vBIT(n,4,12)
/* Automated statistics collection */
u64 stat_cfg;
@ -246,6 +261,7 @@ typedef struct _XENA_dev_config {
#define STAT_TRSF_PER(n) TBD
#define PER_SEC 0x208d5
#define SET_UPDT_PERIOD(n) vBIT((PER_SEC*n),32,32)
#define SET_UPDT_CLICKS(val) vBIT(val, 32, 32)
u64 stat_addr;
@ -267,8 +283,15 @@ typedef struct _XENA_dev_config {
u64 gpio_control;
#define GPIO_CTRL_GPIO_0 BIT(8)
u64 misc_control;
#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3)
u8 unused7[0x600];
u8 unused7_1[0x240 - 0x208];
u64 wreq_split_mask;
#define WREQ_SPLIT_MASK_SET_MASK(val) vBIT(val, 52, 12)
u8 unused7_2[0x800 - 0x248];
/* TxDMA registers */
u64 txdma_int_status;
@ -290,6 +313,7 @@ typedef struct _XENA_dev_config {
u64 pcc_err_reg;
#define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8)
#define PCC_ENABLE_FOUR vBIT(0x0F,0,8)
u64 pcc_err_mask;
u64 pcc_err_alarm;
@ -468,6 +492,7 @@ typedef struct _XENA_dev_config {
#define PRC_CTRL_NO_SNOOP (BIT(22)|BIT(23))
#define PRC_CTRL_NO_SNOOP_DESC BIT(22)
#define PRC_CTRL_NO_SNOOP_BUFF BIT(23)
#define PRC_CTRL_BIMODAL_INTERRUPT BIT(37)
#define PRC_CTRL_RXD_BACKOFF_INTERVAL(val) vBIT(val,40,24)
u64 prc_alarm_action;
@ -691,6 +716,10 @@ typedef struct _XENA_dev_config {
#define MC_ERR_REG_MIRI_CRI_ERR_0 BIT(22)
#define MC_ERR_REG_MIRI_CRI_ERR_1 BIT(23)
#define MC_ERR_REG_SM_ERR BIT(31)
#define MC_ERR_REG_ECC_ALL_SNG (BIT(6) | \
BIT(7) | BIT(17) | BIT(19))
#define MC_ERR_REG_ECC_ALL_DBL (BIT(14) | \
BIT(15) | BIT(18) | BIT(20))
u64 mc_err_mask;
u64 mc_err_alarm;
@ -736,7 +765,19 @@ typedef struct _XENA_dev_config {
u64 mc_rldram_test_d1;
u8 unused24[0x300 - 0x288];
u64 mc_rldram_test_d2;
u8 unused25[0x700 - 0x308];
u8 unused24_1[0x360 - 0x308];
u64 mc_rldram_ctrl;
#define MC_RLDRAM_ENABLE_ODT BIT(7)
u8 unused24_2[0x640 - 0x368];
u64 mc_rldram_ref_per_herc;
#define MC_RLDRAM_SET_REF_PERIOD(val) vBIT(val, 0, 16)
u8 unused24_3[0x660 - 0x648];
u64 mc_rldram_mrs_herc;
u8 unused25[0x700 - 0x668];
u64 mc_debug_ctrl;
u8 unused26[0x3000 - 0x2f08];

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -31,6 +31,9 @@
#define SUCCESS 0
#define FAILURE -1
/* Maximum time to flicker LED when asked to identify NIC using ethtool */
#define MAX_FLICKER_TIME 60000 /* 60 Secs */
/* Maximum outstanding splits to be configured into xena. */
typedef enum xena_max_outstanding_splits {
XENA_ONE_SPLIT_TRANSACTION = 0,
@ -45,10 +48,10 @@ typedef enum xena_max_outstanding_splits {
#define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4)
/* OS concerned variables and constants */
#define WATCH_DOG_TIMEOUT 5*HZ
#define EFILL 0x1234
#define ALIGN_SIZE 127
#define PCIX_COMMAND_REGISTER 0x62
#define WATCH_DOG_TIMEOUT 15*HZ
#define EFILL 0x1234
#define ALIGN_SIZE 127
#define PCIX_COMMAND_REGISTER 0x62
/*
* Debug related variables.
@ -61,7 +64,7 @@ typedef enum xena_max_outstanding_splits {
#define INTR_DBG 4
/* Global variable that defines the present debug level of the driver. */
static int debug_level = ERR_DBG; /* Default level. */
int debug_level = ERR_DBG; /* Default level. */
/* DEBUG message print. */
#define DBG_PRINT(dbg_level, args...) if(!(debug_level<dbg_level)) printk(args)
@ -71,6 +74,12 @@ static int debug_level = ERR_DBG; /* Default level. */
#define L4_CKSUM_OK 0xFFFF
#define S2IO_JUMBO_SIZE 9600
/* Driver statistics maintained by driver */
typedef struct {
unsigned long long single_ecc_errs;
unsigned long long double_ecc_errs;
} swStat_t;
/* The statistics block of Xena */
typedef struct stat_block {
/* Tx MAC statistics counters. */
@ -186,12 +195,90 @@ typedef struct stat_block {
u32 rxd_rd_cnt;
u32 rxf_wr_cnt;
u32 txf_rd_cnt;
/* Tx MAC statistics overflow counters. */
u32 tmac_data_octets_oflow;
u32 tmac_frms_oflow;
u32 tmac_bcst_frms_oflow;
u32 tmac_mcst_frms_oflow;
u32 tmac_ucst_frms_oflow;
u32 tmac_ttl_octets_oflow;
u32 tmac_any_err_frms_oflow;
u32 tmac_nucst_frms_oflow;
u64 tmac_vlan_frms;
u32 tmac_drop_ip_oflow;
u32 tmac_vld_ip_oflow;
u32 tmac_rst_tcp_oflow;
u32 tmac_icmp_oflow;
u32 tpa_unknown_protocol;
u32 tmac_udp_oflow;
u32 reserved_10;
u32 tpa_parse_failure;
/* Rx MAC Statistics overflow counters. */
u32 rmac_data_octets_oflow;
u32 rmac_vld_frms_oflow;
u32 rmac_vld_bcst_frms_oflow;
u32 rmac_vld_mcst_frms_oflow;
u32 rmac_accepted_ucst_frms_oflow;
u32 rmac_ttl_octets_oflow;
u32 rmac_discarded_frms_oflow;
u32 rmac_accepted_nucst_frms_oflow;
u32 rmac_usized_frms_oflow;
u32 rmac_drop_events_oflow;
u32 rmac_frag_frms_oflow;
u32 rmac_osized_frms_oflow;
u32 rmac_ip_oflow;
u32 rmac_jabber_frms_oflow;
u32 rmac_icmp_oflow;
u32 rmac_drop_ip_oflow;
u32 rmac_err_drp_udp_oflow;
u32 rmac_udp_oflow;
u32 reserved_11;
u32 rmac_pause_cnt_oflow;
u64 rmac_ttl_1519_4095_frms;
u64 rmac_ttl_4096_8191_frms;
u64 rmac_ttl_8192_max_frms;
u64 rmac_ttl_gt_max_frms;
u64 rmac_osized_alt_frms;
u64 rmac_jabber_alt_frms;
u64 rmac_gt_max_alt_frms;
u64 rmac_vlan_frms;
u32 rmac_len_discard;
u32 rmac_fcs_discard;
u32 rmac_pf_discard;
u32 rmac_da_discard;
u32 rmac_red_discard;
u32 rmac_rts_discard;
u32 reserved_12;
u32 rmac_ingm_full_discard;
u32 reserved_13;
u32 rmac_accepted_ip_oflow;
u32 reserved_14;
u32 link_fault_cnt;
swStat_t sw_stat;
} StatInfo_t;
/* Structures representing different init time configuration
/*
* Structures representing different init time configuration
* parameters of the NIC.
*/
#define MAX_TX_FIFOS 8
#define MAX_RX_RINGS 8
/* FIFO mappings for all possible number of fifos configured */
int fifo_map[][MAX_TX_FIFOS] = {
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 1, 1, 1},
{0, 0, 0, 1, 1, 1, 2, 2},
{0, 0, 1, 1, 2, 2, 3, 3},
{0, 0, 1, 1, 2, 2, 3, 4},
{0, 0, 1, 1, 2, 3, 4, 5},
{0, 0, 1, 2, 3, 4, 5, 6},
{0, 1, 2, 3, 4, 5, 6, 7},
};
/* Maintains Per FIFO related information. */
typedef struct tx_fifo_config {
#define MAX_AVAILABLE_TXDS 8192
@ -237,14 +324,14 @@ typedef struct rx_ring_config {
#define NO_SNOOP_RXD_BUFFER 0x02
} rx_ring_config_t;
/* This structure provides contains values of the tunable parameters
* of the H/W
/* This structure provides contains values of the tunable parameters
* of the H/W
*/
struct config_param {
/* Tx Side */
u32 tx_fifo_num; /*Number of Tx FIFOs */
#define MAX_TX_FIFOS 8
u8 fifo_mapping[MAX_TX_FIFOS];
tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */
u64 tx_intr_type;
@ -252,10 +339,10 @@ struct config_param {
/* Rx Side */
u32 rx_ring_num; /*Number of receive rings */
#define MAX_RX_RINGS 8
#define MAX_RX_BLOCKS_PER_RING 150
rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
u8 bimodal; /*Flag for setting bimodal interrupts*/
#define HEADER_ETHERNET_II_802_3_SIZE 14
#define HEADER_802_2_SIZE 3
@ -269,6 +356,7 @@ struct config_param {
#define MAX_PYLD_JUMBO 9600
#define MAX_MTU_JUMBO (MAX_PYLD_JUMBO+18)
#define MAX_MTU_JUMBO_VLAN (MAX_PYLD_JUMBO+22)
u16 bus_speed;
};
/* Structure representing MAC Addrs */
@ -277,7 +365,7 @@ typedef struct mac_addr {
} macaddr_t;
/* Structure that represent every FIFO element in the BAR1
* Address location.
* Address location.
*/
typedef struct _TxFIFO_element {
u64 TxDL_Pointer;
@ -339,6 +427,7 @@ typedef struct _RxD_t {
#define RXD_FRAME_PROTO vBIT(0xFFFF,24,8)
#define RXD_FRAME_PROTO_IPV4 BIT(27)
#define RXD_FRAME_PROTO_IPV6 BIT(28)
#define RXD_FRAME_IP_FRAG BIT(29)
#define RXD_FRAME_PROTO_TCP BIT(30)
#define RXD_FRAME_PROTO_UDP BIT(31)
#define TCP_OR_UDP_FRAME (RXD_FRAME_PROTO_TCP | RXD_FRAME_PROTO_UDP)
@ -346,11 +435,15 @@ typedef struct _RxD_t {
#define RXD_GET_L4_CKSUM(val) ((u16)(val) & 0xFFFF)
u64 Control_2;
#define THE_RXD_MARK 0x3
#define SET_RXD_MARKER vBIT(THE_RXD_MARK, 0, 2)
#define GET_RXD_MARKER(ctrl) ((ctrl & SET_RXD_MARKER) >> 62)
#ifndef CONFIG_2BUFF_MODE
#define MASK_BUFFER0_SIZE vBIT(0xFFFF,0,16)
#define SET_BUFFER0_SIZE(val) vBIT(val,0,16)
#define MASK_BUFFER0_SIZE vBIT(0x3FFF,2,14)
#define SET_BUFFER0_SIZE(val) vBIT(val,2,14)
#else
#define MASK_BUFFER0_SIZE vBIT(0xFF,0,16)
#define MASK_BUFFER0_SIZE vBIT(0xFF,2,14)
#define MASK_BUFFER1_SIZE vBIT(0xFFFF,16,16)
#define MASK_BUFFER2_SIZE vBIT(0xFFFF,32,16)
#define SET_BUFFER0_SIZE(val) vBIT(val,8,8)
@ -363,7 +456,7 @@ typedef struct _RxD_t {
#define SET_NUM_TAG(val) vBIT(val,16,32)
#ifndef CONFIG_2BUFF_MODE
#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0xFFFF,0,16)))
#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0x3FFF,2,14)))
#else
#define RXD_GET_BUFFER0_SIZE(Control_2) (u8)((Control_2 & MASK_BUFFER0_SIZE) \
>> 48)
@ -382,7 +475,7 @@ typedef struct _RxD_t {
#endif
} RxD_t;
/* Structure that represents the Rx descriptor block which contains
/* Structure that represents the Rx descriptor block which contains
* 128 Rx descriptors.
*/
#ifndef CONFIG_2BUFF_MODE
@ -392,11 +485,11 @@ typedef struct _RxD_block {
u64 reserved_0;
#define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL
u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last
u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last
* Rxd in this blk */
u64 reserved_2_pNext_RxD_block; /* Logical ptr to next */
u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch
* the upper 32 bits should
* the upper 32 bits should
* be 0 */
} RxD_block_t;
#else
@ -405,13 +498,13 @@ typedef struct _RxD_block {
RxD_t rxd[MAX_RXDS_PER_BLOCK];
#define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL
u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last Rxd
u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last Rxd
* in this blk */
u64 pNext_RxD_Blk_physical; /* Phy ponter to next blk. */
} RxD_block_t;
#define SIZE_OF_BLOCK 4096
/* Structure to hold virtual addresses of Buf0 and Buf1 in
/* Structure to hold virtual addresses of Buf0 and Buf1 in
* 2buf mode. */
typedef struct bufAdd {
void *ba_0_org;
@ -423,8 +516,8 @@ typedef struct bufAdd {
/* Structure which stores all the MAC control parameters */
/* This structure stores the offset of the RxD in the ring
* from which the Rx Interrupt processor can start picking
/* This structure stores the offset of the RxD in the ring
* from which the Rx Interrupt processor can start picking
* up the RxDs for processing.
*/
typedef struct _rx_curr_get_info_t {
@ -436,7 +529,7 @@ typedef struct _rx_curr_get_info_t {
typedef rx_curr_get_info_t rx_curr_put_info_t;
/* This structure stores the offset of the TxDl in the FIFO
* from which the Tx Interrupt processor can start picking
* from which the Tx Interrupt processor can start picking
* up the TxDLs for send complete interrupt processing.
*/
typedef struct {
@ -446,32 +539,96 @@ typedef struct {
typedef tx_curr_get_info_t tx_curr_put_info_t;
/* Structure that holds the Phy and virt addresses of the Blocks */
typedef struct rx_block_info {
RxD_t *block_virt_addr;
dma_addr_t block_dma_addr;
} rx_block_info_t;
/* pre declaration of the nic structure */
typedef struct s2io_nic nic_t;
/* Ring specific structure */
typedef struct ring_info {
/* The ring number */
int ring_no;
/*
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
*/
rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING];
int block_count;
int pkt_cnt;
/*
* Put pointer info which indictes which RxD has to be replenished
* with a new buffer.
*/
rx_curr_put_info_t rx_curr_put_info;
/*
* Get pointer info which indictes which is the last RxD that was
* processed by the driver.
*/
rx_curr_get_info_t rx_curr_get_info;
#ifndef CONFIG_S2IO_NAPI
/* Index to the absolute position of the put pointer of Rx ring */
int put_pos;
#endif
#ifdef CONFIG_2BUFF_MODE
/* Buffer Address store. */
buffAdd_t **ba;
#endif
nic_t *nic;
} ring_info_t;
/* Fifo specific structure */
typedef struct fifo_info {
/* FIFO number */
int fifo_no;
/* Maximum TxDs per TxDL */
int max_txds;
/* Place holder of all the TX List's Phy and Virt addresses. */
list_info_hold_t *list_info;
/*
* Current offset within the tx FIFO where driver would write
* new Tx frame
*/
tx_curr_put_info_t tx_curr_put_info;
/*
* Current offset within tx FIFO from where the driver would start freeing
* the buffers
*/
tx_curr_get_info_t tx_curr_get_info;
nic_t *nic;
}fifo_info_t;
/* Infomation related to the Tx and Rx FIFOs and Rings of Xena
* is maintained in this structure.
*/
typedef struct mac_info {
/* rx side stuff */
/* Put pointer info which indictes which RxD has to be replenished
* with a new buffer.
*/
rx_curr_put_info_t rx_curr_put_info[MAX_RX_RINGS];
/* Get pointer info which indictes which is the last RxD that was
* processed by the driver.
*/
rx_curr_get_info_t rx_curr_get_info[MAX_RX_RINGS];
u16 rmac_pause_time;
u16 mc_pause_threshold_q0q3;
u16 mc_pause_threshold_q4q7;
/* tx side stuff */
/* logical pointer of start of each Tx FIFO */
TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS];
/* Current offset within tx_FIFO_start, where driver would write new Tx frame*/
tx_curr_put_info_t tx_curr_put_info[MAX_TX_FIFOS];
tx_curr_get_info_t tx_curr_get_info[MAX_TX_FIFOS];
/* Fifo specific structure */
fifo_info_t fifos[MAX_TX_FIFOS];
/* rx side stuff */
/* Ring specific structure */
ring_info_t rings[MAX_RX_RINGS];
u16 rmac_pause_time;
u16 mc_pause_threshold_q0q3;
u16 mc_pause_threshold_q4q7;
void *stats_mem; /* orignal pointer to allocated mem */
dma_addr_t stats_mem_phy; /* Physical address of the stat block */
@ -485,12 +642,6 @@ typedef struct {
int usage_cnt;
} usr_addr_t;
/* Structure that holds the Phy and virt addresses of the Blocks */
typedef struct rx_block_info {
RxD_t *block_virt_addr;
dma_addr_t block_dma_addr;
} rx_block_info_t;
/* Default Tunable parameters of the NIC. */
#define DEFAULT_FIFO_LEN 4096
#define SMALL_RXD_CNT 30 * (MAX_RXDS_PER_BLOCK+1)
@ -499,7 +650,20 @@ typedef struct rx_block_info {
#define LARGE_BLK_CNT 100
/* Structure representing one instance of the NIC */
typedef struct s2io_nic {
struct s2io_nic {
#ifdef CONFIG_S2IO_NAPI
/*
* Count of packets to be processed in a given iteration, it will be indicated
* by the quota field of the device structure when NAPI is enabled.
*/
int pkts_to_process;
#endif
struct net_device *dev;
mac_info_t mac_control;
struct config_param config;
struct pci_dev *pdev;
void __iomem *bar0;
void __iomem *bar1;
#define MAX_MAC_SUPPORTED 16
#define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
@ -507,33 +671,20 @@ typedef struct s2io_nic {
macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED];
struct net_device_stats stats;
void __iomem *bar0;
void __iomem *bar1;
struct config_param config;
mac_info_t mac_control;
int high_dma_flag;
int device_close_flag;
int device_enabled_once;
char name[32];
char name[50];
struct tasklet_struct task;
volatile unsigned long tasklet_status;
struct timer_list timer;
struct net_device *dev;
struct pci_dev *pdev;
u16 vendor_id;
u16 device_id;
u16 ccmd;
u32 cbar0_1;
u32 cbar0_2;
u32 cbar1_1;
u32 cbar1_2;
u32 cirq;
u8 cache_line;
u32 rom_expansion;
u16 pcix_cmd;
u32 irq;
/* Timer that handles I/O errors/exceptions */
struct timer_list alarm_timer;
/* Space to back up the PCI config space */
u32 config_space[256 / sizeof(u32)];
atomic_t rx_bufs_left[MAX_RX_RINGS];
spinlock_t tx_lock;
@ -558,27 +709,11 @@ typedef struct s2io_nic {
u16 tx_err_count;
u16 rx_err_count;
#ifndef CONFIG_S2IO_NAPI
/* Index to the absolute position of the put pointer of Rx ring. */
int put_pos[MAX_RX_RINGS];
#endif
/*
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
*/
rx_block_info_t rx_blocks[MAX_RX_RINGS][MAX_RX_BLOCKS_PER_RING];
int block_count[MAX_RX_RINGS];
int pkt_cnt[MAX_RX_RINGS];
/* Place holder of all the TX List's Phy and Virt addresses. */
list_info_hold_t *list_info[MAX_TX_FIFOS];
/* Id timer, used to blink NIC to physically identify NIC. */
struct timer_list id_timer;
/* Restart timer, used to restart NIC if the device is stuck and
* a schedule task that will set the correct Link state once the
* a schedule task that will set the correct Link state once the
* NIC's PHY has stabilized after a state change.
*/
#ifdef INIT_TQUEUE
@ -589,12 +724,12 @@ typedef struct s2io_nic {
struct work_struct set_link_task;
#endif
/* Flag that can be used to turn on or turn off the Rx checksum
/* Flag that can be used to turn on or turn off the Rx checksum
* offload feature.
*/
int rx_csum;
/* after blink, the adapter must be restored with original
/* after blink, the adapter must be restored with original
* values.
*/
u64 adapt_ctrl_org;
@ -604,16 +739,19 @@ typedef struct s2io_nic {
#define LINK_DOWN 1
#define LINK_UP 2
#ifdef CONFIG_2BUFF_MODE
/* Buffer Address store. */
buffAdd_t **ba[MAX_RX_RINGS];
#endif
int task_flag;
#define CARD_DOWN 1
#define CARD_UP 2
atomic_t card_state;
volatile unsigned long link_state;
} nic_t;
struct vlan_group *vlgrp;
#define XFRAME_I_DEVICE 1
#define XFRAME_II_DEVICE 2
u8 device_type;
spinlock_t rx_lock;
atomic_t isr_cnt;
};
#define RESET_ERROR 1;
#define CMD_ERROR 2;
@ -622,9 +760,10 @@ typedef struct s2io_nic {
#ifndef readq
static inline u64 readq(void __iomem *addr)
{
u64 ret = readl(addr + 4);
ret <<= 32;
ret |= readl(addr);
u64 ret = 0;
ret = readl(addr + 4);
(u64) ret <<= 32;
(u64) ret |= readl(addr);
return ret;
}
@ -637,10 +776,10 @@ static inline void writeq(u64 val, void __iomem *addr)
writel((u32) (val >> 32), (addr + 4));
}
/* In 32 bit modes, some registers have to be written in a
/* In 32 bit modes, some registers have to be written in a
* particular order to expect correct hardware operation. The
* macro SPECIAL_REG_WRITE is used to perform such ordered
* writes. Defines UF (Upper First) and LF (Lower First) will
* macro SPECIAL_REG_WRITE is used to perform such ordered
* writes. Defines UF (Upper First) and LF (Lower First) will
* be used to specify the required write order.
*/
#define UF 1
@ -716,6 +855,7 @@ static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order)
#define PCC_FB_ECC_ERR vBIT(0xff, 16, 8) /* Interrupt to indicate
PCC_FB_ECC Error. */
#define RXD_GET_VLAN_TAG(Control_2) (u16)(Control_2 & MASK_VLAN_TAG)
/*
* Prototype declaration.
*/
@ -725,36 +865,30 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
static int init_shared_mem(struct s2io_nic *sp);
static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic);
#ifndef CONFIG_S2IO_NAPI
static void rx_intr_handler(struct s2io_nic *sp);
#endif
static void tx_intr_handler(struct s2io_nic *sp);
static void rx_intr_handler(ring_info_t *ring_data);
static void tx_intr_handler(fifo_info_t *fifo_data);
static void alarm_intr_handler(struct s2io_nic *sp);
static int s2io_starter(void);
static void s2io_closer(void);
void s2io_closer(void);
static void s2io_tx_watchdog(struct net_device *dev);
static void s2io_tasklet(unsigned long dev_addr);
static void s2io_set_multicast(struct net_device *dev);
#ifndef CONFIG_2BUFF_MODE
static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no);
#else
static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no,
buffAdd_t * ba);
#endif
static void s2io_link(nic_t * sp, int link);
static void s2io_reset(nic_t * sp);
#ifdef CONFIG_S2IO_NAPI
static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
void s2io_link(nic_t * sp, int link);
void s2io_reset(nic_t * sp);
#if defined(CONFIG_S2IO_NAPI)
static int s2io_poll(struct net_device *dev, int *budget);
#endif
static void s2io_init_pci(nic_t * sp);
static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
static void s2io_alarm_handle(unsigned long data);
static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
static int verify_xena_quiescence(u64 val64, int flag);
static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
static struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(unsigned long data);
static int s2io_set_swapper(nic_t * sp);
static void s2io_card_down(nic_t * nic);
static int s2io_card_up(nic_t * nic);
int s2io_set_swapper(nic_t * sp);
static void s2io_card_down(nic_t *nic);
static int s2io_card_up(nic_t *nic);
int get_xena_rev_id(struct pci_dev *pdev);
#endif /* _S2IO_H */

Просмотреть файл

@ -42,7 +42,7 @@
#include "skge.h"
#define DRV_NAME "skge"
#define DRV_VERSION "0.8"
#define DRV_VERSION "0.9"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@ -79,8 +79,8 @@ static const struct pci_device_id skge_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
{ PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
{ PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) },
{ PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) },
{ PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, skge_id_table);
@ -189,7 +189,7 @@ static u32 skge_supported_modes(const struct skge_hw *hw)
{
u32 supported;
if (iscopper(hw)) {
if (hw->copper) {
supported = SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
| SUPPORTED_100baseT_Half
@ -222,7 +222,7 @@ static int skge_get_settings(struct net_device *dev,
ecmd->transceiver = XCVR_INTERNAL;
ecmd->supported = skge_supported_modes(hw);
if (iscopper(hw)) {
if (hw->copper) {
ecmd->port = PORT_TP;
ecmd->phy_address = hw->phy_addr;
} else
@ -876,6 +876,9 @@ static int skge_rx_fill(struct skge_port *skge)
static void skge_link_up(struct skge_port *skge)
{
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG),
LED_BLK_OFF|LED_SYNC_OFF|LED_ON);
netif_carrier_on(skge->netdev);
if (skge->tx_avail > MAX_SKB_FRAGS + 1)
netif_wake_queue(skge->netdev);
@ -894,6 +897,7 @@ static void skge_link_up(struct skge_port *skge)
static void skge_link_down(struct skge_port *skge)
{
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
netif_carrier_off(skge->netdev);
netif_stop_queue(skge->netdev);
@ -1599,7 +1603,7 @@ static void yukon_init(struct skge_hw *hw, int port)
adv = PHY_AN_CSMA;
if (skge->autoneg == AUTONEG_ENABLE) {
if (iscopper(hw)) {
if (hw->copper) {
if (skge->advertising & ADVERTISED_1000baseT_Full)
ct1000 |= PHY_M_1000C_AFD;
if (skge->advertising & ADVERTISED_1000baseT_Half)
@ -1691,7 +1695,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
/* Set hardware config mode */
reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE;
reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
reg |= hw->copper ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
/* Clear GMC reset */
skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
@ -1780,7 +1784,12 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg &= ~GMF_RX_F_FL_ON;
skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
/*
* because Pause Packet Truncation in GMAC is not working
* we have to increase the Flush Threshold to 64 bytes
* in order to flush pause packets in Rx FIFO on Yukon-1
*/
skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1);
/* Configure Tx MAC FIFO */
skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
@ -2670,18 +2679,6 @@ static void skge_error_irq(struct skge_hw *hw)
/* Timestamp (unused) overflow */
if (hwstatus & IS_IRQ_TIST_OV)
skge_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
if (hwstatus & IS_IRQ_SENSOR) {
/* no sensors on 32-bit Yukon */
if (!(skge_read16(hw, B0_CTST) & CS_BUS_SLOT_SZ)) {
printk(KERN_ERR PFX "ignoring bogus sensor interrups\n");
skge_write32(hw, B0_HWE_IMSK,
IS_ERR_MSK & ~IS_IRQ_SENSOR);
} else
printk(KERN_WARNING PFX "sensor interrupt\n");
}
}
if (hwstatus & IS_RAM_RD_PAR) {
@ -2712,9 +2709,10 @@ static void skge_error_irq(struct skge_hw *hw)
skge_pci_clear(hw);
/* if error still set then just ignore it */
hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hwstatus & IS_IRQ_STAT) {
printk(KERN_WARNING PFX "IRQ status %x: still set ignoring hardware errors\n",
pr_debug("IRQ status %x: still set ignoring hardware errors\n",
hwstatus);
hw->intr_mask &= ~IS_HW_ERR;
}
@ -2876,7 +2874,7 @@ static const char *skge_board_name(const struct skge_hw *hw)
static int skge_reset(struct skge_hw *hw)
{
u16 ctst;
u8 t8, mac_cfg;
u8 t8, mac_cfg, pmd_type, phy_type;
int i;
ctst = skge_read16(hw, B0_CTST);
@ -2895,18 +2893,19 @@ static int skge_reset(struct skge_hw *hw)
ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
hw->chip_id = skge_read8(hw, B2_CHIP_ID);
hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
hw->pmd_type = skge_read8(hw, B2_PMD_TYP);
phy_type = skge_read8(hw, B2_E_1) & 0xf;
pmd_type = skge_read8(hw, B2_PMD_TYP);
hw->copper = (pmd_type == 'T' || pmd_type == '1');
switch (hw->chip_id) {
case CHIP_ID_GENESIS:
switch (hw->phy_type) {
switch (phy_type) {
case SK_PHY_BCOM:
hw->phy_addr = PHY_ADDR_BCOM;
break;
default:
printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
pci_name(hw->pdev), hw->phy_type);
pci_name(hw->pdev), phy_type);
return -EOPNOTSUPP;
}
break;
@ -2914,13 +2913,10 @@ static int skge_reset(struct skge_hw *hw)
case CHIP_ID_YUKON:
case CHIP_ID_YUKON_LITE:
case CHIP_ID_YUKON_LP:
if (hw->phy_type < SK_PHY_MARV_COPPER && hw->pmd_type != 'S')
hw->phy_type = SK_PHY_MARV_COPPER;
if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
hw->copper = 1;
hw->phy_addr = PHY_ADDR_MARV;
if (!iscopper(hw))
hw->phy_type = SK_PHY_MARV_FIBER;
break;
default:
@ -2948,12 +2944,20 @@ static int skge_reset(struct skge_hw *hw)
else
hw->ram_size = t8 * 4096;
hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_init(hw);
else {
/* switch power to VCC (WA for VAUX problem) */
skge_write8(hw, B0_POWER_CTRL,
PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
/* avoid boards with stuck Hardware error bits */
if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
(skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
hw->intr_mask &= ~IS_HW_ERR;
}
for (i = 0; i < hw->ports; i++) {
skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
@ -2994,7 +2998,6 @@ static int skge_reset(struct skge_hw *hw)
skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
skge_write32(hw, B2_IRQM_CTRL, TIM_START);
hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
skge_write32(hw, B0_IMSK, hw->intr_mask);
if (hw->chip_id != CHIP_ID_GENESIS)

Просмотреть файл

@ -214,8 +214,6 @@ enum {
/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */
enum {
IS_ERR_MSK = 0x00003fff,/* All Error bits */
IS_IRQ_TIST_OV = 1<<13, /* Time Stamp Timer Overflow (YUKON only) */
IS_IRQ_SENSOR = 1<<12, /* IRQ from Sensor (YUKON only) */
IS_IRQ_MST_ERR = 1<<11, /* IRQ master error detected */
@ -230,6 +228,12 @@ enum {
IS_M2_PAR_ERR = 1<<2, /* MAC 2 Parity Error */
IS_R1_PAR_ERR = 1<<1, /* Queue R1 Parity Error */
IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */
IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT
| IS_NO_STAT_M1 | IS_NO_STAT_M2
| IS_RAM_RD_PAR | IS_RAM_WR_PAR
| IS_M1_PAR_ERR | IS_M2_PAR_ERR
| IS_R1_PAR_ERR | IS_R2_PAR_ERR,
};
/* B2_TST_CTRL1 8 bit Test Control Register 1 */
@ -2456,24 +2460,17 @@ struct skge_hw {
u8 chip_id;
u8 chip_rev;
u8 phy_type;
u8 pmd_type;
u16 phy_addr;
u8 copper;
u8 ports;
u32 ram_size;
u32 ram_offset;
u16 phy_addr;
struct tasklet_struct ext_tasklet;
spinlock_t phy_lock;
};
static inline int iscopper(const struct skge_hw *hw)
{
return (hw->pmd_type == 'T');
}
enum {
FLOW_MODE_NONE = 0, /* No Flow-Control */
FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */

Просмотреть файл

@ -1,6 +1,11 @@
/*
* sonic.c
*
* (C) 2005 Finn Thain
*
* Converted to DMA API, added zero-copy buffer handling, and
* (from the mac68k project) introduced dhd's support for 16-bit cards.
*
* (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
*
* This driver is based on work from Andreas Busse, but most of
@ -9,12 +14,23 @@
* (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
*
* Core code included by system sonic drivers
*
* And... partially rewritten again by David Huggins-Daines in order
* to cope with screwed up Macintosh NICs that may or may not use
* 16-bit DMA.
*
* (C) 1999 David Huggins-Daines <dhd@debian.org>
*
*/
/*
* Sources: Olivetti M700-10 Risc Personal Computer hardware handbook,
* National Semiconductors data sheet for the DP83932B Sonic Ethernet
* controller, and the files "8390.c" and "skeleton.c" in this directory.
*
* Additional sources: Nat Semi data sheet for the DP83932C and Nat Semi
* Application Note AN-746, the files "lance.c" and "ibmlana.c". See also
* the NetBSD file "sys/arch/mac68k/dev/if_sn.c".
*/
@ -28,6 +44,9 @@
*/
static int sonic_open(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
int i;
if (sonic_debug > 2)
printk("sonic_open: initializing sonic driver.\n");
@ -40,14 +59,59 @@ static int sonic_open(struct net_device *dev)
* This means that during execution of the handler interrupt are disabled
* covering another bug otherwise corrupting data. This doesn't mean
* this glue works ok under all situations.
*
* Note (dhd): this also appears to prevent lockups on the Macintrash
* when more than one Ethernet card is installed (knock on wood)
*
* Note (fthain): whether the above is still true is anyones guess. Certainly
* the buffer handling algorithms will not tolerate re-entrance without some
* mutual exclusion added. Anyway, the memcpy has now been eliminated from the
* rx code to make this a faster "fast interrupt".
*/
// if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) {
if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT,
"sonic", dev)) {
printk("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) {
printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
return -EAGAIN;
}
for (i = 0; i < SONIC_NUM_RRS; i++) {
struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2);
if (skb == NULL) {
while(i > 0) { /* free any that were allocated successfully */
i--;
dev_kfree_skb(lp->rx_skb[i]);
lp->rx_skb[i] = NULL;
}
printk(KERN_ERR "%s: couldn't allocate receive buffers\n",
dev->name);
return -ENOMEM;
}
skb->dev = dev;
/* align IP header unless DMA requires otherwise */
if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
skb_reserve(skb, 2);
lp->rx_skb[i] = skb;
}
for (i = 0; i < SONIC_NUM_RRS; i++) {
dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE),
SONIC_RBSIZE, DMA_FROM_DEVICE);
if (!laddr) {
while(i > 0) { /* free any that were mapped successfully */
i--;
dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
lp->rx_laddr[i] = (dma_addr_t)0;
}
for (i = 0; i < SONIC_NUM_RRS; i++) {
dev_kfree_skb(lp->rx_skb[i]);
lp->rx_skb[i] = NULL;
}
printk(KERN_ERR "%s: couldn't map rx DMA buffers\n",
dev->name);
return -ENOMEM;
}
lp->rx_laddr[i] = laddr;
}
/*
* Initialize the SONIC
*/
@ -67,7 +131,8 @@ static int sonic_open(struct net_device *dev)
*/
static int sonic_close(struct net_device *dev)
{
unsigned int base_addr = dev->base_addr;
struct sonic_local *lp = netdev_priv(dev);
int i;
if (sonic_debug > 2)
printk("sonic_close\n");
@ -77,20 +142,56 @@ static int sonic_close(struct net_device *dev)
/*
* stop the SONIC, disable interrupts
*/
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
sonic_free_irq(dev->irq, dev); /* release the IRQ */
/* unmap and free skbs that haven't been transmitted */
for (i = 0; i < SONIC_NUM_TDS; i++) {
if(lp->tx_laddr[i]) {
dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE);
lp->tx_laddr[i] = (dma_addr_t)0;
}
if(lp->tx_skb[i]) {
dev_kfree_skb(lp->tx_skb[i]);
lp->tx_skb[i] = NULL;
}
}
/* unmap and free the receive buffers */
for (i = 0; i < SONIC_NUM_RRS; i++) {
if(lp->rx_laddr[i]) {
dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
lp->rx_laddr[i] = (dma_addr_t)0;
}
if(lp->rx_skb[i]) {
dev_kfree_skb(lp->rx_skb[i]);
lp->rx_skb[i] = NULL;
}
}
free_irq(dev->irq, dev); /* release the IRQ */
return 0;
}
static void sonic_tx_timeout(struct net_device *dev)
{
struct sonic_local *lp = (struct sonic_local *) dev->priv;
printk("%s: transmit timed out.\n", dev->name);
struct sonic_local *lp = netdev_priv(dev);
int i;
/* Stop the interrupts for this */
SONIC_WRITE(SONIC_IMR, 0);
/* We could resend the original skbs. Easier to re-initialise. */
for (i = 0; i < SONIC_NUM_TDS; i++) {
if(lp->tx_laddr[i]) {
dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE);
lp->tx_laddr[i] = (dma_addr_t)0;
}
if(lp->tx_skb[i]) {
dev_kfree_skb(lp->tx_skb[i]);
lp->tx_skb[i] = NULL;
}
}
/* Try to restart the adaptor. */
sonic_init(dev);
lp->stats.tx_errors++;
@ -100,60 +201,92 @@ static void sonic_tx_timeout(struct net_device *dev)
/*
* transmit packet
*
* Appends new TD during transmission thus avoiding any TX interrupts
* until we run out of TDs.
* This routine interacts closely with the ISR in that it may,
* set tx_skb[i]
* reset the status flags of the new TD
* set and reset EOL flags
* stop the tx queue
* The ISR interacts with this routine in various ways. It may,
* reset tx_skb[i]
* test the EOL and status flags of the TDs
* wake the tx queue
* Concurrently with all of this, the SONIC is potentially writing to
* the status flags of the TDs.
* Until some mutual exclusion is added, this code will not work with SMP. However,
* MIPS Jazz machines and m68k Macs were all uni-processor machines.
*/
static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct sonic_local *lp = (struct sonic_local *) dev->priv;
unsigned int base_addr = dev->base_addr;
unsigned int laddr;
int entry, length;
netif_stop_queue(dev);
struct sonic_local *lp = netdev_priv(dev);
dma_addr_t laddr;
int length;
int entry = lp->next_tx;
if (sonic_debug > 2)
printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev);
length = skb->len;
if (length < ETH_ZLEN) {
skb = skb_padto(skb, ETH_ZLEN);
if (skb == NULL)
return 0;
length = ETH_ZLEN;
}
/*
* Map the packet data into the logical DMA address space
*/
if ((laddr = vdma_alloc(CPHYSADDR(skb->data), skb->len)) == ~0UL) {
printk("%s: no VDMA entry for transmit available.\n",
dev->name);
laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE);
if (!laddr) {
printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name);
dev_kfree_skb(skb);
netif_start_queue(dev);
return 1;
}
entry = lp->cur_tx & SONIC_TDS_MASK;
sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */
sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */
sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */
sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_L, laddr & 0xffff);
sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_H, laddr >> 16);
sonic_tda_put(dev, entry, SONIC_TD_FRAG_SIZE, length);
sonic_tda_put(dev, entry, SONIC_TD_LINK,
sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL);
/*
* Must set tx_skb[entry] only after clearing status, and
* before clearing EOL and before stopping queue
*/
wmb();
lp->tx_len[entry] = length;
lp->tx_laddr[entry] = laddr;
lp->tx_skb[entry] = skb;
length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
flush_cache_all();
wmb();
sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK,
sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK) & ~SONIC_EOL);
lp->eol_tx = entry;
/*
* Setup the transmit descriptor and issue the transmit command.
*/
lp->tda[entry].tx_status = 0; /* clear status */
lp->tda[entry].tx_frag_count = 1; /* single fragment */
lp->tda[entry].tx_pktsize = length; /* length of packet */
lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff;
lp->tda[entry].tx_frag_ptr_h = laddr >> 16;
lp->tda[entry].tx_frag_size = length;
lp->cur_tx++;
lp->stats.tx_bytes += length;
lp->next_tx = (entry + 1) & SONIC_TDS_MASK;
if (lp->tx_skb[lp->next_tx] != NULL) {
/* The ring is full, the ISR has yet to process the next TD. */
if (sonic_debug > 3)
printk("%s: stopping queue\n", dev->name);
netif_stop_queue(dev);
/* after this packet, wait for ISR to free up some TDAs */
} else netif_start_queue(dev);
if (sonic_debug > 2)
printk("sonic_send_packet: issueing Tx command\n");
printk("sonic_send_packet: issuing Tx command\n");
SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
dev->trans_start = jiffies;
if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS)
netif_start_queue(dev);
else
lp->tx_full = 1;
return 0;
}
@ -164,175 +297,199 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
unsigned int base_addr = dev->base_addr;
struct sonic_local *lp;
struct sonic_local *lp = netdev_priv(dev);
int status;
if (dev == NULL) {
printk("sonic_interrupt: irq %d for unknown device.\n", irq);
printk(KERN_ERR "sonic_interrupt: irq %d for unknown device.\n", irq);
return IRQ_NONE;
}
lp = (struct sonic_local *) dev->priv;
if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT))
return IRQ_NONE;
status = SONIC_READ(SONIC_ISR);
SONIC_WRITE(SONIC_ISR, 0x7fff); /* clear all bits */
do {
if (status & SONIC_INT_PKTRX) {
if (sonic_debug > 2)
printk("%s: packet rx\n", dev->name);
sonic_rx(dev); /* got packet(s) */
SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */
}
if (sonic_debug > 2)
printk("sonic_interrupt: ISR=%x\n", status);
if (status & SONIC_INT_TXDN) {
int entry = lp->cur_tx;
int td_status;
int freed_some = 0;
if (status & SONIC_INT_PKTRX) {
sonic_rx(dev); /* got packet(s) */
}
/* At this point, cur_tx is the index of a TD that is one of:
* unallocated/freed (status set & tx_skb[entry] clear)
* allocated and sent (status set & tx_skb[entry] set )
* allocated and not yet sent (status clear & tx_skb[entry] set )
* still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear)
*/
if (status & SONIC_INT_TXDN) {
int dirty_tx = lp->dirty_tx;
if (sonic_debug > 2)
printk("%s: tx done\n", dev->name);
while (dirty_tx < lp->cur_tx) {
int entry = dirty_tx & SONIC_TDS_MASK;
int status = lp->tda[entry].tx_status;
while (lp->tx_skb[entry] != NULL) {
if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0)
break;
if (sonic_debug > 3)
printk
("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n",
status, lp->cur_tx, lp->dirty_tx);
if (td_status & 0x0001) {
lp->stats.tx_packets++;
lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE);
} else {
lp->stats.tx_errors++;
if (td_status & 0x0642)
lp->stats.tx_aborted_errors++;
if (td_status & 0x0180)
lp->stats.tx_carrier_errors++;
if (td_status & 0x0020)
lp->stats.tx_window_errors++;
if (td_status & 0x0004)
lp->stats.tx_fifo_errors++;
}
if (status == 0) {
/* It still hasn't been Txed, kick the sonic again */
SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
break;
}
/* put back EOL and free descriptor */
lp->tda[entry].tx_frag_count = 0;
lp->tda[entry].tx_status = 0;
if (status & 0x0001)
lp->stats.tx_packets++;
else {
lp->stats.tx_errors++;
if (status & 0x0642)
lp->stats.tx_aborted_errors++;
if (status & 0x0180)
lp->stats.tx_carrier_errors++;
if (status & 0x0020)
lp->stats.tx_window_errors++;
if (status & 0x0004)
lp->stats.tx_fifo_errors++;
}
/* We must free the original skb */
if (lp->tx_skb[entry]) {
/* We must free the original skb */
dev_kfree_skb_irq(lp->tx_skb[entry]);
lp->tx_skb[entry] = 0;
lp->tx_skb[entry] = NULL;
/* and unmap DMA buffer */
dma_unmap_single(lp->device, lp->tx_laddr[entry], lp->tx_len[entry], DMA_TO_DEVICE);
lp->tx_laddr[entry] = (dma_addr_t)0;
freed_some = 1;
if (sonic_tda_get(dev, entry, SONIC_TD_LINK) & SONIC_EOL) {
entry = (entry + 1) & SONIC_TDS_MASK;
break;
}
entry = (entry + 1) & SONIC_TDS_MASK;
}
/* and the VDMA address */
vdma_free(lp->tx_laddr[entry]);
dirty_tx++;
if (freed_some || lp->tx_skb[entry] == NULL)
netif_wake_queue(dev); /* The ring is no longer full */
lp->cur_tx = entry;
SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */
}
if (lp->tx_full
&& dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) {
/* The ring is no longer full, clear tbusy. */
lp->tx_full = 0;
netif_wake_queue(dev);
/*
* check error conditions
*/
if (status & SONIC_INT_RFO) {
if (sonic_debug > 1)
printk("%s: rx fifo overrun\n", dev->name);
lp->stats.rx_fifo_errors++;
SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */
}
if (status & SONIC_INT_RDE) {
if (sonic_debug > 1)
printk("%s: rx descriptors exhausted\n", dev->name);
lp->stats.rx_dropped++;
SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */
}
if (status & SONIC_INT_RBAE) {
if (sonic_debug > 1)
printk("%s: rx buffer area exceeded\n", dev->name);
lp->stats.rx_dropped++;
SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */
}
lp->dirty_tx = dirty_tx;
}
/* counter overruns; all counters are 16bit wide */
if (status & SONIC_INT_FAE) {
lp->stats.rx_frame_errors += 65536;
SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */
}
if (status & SONIC_INT_CRC) {
lp->stats.rx_crc_errors += 65536;
SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */
}
if (status & SONIC_INT_MP) {
lp->stats.rx_missed_errors += 65536;
SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */
}
/*
* check error conditions
*/
if (status & SONIC_INT_RFO) {
printk("%s: receive fifo underrun\n", dev->name);
lp->stats.rx_fifo_errors++;
}
if (status & SONIC_INT_RDE) {
printk("%s: receive descriptors exhausted\n", dev->name);
lp->stats.rx_dropped++;
}
if (status & SONIC_INT_RBE) {
printk("%s: receive buffer exhausted\n", dev->name);
lp->stats.rx_dropped++;
}
if (status & SONIC_INT_RBAE) {
printk("%s: receive buffer area exhausted\n", dev->name);
lp->stats.rx_dropped++;
}
/* transmit error */
if (status & SONIC_INT_TXER) {
if ((SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) && (sonic_debug > 2))
printk(KERN_ERR "%s: tx fifo underrun\n", dev->name);
SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */
}
/* counter overruns; all counters are 16bit wide */
if (status & SONIC_INT_FAE)
lp->stats.rx_frame_errors += 65536;
if (status & SONIC_INT_CRC)
lp->stats.rx_crc_errors += 65536;
if (status & SONIC_INT_MP)
lp->stats.rx_missed_errors += 65536;
/* bus retry */
if (status & SONIC_INT_BR) {
printk(KERN_ERR "%s: Bus retry occurred! Device interrupt disabled.\n",
dev->name);
/* ... to help debug DMA problems causing endless interrupts. */
/* Bounce the eth interface to turn on the interrupt again. */
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */
}
/* transmit error */
if (status & SONIC_INT_TXER)
lp->stats.tx_errors++;
/*
* clear interrupt bits and return
*/
SONIC_WRITE(SONIC_ISR, status);
/* load CAM done */
if (status & SONIC_INT_LCD)
SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */
} while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT));
return IRQ_HANDLED;
}
/*
* We have a good packet(s), get it/them out of the buffers.
* We have a good packet(s), pass it/them up the network stack.
*/
static void sonic_rx(struct net_device *dev)
{
unsigned int base_addr = dev->base_addr;
struct sonic_local *lp = (struct sonic_local *) dev->priv;
sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK];
struct sonic_local *lp = netdev_priv(dev);
int status;
int entry = lp->cur_rx;
while (rd->in_use == 0) {
struct sk_buff *skb;
while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) {
struct sk_buff *used_skb;
struct sk_buff *new_skb;
dma_addr_t new_laddr;
u16 bufadr_l;
u16 bufadr_h;
int pkt_len;
unsigned char *pkt_ptr;
status = rd->rx_status;
if (sonic_debug > 3)
printk("status %x, cur_rx %d, cur_rra %x\n",
status, lp->cur_rx, lp->cur_rra);
status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
if (status & SONIC_RCR_PRX) {
pkt_len = rd->rx_pktlen;
pkt_ptr =
(char *)
sonic_chiptomem((rd->rx_pktptr_h << 16) +
rd->rx_pktptr_l);
if (sonic_debug > 3)
printk
("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n",
pkt_ptr, lp->rba, rd->rx_pktptr_h,
rd->rx_pktptr_l,
SONIC_READ(SONIC_RBWC1),
SONIC_READ(SONIC_RBWC0));
/* Malloc up new buffer. */
skb = dev_alloc_skb(pkt_len + 2);
if (skb == NULL) {
printk
("%s: Memory squeeze, dropping packet.\n",
dev->name);
new_skb = dev_alloc_skb(SONIC_RBSIZE + 2);
if (new_skb == NULL) {
printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
break;
}
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, pkt_len); /* Make room */
eth_copy_and_sum(skb, pkt_ptr, pkt_len, 0);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb); /* pass the packet to upper layers */
new_skb->dev = dev;
/* provide 16 byte IP header alignment unless DMA requires otherwise */
if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
skb_reserve(new_skb, 2);
new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE),
SONIC_RBSIZE, DMA_FROM_DEVICE);
if (!new_laddr) {
dev_kfree_skb(new_skb);
printk(KERN_ERR "%s: Failed to map rx buffer, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
break;
}
/* now we have a new skb to replace it, pass the used one up the stack */
dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE);
used_skb = lp->rx_skb[entry];
pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN);
skb_trim(used_skb, pkt_len);
used_skb->protocol = eth_type_trans(used_skb, dev);
netif_rx(used_skb);
dev->last_rx = jiffies;
lp->stats.rx_packets++;
lp->stats.rx_bytes += pkt_len;
/* and insert the new skb */
lp->rx_laddr[entry] = new_laddr;
lp->rx_skb[entry] = new_skb;
bufadr_l = (unsigned long)new_laddr & 0xffff;
bufadr_h = (unsigned long)new_laddr >> 16;
sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l);
sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h);
} else {
/* This should only happen, if we enable accepting broken packets. */
lp->stats.rx_errors++;
@ -341,29 +498,35 @@ static void sonic_rx(struct net_device *dev)
if (status & SONIC_RCR_CRCR)
lp->stats.rx_crc_errors++;
}
rd->in_use = 1;
rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK];
/* now give back the buffer to the receive buffer area */
if (status & SONIC_RCR_LPKT) {
/*
* this was the last packet out of the current receice buffer
* this was the last packet out of the current receive buffer
* give the buffer back to the SONIC
*/
lp->cur_rra += sizeof(sonic_rr_t);
if (lp->cur_rra >
(lp->rra_laddr +
(SONIC_NUM_RRS -
1) * sizeof(sonic_rr_t))) lp->cur_rra =
lp->rra_laddr;
SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff);
lp->cur_rwp += SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode);
if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff;
SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) {
if (sonic_debug > 2)
printk("%s: rx buffer exhausted\n", dev->name);
SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
}
} else
printk
("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
dev->name);
/*
* give back the descriptor
*/
sonic_rda_put(dev, entry, SONIC_RD_LINK,
sonic_rda_get(dev, entry, SONIC_RD_LINK) | SONIC_EOL);
sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK,
sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK) & ~SONIC_EOL);
lp->eol_rx = entry;
lp->cur_rx = entry = (entry + 1) & SONIC_RDS_MASK;
}
/*
* If any worth-while packets have been received, dev_rint()
* If any worth-while packets have been received, netif_rx()
* has done a mark_bh(NET_BH) for us and will work on them
* when we get to the bottom-half routine.
*/
@ -376,8 +539,7 @@ static void sonic_rx(struct net_device *dev)
*/
static struct net_device_stats *sonic_get_stats(struct net_device *dev)
{
struct sonic_local *lp = (struct sonic_local *) dev->priv;
unsigned int base_addr = dev->base_addr;
struct sonic_local *lp = netdev_priv(dev);
/* read the tally counter from the SONIC and reset them */
lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT);
@ -396,8 +558,7 @@ static struct net_device_stats *sonic_get_stats(struct net_device *dev)
*/
static void sonic_multicast_list(struct net_device *dev)
{
struct sonic_local *lp = (struct sonic_local *) dev->priv;
unsigned int base_addr = dev->base_addr;
struct sonic_local *lp = netdev_priv(dev);
unsigned int rcr;
struct dev_mc_list *dmi = dev->mc_list;
unsigned char *addr;
@ -413,20 +574,15 @@ static void sonic_multicast_list(struct net_device *dev)
rcr |= SONIC_RCR_AMC;
} else {
if (sonic_debug > 2)
printk
("sonic_multicast_list: mc_count %d\n",
dev->mc_count);
lp->cda.cam_enable = 1; /* always enable our own address */
printk("sonic_multicast_list: mc_count %d\n", dev->mc_count);
sonic_set_cam_enable(dev, 1); /* always enable our own address */
for (i = 1; i <= dev->mc_count; i++) {
addr = dmi->dmi_addr;
dmi = dmi->next;
lp->cda.cam_desc[i].cam_cap0 =
addr[1] << 8 | addr[0];
lp->cda.cam_desc[i].cam_cap1 =
addr[3] << 8 | addr[2];
lp->cda.cam_desc[i].cam_cap2 =
addr[5] << 8 | addr[4];
lp->cda.cam_enable |= (1 << i);
sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]);
sonic_cda_put(dev, i, SONIC_CD_CAP1, addr[3] << 8 | addr[2]);
sonic_cda_put(dev, i, SONIC_CD_CAP2, addr[5] << 8 | addr[4]);
sonic_set_cam_enable(dev, sonic_get_cam_enable(dev) | (1 << i));
}
SONIC_WRITE(SONIC_CDC, 16);
/* issue Load CAM command */
@ -447,19 +603,16 @@ static void sonic_multicast_list(struct net_device *dev)
*/
static int sonic_init(struct net_device *dev)
{
unsigned int base_addr = dev->base_addr;
unsigned int cmd;
struct sonic_local *lp = (struct sonic_local *) dev->priv;
unsigned int rra_start;
unsigned int rra_end;
struct sonic_local *lp = netdev_priv(dev);
int i;
/*
* put the Sonic into software-reset mode and
* disable all interrupts
*/
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
/*
@ -475,34 +628,32 @@ static int sonic_init(struct net_device *dev)
if (sonic_debug > 2)
printk("sonic_init: initialize receive resource area\n");
rra_start = lp->rra_laddr & 0xffff;
rra_end =
(rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff;
for (i = 0; i < SONIC_NUM_RRS; i++) {
lp->rra[i].rx_bufadr_l =
(lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff;
lp->rra[i].rx_bufadr_h =
(lp->rba_laddr + i * SONIC_RBSIZE) >> 16;
lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1;
lp->rra[i].rx_bufsize_h = 0;
u16 bufadr_l = (unsigned long)lp->rx_laddr[i] & 0xffff;
u16 bufadr_h = (unsigned long)lp->rx_laddr[i] >> 16;
sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_L, SONIC_RBSIZE >> 1);
sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_H, 0);
}
/* initialize all RRA registers */
SONIC_WRITE(SONIC_RSA, rra_start);
SONIC_WRITE(SONIC_REA, rra_end);
SONIC_WRITE(SONIC_RRP, rra_start);
SONIC_WRITE(SONIC_RWP, rra_end);
lp->rra_end = (lp->rra_laddr + SONIC_NUM_RRS * SIZEOF_SONIC_RR *
SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR *
SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff);
SONIC_WRITE(SONIC_REA, lp->rra_end);
SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff);
SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16);
SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE - 2) >> 1);
lp->cur_rra =
lp->rra_laddr + (SONIC_NUM_RRS - 1) * sizeof(sonic_rr_t);
SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1));
/* load the resource pointers */
if (sonic_debug > 3)
printk("sonic_init: issueing RRRA command\n");
printk("sonic_init: issuing RRRA command\n");
SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
i = 0;
while (i++ < 100) {
@ -511,27 +662,30 @@ static int sonic_init(struct net_device *dev)
}
if (sonic_debug > 2)
printk("sonic_init: status=%x\n", SONIC_READ(SONIC_CMD));
printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i);
/*
* Initialize the receive descriptors so that they
* become a circular linked list, ie. let the last
* descriptor point to the first again.
*/
if (sonic_debug > 2)
printk("sonic_init: initialize receive descriptors\n");
for (i = 0; i < SONIC_NUM_RDS; i++) {
lp->rda[i].rx_status = 0;
lp->rda[i].rx_pktlen = 0;
lp->rda[i].rx_pktptr_l = 0;
lp->rda[i].rx_pktptr_h = 0;
lp->rda[i].rx_seqno = 0;
lp->rda[i].in_use = 1;
lp->rda[i].link =
lp->rda_laddr + (i + 1) * sizeof(sonic_rd_t);
printk("sonic_init: initialize receive descriptors\n");
for (i=0; i<SONIC_NUM_RDS; i++) {
sonic_rda_put(dev, i, SONIC_RD_STATUS, 0);
sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0);
sonic_rda_put(dev, i, SONIC_RD_PKTPTR_L, 0);
sonic_rda_put(dev, i, SONIC_RD_PKTPTR_H, 0);
sonic_rda_put(dev, i, SONIC_RD_SEQNO, 0);
sonic_rda_put(dev, i, SONIC_RD_IN_USE, 1);
sonic_rda_put(dev, i, SONIC_RD_LINK,
lp->rda_laddr +
((i+1) * SIZEOF_SONIC_RD * SONIC_BUS_SCALE(lp->dma_bitmode)));
}
/* fix last descriptor */
lp->rda[SONIC_NUM_RDS - 1].link = lp->rda_laddr;
sonic_rda_put(dev, SONIC_NUM_RDS - 1, SONIC_RD_LINK,
(lp->rda_laddr & 0xffff) | SONIC_EOL);
lp->eol_rx = SONIC_NUM_RDS - 1;
lp->cur_rx = 0;
SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16);
SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff);
@ -542,34 +696,34 @@ static int sonic_init(struct net_device *dev)
if (sonic_debug > 2)
printk("sonic_init: initialize transmit descriptors\n");
for (i = 0; i < SONIC_NUM_TDS; i++) {
lp->tda[i].tx_status = 0;
lp->tda[i].tx_config = 0;
lp->tda[i].tx_pktsize = 0;
lp->tda[i].tx_frag_count = 0;
lp->tda[i].link =
(lp->tda_laddr +
(i + 1) * sizeof(sonic_td_t)) | SONIC_END_OF_LINKS;
sonic_tda_put(dev, i, SONIC_TD_STATUS, 0);
sonic_tda_put(dev, i, SONIC_TD_CONFIG, 0);
sonic_tda_put(dev, i, SONIC_TD_PKTSIZE, 0);
sonic_tda_put(dev, i, SONIC_TD_FRAG_COUNT, 0);
sonic_tda_put(dev, i, SONIC_TD_LINK,
(lp->tda_laddr & 0xffff) +
(i + 1) * SIZEOF_SONIC_TD * SONIC_BUS_SCALE(lp->dma_bitmode));
lp->tx_skb[i] = NULL;
}
lp->tda[SONIC_NUM_TDS - 1].link =
(lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS;
/* fix last descriptor */
sonic_tda_put(dev, SONIC_NUM_TDS - 1, SONIC_TD_LINK,
(lp->tda_laddr & 0xffff));
SONIC_WRITE(SONIC_UTDA, lp->tda_laddr >> 16);
SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff);
lp->cur_tx = lp->dirty_tx = 0;
lp->cur_tx = lp->next_tx = 0;
lp->eol_tx = SONIC_NUM_TDS - 1;
/*
* put our own address to CAM desc[0]
*/
lp->cda.cam_desc[0].cam_cap0 =
dev->dev_addr[1] << 8 | dev->dev_addr[0];
lp->cda.cam_desc[0].cam_cap1 =
dev->dev_addr[3] << 8 | dev->dev_addr[2];
lp->cda.cam_desc[0].cam_cap2 =
dev->dev_addr[5] << 8 | dev->dev_addr[4];
lp->cda.cam_enable = 1;
sonic_cda_put(dev, 0, SONIC_CD_CAP0, dev->dev_addr[1] << 8 | dev->dev_addr[0]);
sonic_cda_put(dev, 0, SONIC_CD_CAP1, dev->dev_addr[3] << 8 | dev->dev_addr[2]);
sonic_cda_put(dev, 0, SONIC_CD_CAP2, dev->dev_addr[5] << 8 | dev->dev_addr[4]);
sonic_set_cam_enable(dev, 1);
for (i = 0; i < 16; i++)
lp->cda.cam_desc[i].cam_entry_pointer = i;
sonic_cda_put(dev, i, SONIC_CD_ENTRY_POINTER, i);
/*
* initialize CAM registers
@ -588,8 +742,8 @@ static int sonic_init(struct net_device *dev)
break;
}
if (sonic_debug > 2) {
printk("sonic_init: CMD=%x, ISR=%x\n",
SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR));
printk("sonic_init: CMD=%x, ISR=%x\n, i=%d",
SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i);
}
/*
@ -604,7 +758,7 @@ static int sonic_init(struct net_device *dev)
cmd = SONIC_READ(SONIC_CMD);
if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0)
printk("sonic_init: failed, status=%x\n", cmd);
printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd);
if (sonic_debug > 2)
printk("sonic_init: new status=%x\n",

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Helpfile for sonic.c
* Header file for sonic.c
*
* (C) Waldorf Electronics, Germany
* Written by Andreas Busse
@ -9,10 +9,16 @@
* and pad structure members must be exchanged. Also, the structures
* need to be changed accordingly to the bus size.
*
* 981229 MSch: did just that for the 68k Mac port (32 bit, big endian),
* see CONFIG_MACSONIC branch below.
* 981229 MSch: did just that for the 68k Mac port (32 bit, big endian)
*
* 990611 David Huggins-Daines <dhd@debian.org>: This machine abstraction
* does not cope with 16-bit bus sizes very well. Therefore I have
* rewritten it with ugly macros and evil inlines.
*
* 050625 Finn Thain: introduced more 32-bit cards and dhd's support
* for 16-bit cards (from the mac68k project).
*/
#ifndef SONIC_H
#define SONIC_H
@ -83,6 +89,7 @@
/*
* Error counters
*/
#define SONIC_CRCT 0x2c
#define SONIC_FAET 0x2d
#define SONIC_MPT 0x2e
@ -182,14 +189,14 @@
#define SONIC_INT_BR 0x4000
#define SONIC_INT_HBL 0x2000
#define SONIC_INT_LCD 0x1000
#define SONIC_INT_PINT 0x0800
#define SONIC_INT_PKTRX 0x0400
#define SONIC_INT_TXDN 0x0200
#define SONIC_INT_TXER 0x0100
#define SONIC_INT_TC 0x0080
#define SONIC_INT_RDE 0x0040
#define SONIC_INT_RBE 0x0020
#define SONIC_INT_LCD 0x1000
#define SONIC_INT_PINT 0x0800
#define SONIC_INT_PKTRX 0x0400
#define SONIC_INT_TXDN 0x0200
#define SONIC_INT_TXER 0x0100
#define SONIC_INT_TC 0x0080
#define SONIC_INT_RDE 0x0040
#define SONIC_INT_RBE 0x0020
#define SONIC_INT_RBAE 0x0010
#define SONIC_INT_CRC 0x0008
#define SONIC_INT_FAE 0x0004
@ -201,224 +208,61 @@
* The interrupts we allow.
*/
#define SONIC_IMR_DEFAULT (SONIC_INT_BR | \
SONIC_INT_LCD | \
SONIC_INT_PINT | \
#define SONIC_IMR_DEFAULT ( SONIC_INT_BR | \
SONIC_INT_LCD | \
SONIC_INT_RFO | \
SONIC_INT_PKTRX | \
SONIC_INT_TXDN | \
SONIC_INT_TXER | \
SONIC_INT_RDE | \
SONIC_INT_RBE | \
SONIC_INT_RBAE | \
SONIC_INT_CRC | \
SONIC_INT_FAE | \
SONIC_INT_MP)
#define SONIC_END_OF_LINKS 0x0001
#ifdef CONFIG_MACSONIC
/*
* Big endian like structures on 680x0 Macs
*/
typedef struct {
u32 rx_bufadr_l; /* receive buffer ptr */
u32 rx_bufadr_h;
u32 rx_bufsize_l; /* no. of words in the receive buffer */
u32 rx_bufsize_h;
} sonic_rr_t;
/*
* Sonic receive descriptor. Receive descriptors are
* kept in a linked list of these structures.
*/
typedef struct {
SREGS_PAD(pad0);
u16 rx_status; /* status after reception of a packet */
SREGS_PAD(pad1);
u16 rx_pktlen; /* length of the packet incl. CRC */
/*
* Pointers to the location in the receive buffer area (RBA)
* where the packet resides. A packet is always received into
* a contiguous piece of memory.
*/
SREGS_PAD(pad2);
u16 rx_pktptr_l;
SREGS_PAD(pad3);
u16 rx_pktptr_h;
SREGS_PAD(pad4);
u16 rx_seqno; /* sequence no. */
SREGS_PAD(pad5);
u16 link; /* link to next RDD (end if EOL bit set) */
/*
* Owner of this descriptor, 0= driver, 1=sonic
*/
SREGS_PAD(pad6);
u16 in_use;
caddr_t rda_next; /* pointer to next RD */
} sonic_rd_t;
/*
* Describes a Transmit Descriptor
*/
typedef struct {
SREGS_PAD(pad0);
u16 tx_status; /* status after transmission of a packet */
SREGS_PAD(pad1);
u16 tx_config; /* transmit configuration for this packet */
SREGS_PAD(pad2);
u16 tx_pktsize; /* size of the packet to be transmitted */
SREGS_PAD(pad3);
u16 tx_frag_count; /* no. of fragments */
SREGS_PAD(pad4);
u16 tx_frag_ptr_l;
SREGS_PAD(pad5);
u16 tx_frag_ptr_h;
SREGS_PAD(pad6);
u16 tx_frag_size;
SREGS_PAD(pad7);
u16 link; /* ptr to next descriptor */
} sonic_td_t;
/*
* Describes an entry in the CAM Descriptor Area.
*/
typedef struct {
SREGS_PAD(pad0);
u16 cam_entry_pointer;
SREGS_PAD(pad1);
u16 cam_cap0;
SREGS_PAD(pad2);
u16 cam_cap1;
SREGS_PAD(pad3);
u16 cam_cap2;
} sonic_cd_t;
#define SONIC_EOL 0x0001
#define CAM_DESCRIPTORS 16
/* Offsets in the various DMA buffers accessed by the SONIC */
typedef struct {
sonic_cd_t cam_desc[CAM_DESCRIPTORS];
SREGS_PAD(pad);
u16 cam_enable;
} sonic_cda_t;
#define SONIC_BITMODE16 0
#define SONIC_BITMODE32 1
#define SONIC_BUS_SCALE(bitmode) ((bitmode) ? 4 : 2)
/* Note! These are all measured in bus-size units, so use SONIC_BUS_SCALE */
#define SIZEOF_SONIC_RR 4
#define SONIC_RR_BUFADR_L 0
#define SONIC_RR_BUFADR_H 1
#define SONIC_RR_BUFSIZE_L 2
#define SONIC_RR_BUFSIZE_H 3
#else /* original declarations, little endian 32 bit */
#define SIZEOF_SONIC_RD 7
#define SONIC_RD_STATUS 0
#define SONIC_RD_PKTLEN 1
#define SONIC_RD_PKTPTR_L 2
#define SONIC_RD_PKTPTR_H 3
#define SONIC_RD_SEQNO 4
#define SONIC_RD_LINK 5
#define SONIC_RD_IN_USE 6
/*
* structure definitions
*/
#define SIZEOF_SONIC_TD 8
#define SONIC_TD_STATUS 0
#define SONIC_TD_CONFIG 1
#define SONIC_TD_PKTSIZE 2
#define SONIC_TD_FRAG_COUNT 3
#define SONIC_TD_FRAG_PTR_L 4
#define SONIC_TD_FRAG_PTR_H 5
#define SONIC_TD_FRAG_SIZE 6
#define SONIC_TD_LINK 7
typedef struct {
u32 rx_bufadr_l; /* receive buffer ptr */
u32 rx_bufadr_h;
#define SIZEOF_SONIC_CD 4
#define SONIC_CD_ENTRY_POINTER 0
#define SONIC_CD_CAP0 1
#define SONIC_CD_CAP1 2
#define SONIC_CD_CAP2 3
u32 rx_bufsize_l; /* no. of words in the receive buffer */
u32 rx_bufsize_h;
} sonic_rr_t;
/*
* Sonic receive descriptor. Receive descriptors are
* kept in a linked list of these structures.
*/
typedef struct {
u16 rx_status; /* status after reception of a packet */
SREGS_PAD(pad0);
u16 rx_pktlen; /* length of the packet incl. CRC */
SREGS_PAD(pad1);
/*
* Pointers to the location in the receive buffer area (RBA)
* where the packet resides. A packet is always received into
* a contiguous piece of memory.
*/
u16 rx_pktptr_l;
SREGS_PAD(pad2);
u16 rx_pktptr_h;
SREGS_PAD(pad3);
u16 rx_seqno; /* sequence no. */
SREGS_PAD(pad4);
u16 link; /* link to next RDD (end if EOL bit set) */
SREGS_PAD(pad5);
/*
* Owner of this descriptor, 0= driver, 1=sonic
*/
u16 in_use;
SREGS_PAD(pad6);
caddr_t rda_next; /* pointer to next RD */
} sonic_rd_t;
/*
* Describes a Transmit Descriptor
*/
typedef struct {
u16 tx_status; /* status after transmission of a packet */
SREGS_PAD(pad0);
u16 tx_config; /* transmit configuration for this packet */
SREGS_PAD(pad1);
u16 tx_pktsize; /* size of the packet to be transmitted */
SREGS_PAD(pad2);
u16 tx_frag_count; /* no. of fragments */
SREGS_PAD(pad3);
u16 tx_frag_ptr_l;
SREGS_PAD(pad4);
u16 tx_frag_ptr_h;
SREGS_PAD(pad5);
u16 tx_frag_size;
SREGS_PAD(pad6);
u16 link; /* ptr to next descriptor */
SREGS_PAD(pad7);
} sonic_td_t;
/*
* Describes an entry in the CAM Descriptor Area.
*/
typedef struct {
u16 cam_entry_pointer;
SREGS_PAD(pad0);
u16 cam_cap0;
SREGS_PAD(pad1);
u16 cam_cap1;
SREGS_PAD(pad2);
u16 cam_cap2;
SREGS_PAD(pad3);
} sonic_cd_t;
#define CAM_DESCRIPTORS 16
typedef struct {
sonic_cd_t cam_desc[CAM_DESCRIPTORS];
u16 cam_enable;
SREGS_PAD(pad);
} sonic_cda_t;
#endif /* endianness */
#define SIZEOF_SONIC_CDA ((CAM_DESCRIPTORS * SIZEOF_SONIC_CD) + 1)
#define SONIC_CDA_CAM_ENABLE (CAM_DESCRIPTORS * SIZEOF_SONIC_CD)
/*
* Some tunables for the buffer areas. Power of 2 is required
@ -426,44 +270,60 @@ typedef struct {
*
* MSch: use more buffer space for the slow m68k Macs!
*/
#ifdef CONFIG_MACSONIC
#define SONIC_NUM_RRS 32 /* number of receive resources */
#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */
#define SONIC_NUM_TDS 32 /* number of transmit descriptors */
#else
#define SONIC_NUM_RRS 16 /* number of receive resources */
#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */
#define SONIC_NUM_TDS 16 /* number of transmit descriptors */
#endif
#define SONIC_RBSIZE 1520 /* size of one resource buffer */
#define SONIC_NUM_RRS 16 /* number of receive resources */
#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */
#define SONIC_NUM_TDS 16 /* number of transmit descriptors */
#define SONIC_RDS_MASK (SONIC_NUM_RDS-1)
#define SONIC_TDS_MASK (SONIC_NUM_TDS-1)
#define SONIC_RDS_MASK (SONIC_NUM_RDS-1)
#define SONIC_TDS_MASK (SONIC_NUM_TDS-1)
#define SONIC_RBSIZE 1520 /* size of one resource buffer */
/* Again, measured in bus size units! */
#define SIZEOF_SONIC_DESC (SIZEOF_SONIC_CDA \
+ (SIZEOF_SONIC_TD * SONIC_NUM_TDS) \
+ (SIZEOF_SONIC_RD * SONIC_NUM_RDS) \
+ (SIZEOF_SONIC_RR * SONIC_NUM_RRS))
/* Information that need to be kept for each board. */
struct sonic_local {
sonic_cda_t cda; /* virtual CPU address of CDA */
sonic_td_t tda[SONIC_NUM_TDS]; /* transmit descriptor area */
sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource area */
sonic_rd_t rda[SONIC_NUM_RDS]; /* receive descriptor area */
struct sk_buff *tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */
unsigned int tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */
unsigned char *rba; /* start of receive buffer areas */
unsigned int cda_laddr; /* logical DMA address of CDA */
unsigned int tda_laddr; /* logical DMA address of TDA */
unsigned int rra_laddr; /* logical DMA address of RRA */
unsigned int rda_laddr; /* logical DMA address of RDA */
unsigned int rba_laddr; /* logical DMA address of RBA */
unsigned int cur_rra; /* current indexes to resource areas */
/* Bus size. 0 == 16 bits, 1 == 32 bits. */
int dma_bitmode;
/* Register offset within the longword (independent of endianness,
and varies from one type of Macintosh SONIC to another
(Aarrgh)) */
int reg_offset;
void *descriptors;
/* Crud. These areas have to be within the same 64K. Therefore
we allocate a desriptors page, and point these to places within it. */
void *cda; /* CAM descriptor area */
void *tda; /* Transmit descriptor area */
void *rra; /* Receive resource area */
void *rda; /* Receive descriptor area */
struct sk_buff* volatile rx_skb[SONIC_NUM_RRS]; /* packets to be received */
struct sk_buff* volatile tx_skb[SONIC_NUM_TDS]; /* packets to be transmitted */
unsigned int tx_len[SONIC_NUM_TDS]; /* lengths of tx DMA mappings */
/* Logical DMA addresses on MIPS, bus addresses on m68k
* (so "laddr" is a bit misleading) */
dma_addr_t descriptors_laddr;
u32 cda_laddr; /* logical DMA address of CDA */
u32 tda_laddr; /* logical DMA address of TDA */
u32 rra_laddr; /* logical DMA address of RRA */
u32 rda_laddr; /* logical DMA address of RDA */
dma_addr_t rx_laddr[SONIC_NUM_RRS]; /* logical DMA addresses of rx skbuffs */
dma_addr_t tx_laddr[SONIC_NUM_TDS]; /* logical DMA addresses of tx skbuffs */
unsigned int rra_end;
unsigned int cur_rwp;
unsigned int cur_rx;
unsigned int cur_tx;
unsigned int dirty_tx; /* last unacked transmit packet */
char tx_full;
unsigned int cur_tx; /* first unacked transmit packet */
unsigned int eol_rx;
unsigned int eol_tx; /* last unacked transmit packet */
unsigned int next_tx; /* next free TD */
struct device *device; /* generic device */
struct net_device_stats stats;
};
#define TX_TIMEOUT 6
#define TX_TIMEOUT (3 * HZ)
/* Index to functions, as function prototypes. */
@ -477,6 +337,114 @@ static void sonic_multicast_list(struct net_device *dev);
static int sonic_init(struct net_device *dev);
static void sonic_tx_timeout(struct net_device *dev);
/* Internal inlines for reading/writing DMA buffers. Note that bus
size and endianness matter here, whereas they don't for registers,
as far as we can tell. */
/* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put()
is a much better name. */
static inline void sonic_buf_put(void* base, int bitmode,
int offset, __u16 val)
{
if (bitmode)
#ifdef __BIG_ENDIAN
((__u16 *) base + (offset*2))[1] = val;
#else
((__u16 *) base + (offset*2))[0] = val;
#endif
else
((__u16 *) base)[offset] = val;
}
static inline __u16 sonic_buf_get(void* base, int bitmode,
int offset)
{
if (bitmode)
#ifdef __BIG_ENDIAN
return ((volatile __u16 *) base + (offset*2))[1];
#else
return ((volatile __u16 *) base + (offset*2))[0];
#endif
else
return ((volatile __u16 *) base)[offset];
}
/* Inlines that you should actually use for reading/writing DMA buffers */
static inline void sonic_cda_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
sonic_buf_put(lp->cda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_CD) + offset, val);
}
static inline __u16 sonic_cda_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
return sonic_buf_get(lp->cda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_CD) + offset);
}
static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val);
}
static inline __u16 sonic_get_cam_enable(struct net_device* dev)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE);
}
static inline void sonic_tda_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
sonic_buf_put(lp->tda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_TD) + offset, val);
}
static inline __u16 sonic_tda_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
return sonic_buf_get(lp->tda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_TD) + offset);
}
static inline void sonic_rda_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
sonic_buf_put(lp->rda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RD) + offset, val);
}
static inline __u16 sonic_rda_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
return sonic_buf_get(lp->rda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RD) + offset);
}
static inline void sonic_rra_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
sonic_buf_put(lp->rra, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RR) + offset, val);
}
static inline __u16 sonic_rra_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local* lp = (struct sonic_local *) dev->priv;
return sonic_buf_get(lp->rra, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RR) + offset);
}
static const char *version =
"sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";

Просмотреть файл

@ -84,7 +84,7 @@ config 3C359
config TMS380TR
tristate "Generic TMS380 Token Ring ISA/PCI adapter support"
depends on TR && (PCI || ISA && ISA_DMA_API)
depends on TR && (PCI || ISA && ISA_DMA_API || MCA)
select FW_LOADER
---help---
This driver provides generic support for token ring adapters
@ -158,7 +158,7 @@ config ABYSS
config MADGEMC
tristate "Madge Smart 16/4 Ringnode MicroChannel"
depends on TR && TMS380TR && MCA_LEGACY
depends on TR && TMS380TR && MCA
help
This tms380 module supports the Madge Smart 16/4 MC16 and MC32
MicroChannel adapters.

Просмотреть файл

@ -139,7 +139,7 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
*/
dev->base_addr += 0x10;
ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev);
ret = tmsdev_init(dev, &pdev->dev);
if (ret) {
printk("%s: unable to get memory for dev->priv.\n",
dev->name);

Просмотреть файл

@ -20,7 +20,7 @@
static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
#include <linux/module.h>
#include <linux/mca-legacy.h>
#include <linux/mca.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pci.h>
@ -38,9 +38,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
#define MADGEMC_IO_EXTENT 32
#define MADGEMC_SIF_OFFSET 0x08
struct madgemc_card {
struct net_device *dev;
struct card_info {
/*
* These are read from the BIA ROM.
*/
@ -57,16 +55,12 @@ struct madgemc_card {
unsigned int arblevel:4;
unsigned int ringspeed:2; /* 0 = 4mb, 1 = 16, 2 = Auto/none */
unsigned int cabletype:1; /* 0 = RJ45, 1 = DB9 */
struct madgemc_card *next;
};
static struct madgemc_card *madgemc_card_list;
static int madgemc_open(struct net_device *dev);
static int madgemc_close(struct net_device *dev);
static int madgemc_chipset_init(struct net_device *dev);
static void madgemc_read_rom(struct madgemc_card *card);
static void madgemc_read_rom(struct net_device *dev, struct card_info *card);
static unsigned short madgemc_setnselout_pins(struct net_device *dev);
static void madgemc_setcabletype(struct net_device *dev, int type);
@ -151,261 +145,237 @@ static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsign
static int __init madgemc_probe(void)
static int __devinit madgemc_probe(struct device *device)
{
static int versionprinted;
struct net_device *dev;
struct net_local *tp;
struct madgemc_card *card;
int i,slot = 0;
__u8 posreg[4];
struct card_info *card;
struct mca_device *mdev = to_mca_device(device);
int ret = 0, i = 0;
if (!MCA_bus)
return -1;
while (slot != MCA_NOTFOUND) {
/*
* Currently we only support the MC16/32 (MCA ID 002d)
*/
slot = mca_find_unused_adapter(0x002d, slot);
if (slot == MCA_NOTFOUND)
break;
if (versionprinted++ == 0)
printk("%s", version);
/*
* If we get here, we have an adapter.
*/
if (versionprinted++ == 0)
printk("%s", version);
if(mca_device_claimed(mdev))
return -EBUSY;
mca_device_set_claim(mdev, 1);
dev = alloc_trdev(sizeof(struct net_local));
if (dev == NULL) {
printk("madgemc: unable to allocate dev space\n");
if (madgemc_card_list)
return 0;
return -1;
}
dev = alloc_trdev(sizeof(struct net_local));
if (!dev) {
printk("madgemc: unable to allocate dev space\n");
mca_device_set_claim(mdev, 0);
ret = -ENOMEM;
goto getout;
}
SET_MODULE_OWNER(dev);
dev->dma = 0;
SET_MODULE_OWNER(dev);
dev->dma = 0;
/*
* Fetch MCA config registers
*/
for(i=0;i<4;i++)
posreg[i] = mca_read_stored_pos(slot, i+2);
card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL);
if (card==NULL) {
printk("madgemc: unable to allocate card struct\n");
free_netdev(dev);
if (madgemc_card_list)
return 0;
return -1;
}
card->dev = dev;
card = kmalloc(sizeof(struct card_info), GFP_KERNEL);
if (card==NULL) {
printk("madgemc: unable to allocate card struct\n");
ret = -ENOMEM;
goto getout1;
}
/*
* Parse configuration information. This all comes
* directly from the publicly available @002d.ADF.
* Get it from Madge or your local ADF library.
*/
/*
* Parse configuration information. This all comes
* directly from the publicly available @002d.ADF.
* Get it from Madge or your local ADF library.
*/
/*
* Base address
*/
dev->base_addr = 0x0a20 +
((posreg[2] & MC16_POS2_ADDR2)?0x0400:0) +
((posreg[0] & MC16_POS0_ADDR1)?0x1000:0) +
((posreg[3] & MC16_POS3_ADDR3)?0x2000:0);
/*
* Base address
*/
dev->base_addr = 0x0a20 +
((mdev->pos[2] & MC16_POS2_ADDR2)?0x0400:0) +
((mdev->pos[0] & MC16_POS0_ADDR1)?0x1000:0) +
((mdev->pos[3] & MC16_POS3_ADDR3)?0x2000:0);
/*
* Interrupt line
*/
switch(posreg[0] >> 6) { /* upper two bits */
/*
* Interrupt line
*/
switch(mdev->pos[0] >> 6) { /* upper two bits */
case 0x1: dev->irq = 3; break;
case 0x2: dev->irq = 9; break; /* IRQ 2 = IRQ 9 */
case 0x3: dev->irq = 10; break;
default: dev->irq = 0; break;
}
}
if (dev->irq == 0) {
printk("%s: invalid IRQ\n", dev->name);
goto getout1;
}
if (dev->irq == 0) {
printk("%s: invalid IRQ\n", dev->name);
ret = -EBUSY;
goto getout2;
}
if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT,
"madgemc")) {
printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr);
dev->base_addr += MADGEMC_SIF_OFFSET;
goto getout1;
}
if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT,
"madgemc")) {
printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", mdev->slot, dev->base_addr);
dev->base_addr += MADGEMC_SIF_OFFSET;
ret = -EBUSY;
goto getout2;
}
dev->base_addr += MADGEMC_SIF_OFFSET;
/*
* Arbitration Level
*/
card->arblevel = ((mdev->pos[0] >> 1) & 0x7) + 8;
/*
* Burst mode and Fairness
*/
card->burstmode = ((mdev->pos[2] >> 6) & 0x3);
card->fairness = ((mdev->pos[2] >> 4) & 0x1);
/*
* Ring Speed
*/
if ((mdev->pos[1] >> 2)&0x1)
card->ringspeed = 2; /* not selected */
else if ((mdev->pos[2] >> 5) & 0x1)
card->ringspeed = 1; /* 16Mb */
else
card->ringspeed = 0; /* 4Mb */
/*
* Cable type
*/
if ((mdev->pos[1] >> 6)&0x1)
card->cabletype = 1; /* STP/DB9 */
else
card->cabletype = 0; /* UTP/RJ-45 */
/*
* ROM Info. This requires us to actually twiddle
* bits on the card, so we must ensure above that
* the base address is free of conflict (request_region above).
*/
madgemc_read_rom(dev, card);
/*
* Arbitration Level
*/
card->arblevel = ((posreg[0] >> 1) & 0x7) + 8;
/*
* Burst mode and Fairness
*/
card->burstmode = ((posreg[2] >> 6) & 0x3);
card->fairness = ((posreg[2] >> 4) & 0x1);
/*
* Ring Speed
*/
if ((posreg[1] >> 2)&0x1)
card->ringspeed = 2; /* not selected */
else if ((posreg[2] >> 5) & 0x1)
card->ringspeed = 1; /* 16Mb */
else
card->ringspeed = 0; /* 4Mb */
/*
* Cable type
*/
if ((posreg[1] >> 6)&0x1)
card->cabletype = 1; /* STP/DB9 */
else
card->cabletype = 0; /* UTP/RJ-45 */
/*
* ROM Info. This requires us to actually twiddle
* bits on the card, so we must ensure above that
* the base address is free of conflict (request_region above).
*/
madgemc_read_rom(card);
if (card->manid != 0x4d) { /* something went wrong */
printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid);
goto getout3;
}
if (card->manid != 0x4d) { /* something went wrong */
printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid);
goto getout;
}
if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) {
printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype);
goto getout;
}
if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) {
printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype);
ret = -EIO;
goto getout3;
}
/* All cards except Rev 0 and 1 MC16's have 256kb of RAM */
if ((card->cardtype == 0x08) && (card->cardrev <= 0x01))
card->ramsize = 128;
else
card->ramsize = 256;
/* All cards except Rev 0 and 1 MC16's have 256kb of RAM */
if ((card->cardtype == 0x08) && (card->cardrev <= 0x01))
card->ramsize = 128;
else
card->ramsize = 256;
printk("%s: %s Rev %d at 0x%04lx IRQ %d\n",
dev->name,
(card->cardtype == 0x08)?MADGEMC16_CARDNAME:
MADGEMC32_CARDNAME, card->cardrev,
dev->base_addr, dev->irq);
printk("%s: %s Rev %d at 0x%04lx IRQ %d\n",
dev->name,
(card->cardtype == 0x08)?MADGEMC16_CARDNAME:
MADGEMC32_CARDNAME, card->cardrev,
dev->base_addr, dev->irq);
if (card->cardtype == 0x0d)
printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name);
if (card->cardtype == 0x0d)
printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name);
if (card->ringspeed==2) { /* Unknown */
printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name);
card->ringspeed = 1; /* default to 16mb */
}
if (card->ringspeed==2) { /* Unknown */
printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name);
card->ringspeed = 1; /* default to 16mb */
}
printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize);
printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize);
printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name,
(card->ringspeed)?16:4,
card->cabletype?"STP/DB9":"UTP/RJ-45");
printk("%s: Arbitration Level: %d\n", dev->name,
card->arblevel);
printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name,
(card->ringspeed)?16:4,
card->cabletype?"STP/DB9":"UTP/RJ-45");
printk("%s: Arbitration Level: %d\n", dev->name,
card->arblevel);
printk("%s: Burst Mode: ", dev->name);
switch(card->burstmode) {
printk("%s: Burst Mode: ", dev->name);
switch(card->burstmode) {
case 0: printk("Cycle steal"); break;
case 1: printk("Limited burst"); break;
case 2: printk("Delayed release"); break;
case 3: printk("Immediate release"); break;
}
printk(" (%s)\n", (card->fairness)?"Unfair":"Fair");
}
printk(" (%s)\n", (card->fairness)?"Unfair":"Fair");
/*
* Enable SIF before we assign the interrupt handler,
* just in case we get spurious interrupts that need
* handling.
*/
outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */
madgemc_setsifsel(dev, 1);
if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ,
"madgemc", dev))
goto getout;
madgemc_chipset_init(dev); /* enables interrupts! */
madgemc_setcabletype(dev, card->cabletype);
/* Setup MCA structures */
mca_set_adapter_name(slot, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
mca_set_adapter_procfn(slot, madgemc_mcaproc, dev);
mca_mark_as_used(slot);
printk("%s: Ring Station Address: ", dev->name);
printk("%2.2x", dev->dev_addr[0]);
for (i = 1; i < 6; i++)
printk(":%2.2x", dev->dev_addr[i]);
printk("\n");
/* XXX is ISA_MAX_ADDRESS correct here? */
if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) {
printk("%s: unable to get memory for dev->priv.\n",
dev->name);
release_region(dev->base_addr-MADGEMC_SIF_OFFSET,
MADGEMC_IO_EXTENT);
kfree(card);
tmsdev_term(dev);
free_netdev(dev);
if (madgemc_card_list)
return 0;
return -1;
}
tp = netdev_priv(dev);
/*
* The MC16 is physically a 32bit card. However, Madge
* insists on calling it 16bit, so I'll assume here that
* they know what they're talking about. Cut off DMA
* at 16mb.
*/
tp->setnselout = madgemc_setnselout_pins;
tp->sifwriteb = madgemc_sifwriteb;
tp->sifreadb = madgemc_sifreadb;
tp->sifwritew = madgemc_sifwritew;
tp->sifreadw = madgemc_sifreadw;
tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4;
memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1);
dev->open = madgemc_open;
dev->stop = madgemc_close;
if (register_netdev(dev) == 0) {
/* Enlist in the card list */
card->next = madgemc_card_list;
madgemc_card_list = card;
slot++;
continue; /* successful, try to find another */
}
free_irq(dev->irq, dev);
getout:
release_region(dev->base_addr-MADGEMC_SIF_OFFSET,
MADGEMC_IO_EXTENT);
getout1:
kfree(card);
free_netdev(dev);
slot++;
/*
* Enable SIF before we assign the interrupt handler,
* just in case we get spurious interrupts that need
* handling.
*/
outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */
madgemc_setsifsel(dev, 1);
if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ,
"madgemc", dev)) {
ret = -EBUSY;
goto getout3;
}
if (madgemc_card_list)
madgemc_chipset_init(dev); /* enables interrupts! */
madgemc_setcabletype(dev, card->cabletype);
/* Setup MCA structures */
mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev);
printk("%s: Ring Station Address: ", dev->name);
printk("%2.2x", dev->dev_addr[0]);
for (i = 1; i < 6; i++)
printk(":%2.2x", dev->dev_addr[i]);
printk("\n");
if (tmsdev_init(dev, device)) {
printk("%s: unable to get memory for dev->priv.\n",
dev->name);
ret = -ENOMEM;
goto getout4;
}
tp = netdev_priv(dev);
/*
* The MC16 is physically a 32bit card. However, Madge
* insists on calling it 16bit, so I'll assume here that
* they know what they're talking about. Cut off DMA
* at 16mb.
*/
tp->setnselout = madgemc_setnselout_pins;
tp->sifwriteb = madgemc_sifwriteb;
tp->sifreadb = madgemc_sifreadb;
tp->sifwritew = madgemc_sifwritew;
tp->sifreadw = madgemc_sifreadw;
tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4;
memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1);
dev->open = madgemc_open;
dev->stop = madgemc_close;
tp->tmspriv = card;
dev_set_drvdata(device, dev);
if (register_netdev(dev) == 0)
return 0;
return -1;
dev_set_drvdata(device, NULL);
ret = -ENOMEM;
getout4:
free_irq(dev->irq, dev);
getout3:
release_region(dev->base_addr-MADGEMC_SIF_OFFSET,
MADGEMC_IO_EXTENT);
getout2:
kfree(card);
getout1:
free_netdev(dev);
getout:
mca_device_set_claim(mdev, 0);
return ret;
}
/*
@ -664,12 +634,12 @@ static void madgemc_chipset_close(struct net_device *dev)
* is complete.
*
*/
static void madgemc_read_rom(struct madgemc_card *card)
static void madgemc_read_rom(struct net_device *dev, struct card_info *card)
{
unsigned long ioaddr;
unsigned char reg0, reg1, tmpreg0, i;
ioaddr = card->dev->base_addr;
ioaddr = dev->base_addr;
reg0 = inb(ioaddr + MC_CONTROL_REG0);
reg1 = inb(ioaddr + MC_CONTROL_REG1);
@ -686,9 +656,9 @@ static void madgemc_read_rom(struct madgemc_card *card)
outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0);
/* Read BIA */
card->dev->addr_len = 6;
dev->addr_len = 6;
for (i = 0; i < 6; i++)
card->dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i);
dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i);
/* Restore original register values */
outb(reg0, ioaddr + MC_CONTROL_REG0);
@ -721,14 +691,10 @@ static int madgemc_close(struct net_device *dev)
static int madgemc_mcaproc(char *buf, int slot, void *d)
{
struct net_device *dev = (struct net_device *)d;
struct madgemc_card *curcard = madgemc_card_list;
struct net_local *tp = dev->priv;
struct card_info *curcard = tp->tmspriv;
int len = 0;
while (curcard) { /* search for card struct */
if (curcard->dev == dev)
break;
curcard = curcard->next;
}
len += sprintf(buf+len, "-------\n");
if (curcard) {
struct net_local *tp = netdev_priv(dev);
@ -763,25 +729,56 @@ static int madgemc_mcaproc(char *buf, int slot, void *d)
return len;
}
static void __exit madgemc_exit(void)
static int __devexit madgemc_remove(struct device *device)
{
struct net_device *dev;
struct madgemc_card *this_card;
while (madgemc_card_list) {
dev = madgemc_card_list->dev;
unregister_netdev(dev);
release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT);
free_irq(dev->irq, dev);
tmsdev_term(dev);
free_netdev(dev);
this_card = madgemc_card_list;
madgemc_card_list = this_card->next;
kfree(this_card);
}
struct net_device *dev = dev_get_drvdata(device);
struct net_local *tp;
struct card_info *card;
if (!dev)
BUG();
tp = dev->priv;
card = tp->tmspriv;
kfree(card);
tp->tmspriv = NULL;
unregister_netdev(dev);
release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT);
free_irq(dev->irq, dev);
tmsdev_term(dev);
free_netdev(dev);
dev_set_drvdata(device, NULL);
return 0;
}
module_init(madgemc_probe);
static short madgemc_adapter_ids[] __initdata = {
0x002d,
0x0000
};
static struct mca_driver madgemc_driver = {
.id_table = madgemc_adapter_ids,
.driver = {
.name = "madgemc",
.bus = &mca_bus_type,
.probe = madgemc_probe,
.remove = __devexit_p(madgemc_remove),
},
};
static int __init madgemc_init (void)
{
return mca_register_driver (&madgemc_driver);
}
static void __exit madgemc_exit (void)
{
mca_unregister_driver (&madgemc_driver);
}
module_init(madgemc_init);
module_exit(madgemc_exit);
MODULE_LICENSE("GPL");

Просмотреть файл

@ -62,8 +62,7 @@ static int dmalist[] __initdata = {
};
static char cardname[] = "Proteon 1392\0";
struct net_device *proteon_probe(int unit);
static u64 dma_mask = ISA_MAX_ADDRESS;
static int proteon_open(struct net_device *dev);
static void proteon_read_eeprom(struct net_device *dev);
static unsigned short proteon_setnselout_pins(struct net_device *dev);
@ -116,7 +115,7 @@ nodev:
return -ENODEV;
}
static int __init setup_card(struct net_device *dev)
static int __init setup_card(struct net_device *dev, struct device *pdev)
{
struct net_local *tp;
static int versionprinted;
@ -137,7 +136,7 @@ static int __init setup_card(struct net_device *dev)
}
}
if (err)
goto out4;
goto out5;
/* At this point we have found a valid card. */
@ -145,14 +144,15 @@ static int __init setup_card(struct net_device *dev)
printk(KERN_DEBUG "%s", version);
err = -EIO;
if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL))
pdev->dma_mask = &dma_mask;
if (tmsdev_init(dev, pdev))
goto out4;
dev->base_addr &= ~3;
proteon_read_eeprom(dev);
printk(KERN_DEBUG "%s: Ring Station Address: ", dev->name);
printk(KERN_DEBUG "proteon.c: Ring Station Address: ");
printk("%2.2x", dev->dev_addr[0]);
for (j = 1; j < 6; j++)
printk(":%2.2x", dev->dev_addr[j]);
@ -185,7 +185,7 @@ static int __init setup_card(struct net_device *dev)
if(irqlist[j] == 0)
{
printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name);
printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n");
goto out3;
}
}
@ -196,15 +196,15 @@ static int __init setup_card(struct net_device *dev)
break;
if (irqlist[j] == 0)
{
printk(KERN_INFO "%s: Illegal IRQ %d specified\n",
dev->name, dev->irq);
printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n",
dev->irq);
goto out3;
}
if (request_irq(dev->irq, tms380tr_interrupt, 0,
cardname, dev))
{
printk(KERN_INFO "%s: Selected IRQ %d not available\n",
dev->name, dev->irq);
printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n",
dev->irq);
goto out3;
}
}
@ -220,7 +220,7 @@ static int __init setup_card(struct net_device *dev)
if(dmalist[j] == 0)
{
printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name);
printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n");
goto out2;
}
}
@ -231,25 +231,25 @@ static int __init setup_card(struct net_device *dev)
break;
if (dmalist[j] == 0)
{
printk(KERN_INFO "%s: Illegal DMA %d specified\n",
dev->name, dev->dma);
printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n",
dev->dma);
goto out2;
}
if (request_dma(dev->dma, cardname))
{
printk(KERN_INFO "%s: Selected DMA %d not available\n",
dev->name, dev->dma);
printk(KERN_INFO "proteon.c: Selected DMA %d not available\n",
dev->dma);
goto out2;
}
}
printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n",
dev->name, dev->base_addr, dev->irq, dev->dma);
err = register_netdev(dev);
if (err)
goto out;
printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n",
dev->name, dev->base_addr, dev->irq, dev->dma);
return 0;
out:
free_dma(dev->dma);
@ -258,34 +258,11 @@ out2:
out3:
tmsdev_term(dev);
out4:
release_region(dev->base_addr, PROTEON_IO_EXTENT);
release_region(dev->base_addr, PROTEON_IO_EXTENT);
out5:
return err;
}
struct net_device * __init proteon_probe(int unit)
{
struct net_device *dev = alloc_trdev(sizeof(struct net_local));
int err = 0;
if (!dev)
return ERR_PTR(-ENOMEM);
if (unit >= 0) {
sprintf(dev->name, "tr%d", unit);
netdev_boot_setup_check(dev);
}
err = setup_card(dev);
if (err)
goto out;
return dev;
out:
free_netdev(dev);
return ERR_PTR(err);
}
/*
* Reads MAC address from adapter RAM, which should've read it from
* the onboard ROM.
@ -352,8 +329,6 @@ static int proteon_open(struct net_device *dev)
return tms380tr_open(dev);
}
#ifdef MODULE
#define ISATR_MAX_ADAPTERS 3
static int io[ISATR_MAX_ADAPTERS];
@ -366,13 +341,23 @@ module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param_array(dma, int, NULL, 0);
static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS];
static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS];
int init_module(void)
static struct device_driver proteon_driver = {
.name = "proteon",
.bus = &platform_bus_type,
};
static int __init proteon_init(void)
{
struct net_device *dev;
struct platform_device *pdev;
int i, num = 0, err = 0;
err = driver_register(&proteon_driver);
if (err)
return err;
for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
dev = alloc_trdev(sizeof(struct net_local));
if (!dev)
@ -381,11 +366,15 @@ int init_module(void)
dev->base_addr = io[i];
dev->irq = irq[i];
dev->dma = dma[i];
err = setup_card(dev);
pdev = platform_device_register_simple("proteon",
i, NULL, 0);
err = setup_card(dev, &pdev->dev);
if (!err) {
proteon_dev[i] = dev;
proteon_dev[i] = pdev;
dev_set_drvdata(&pdev->dev, dev);
++num;
} else {
platform_device_unregister(pdev);
free_netdev(dev);
}
}
@ -399,23 +388,28 @@ int init_module(void)
return (0);
}
void cleanup_module(void)
static void __exit proteon_cleanup(void)
{
struct net_device *dev;
int i;
for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
struct net_device *dev = proteon_dev[i];
struct platform_device *pdev = proteon_dev[i];
if (!dev)
if (!pdev)
continue;
dev = dev_get_drvdata(&pdev->dev);
unregister_netdev(dev);
release_region(dev->base_addr, PROTEON_IO_EXTENT);
free_irq(dev->irq, dev);
free_dma(dev->dma);
tmsdev_term(dev);
free_netdev(dev);
dev_set_drvdata(&pdev->dev, NULL);
platform_device_unregister(pdev);
}
driver_unregister(&proteon_driver);
}
#endif /* MODULE */
module_init(proteon_init);
module_exit(proteon_cleanup);

Просмотреть файл

@ -68,8 +68,7 @@ static int dmalist[] __initdata = {
};
static char isa_cardname[] = "SK NET TR 4/16 ISA\0";
struct net_device *sk_isa_probe(int unit);
static u64 dma_mask = ISA_MAX_ADDRESS;
static int sk_isa_open(struct net_device *dev);
static void sk_isa_read_eeprom(struct net_device *dev);
static unsigned short sk_isa_setnselout_pins(struct net_device *dev);
@ -133,7 +132,7 @@ static int __init sk_isa_probe1(struct net_device *dev, int ioaddr)
return 0;
}
static int __init setup_card(struct net_device *dev)
static int __init setup_card(struct net_device *dev, struct device *pdev)
{
struct net_local *tp;
static int versionprinted;
@ -154,7 +153,7 @@ static int __init setup_card(struct net_device *dev)
}
}
if (err)
goto out4;
goto out5;
/* At this point we have found a valid card. */
@ -162,14 +161,15 @@ static int __init setup_card(struct net_device *dev)
printk(KERN_DEBUG "%s", version);
err = -EIO;
if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL))
pdev->dma_mask = &dma_mask;
if (tmsdev_init(dev, pdev))
goto out4;
dev->base_addr &= ~3;
sk_isa_read_eeprom(dev);
printk(KERN_DEBUG "%s: Ring Station Address: ", dev->name);
printk(KERN_DEBUG "skisa.c: Ring Station Address: ");
printk("%2.2x", dev->dev_addr[0]);
for (j = 1; j < 6; j++)
printk(":%2.2x", dev->dev_addr[j]);
@ -202,7 +202,7 @@ static int __init setup_card(struct net_device *dev)
if(irqlist[j] == 0)
{
printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name);
printk(KERN_INFO "skisa.c: AutoSelect no IRQ available\n");
goto out3;
}
}
@ -213,15 +213,15 @@ static int __init setup_card(struct net_device *dev)
break;
if (irqlist[j] == 0)
{
printk(KERN_INFO "%s: Illegal IRQ %d specified\n",
dev->name, dev->irq);
printk(KERN_INFO "skisa.c: Illegal IRQ %d specified\n",
dev->irq);
goto out3;
}
if (request_irq(dev->irq, tms380tr_interrupt, 0,
isa_cardname, dev))
{
printk(KERN_INFO "%s: Selected IRQ %d not available\n",
dev->name, dev->irq);
printk(KERN_INFO "skisa.c: Selected IRQ %d not available\n",
dev->irq);
goto out3;
}
}
@ -237,7 +237,7 @@ static int __init setup_card(struct net_device *dev)
if(dmalist[j] == 0)
{
printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name);
printk(KERN_INFO "skisa.c: AutoSelect no DMA available\n");
goto out2;
}
}
@ -248,25 +248,25 @@ static int __init setup_card(struct net_device *dev)
break;
if (dmalist[j] == 0)
{
printk(KERN_INFO "%s: Illegal DMA %d specified\n",
dev->name, dev->dma);
printk(KERN_INFO "skisa.c: Illegal DMA %d specified\n",
dev->dma);
goto out2;
}
if (request_dma(dev->dma, isa_cardname))
{
printk(KERN_INFO "%s: Selected DMA %d not available\n",
dev->name, dev->dma);
printk(KERN_INFO "skisa.c: Selected DMA %d not available\n",
dev->dma);
goto out2;
}
}
printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n",
dev->name, dev->base_addr, dev->irq, dev->dma);
err = register_netdev(dev);
if (err)
goto out;
printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n",
dev->name, dev->base_addr, dev->irq, dev->dma);
return 0;
out:
free_dma(dev->dma);
@ -275,33 +275,11 @@ out2:
out3:
tmsdev_term(dev);
out4:
release_region(dev->base_addr, SK_ISA_IO_EXTENT);
release_region(dev->base_addr, SK_ISA_IO_EXTENT);
out5:
return err;
}
struct net_device * __init sk_isa_probe(int unit)
{
struct net_device *dev = alloc_trdev(sizeof(struct net_local));
int err = 0;
if (!dev)
return ERR_PTR(-ENOMEM);
if (unit >= 0) {
sprintf(dev->name, "tr%d", unit);
netdev_boot_setup_check(dev);
}
err = setup_card(dev);
if (err)
goto out;
return dev;
out:
free_netdev(dev);
return ERR_PTR(err);
}
/*
* Reads MAC address from adapter RAM, which should've read it from
* the onboard ROM.
@ -361,8 +339,6 @@ static int sk_isa_open(struct net_device *dev)
return tms380tr_open(dev);
}
#ifdef MODULE
#define ISATR_MAX_ADAPTERS 3
static int io[ISATR_MAX_ADAPTERS];
@ -375,13 +351,23 @@ module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param_array(dma, int, NULL, 0);
static struct net_device *sk_isa_dev[ISATR_MAX_ADAPTERS];
static struct platform_device *sk_isa_dev[ISATR_MAX_ADAPTERS];
int init_module(void)
static struct device_driver sk_isa_driver = {
.name = "skisa",
.bus = &platform_bus_type,
};
static int __init sk_isa_init(void)
{
struct net_device *dev;
struct platform_device *pdev;
int i, num = 0, err = 0;
err = driver_register(&sk_isa_driver);
if (err)
return err;
for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
dev = alloc_trdev(sizeof(struct net_local));
if (!dev)
@ -390,12 +376,15 @@ int init_module(void)
dev->base_addr = io[i];
dev->irq = irq[i];
dev->dma = dma[i];
err = setup_card(dev);
pdev = platform_device_register_simple("skisa",
i, NULL, 0);
err = setup_card(dev, &pdev->dev);
if (!err) {
sk_isa_dev[i] = dev;
sk_isa_dev[i] = pdev;
dev_set_drvdata(&sk_isa_dev[i]->dev, dev);
++num;
} else {
platform_device_unregister(pdev);
free_netdev(dev);
}
}
@ -409,23 +398,28 @@ int init_module(void)
return (0);
}
void cleanup_module(void)
static void __exit sk_isa_cleanup(void)
{
struct net_device *dev;
int i;
for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
struct net_device *dev = sk_isa_dev[i];
struct platform_device *pdev = sk_isa_dev[i];
if (!dev)
if (!pdev)
continue;
dev = dev_get_drvdata(&pdev->dev);
unregister_netdev(dev);
release_region(dev->base_addr, SK_ISA_IO_EXTENT);
free_irq(dev->irq, dev);
free_dma(dev->dma);
tmsdev_term(dev);
free_netdev(dev);
dev_set_drvdata(&pdev->dev, NULL);
platform_device_unregister(pdev);
}
driver_unregister(&sk_isa_driver);
}
#endif /* MODULE */
module_init(sk_isa_init);
module_exit(sk_isa_cleanup);

Просмотреть файл

@ -62,6 +62,7 @@
* normal operation.
* 30-Dec-02 JF Removed incorrect __init from
* tms380tr_init_card.
* 22-Jul-05 JF Converted to dma-mapping.
*
* To do:
* 1. Multi/Broadcast packet handling (this may have fixed itself)
@ -89,7 +90,7 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A
#include <linux/time.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@ -114,8 +115,6 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A
#endif
static unsigned int tms380tr_debug = TMS380TR_DEBUG;
static struct device tms_device;
/* Index to functions, as function prototypes.
* Alphabetical by function name.
*/
@ -434,7 +433,7 @@ static void tms380tr_init_net_local(struct net_device *dev)
skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
/* data unreachable for DMA ? then use local buffer */
dmabuf = pci_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
dmabuf = dma_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE);
if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
{
tp->Rpl[i].SkbStat = SKB_DATA_COPY;
@ -638,10 +637,10 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device
/* Is buffer reachable for Busmaster-DMA? */
length = skb->len;
dmabuf = pci_map_single(tp->pdev, skb->data, length, PCI_DMA_TODEVICE);
dmabuf = dma_map_single(tp->pdev, skb->data, length, DMA_TO_DEVICE);
if(tp->dmalimit && (dmabuf + length > tp->dmalimit)) {
/* Copy frame to local buffer */
pci_unmap_single(tp->pdev, dmabuf, length, PCI_DMA_TODEVICE);
dma_unmap_single(tp->pdev, dmabuf, length, DMA_TO_DEVICE);
dmabuf = 0;
i = tp->TplFree->TPLIndex;
buf = tp->LocalTxBuffers[i];
@ -1284,9 +1283,7 @@ static int tms380tr_reset_adapter(struct net_device *dev)
unsigned short count, c, count2;
const struct firmware *fw_entry = NULL;
strncpy(tms_device.bus_id,dev->name, BUS_ID_SIZE);
if (request_firmware(&fw_entry, "tms380tr.bin", &tms_device) != 0) {
if (request_firmware(&fw_entry, "tms380tr.bin", tp->pdev) != 0) {
printk(KERN_ALERT "%s: firmware %s is missing, cannot start.\n",
dev->name, "tms380tr.bin");
return (-1);
@ -2021,7 +2018,7 @@ static void tms380tr_cancel_tx_queue(struct net_local* tp)
printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);
if (tpl->DMABuff)
pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(tpl->Skb);
}
@ -2090,7 +2087,7 @@ static void tms380tr_tx_status_irq(struct net_device *dev)
tp->MacStat.tx_packets++;
if (tpl->DMABuff)
pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE);
dev_kfree_skb_irq(tpl->Skb);
tpl->BusyFlag = 0; /* "free" TPL */
}
@ -2209,7 +2206,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
tp->MacStat.rx_errors++;
}
if (rpl->DMABuff)
pci_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, PCI_DMA_TODEVICE);
dma_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, DMA_TO_DEVICE);
rpl->DMABuff = 0;
/* Allocate new skb for rpl */
@ -2227,7 +2224,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
skb_put(rpl->Skb, tp->MaxPacketSize);
/* Data unreachable for DMA ? then use local buffer */
dmabuf = pci_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
dmabuf = dma_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE);
if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
{
rpl->SkbStat = SKB_DATA_COPY;
@ -2332,23 +2329,26 @@ void tmsdev_term(struct net_device *dev)
struct net_local *tp;
tp = netdev_priv(dev);
pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local),
PCI_DMA_BIDIRECTIONAL);
dma_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local),
DMA_BIDIRECTIONAL);
}
int tmsdev_init(struct net_device *dev, unsigned long dmalimit,
struct pci_dev *pdev)
int tmsdev_init(struct net_device *dev, struct device *pdev)
{
struct net_local *tms_local;
memset(dev->priv, 0, sizeof(struct net_local));
tms_local = netdev_priv(dev);
init_waitqueue_head(&tms_local->wait_for_tok_int);
tms_local->dmalimit = dmalimit;
if (pdev->dma_mask)
tms_local->dmalimit = *pdev->dma_mask;
else
return -ENOMEM;
tms_local->pdev = pdev;
tms_local->dmabuffer = pci_map_single(pdev, (void *)tms_local,
sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL);
if (tms_local->dmabuffer + sizeof(struct net_local) > dmalimit)
tms_local->dmabuffer = dma_map_single(pdev, (void *)tms_local,
sizeof(struct net_local), DMA_BIDIRECTIONAL);
if (tms_local->dmabuffer + sizeof(struct net_local) >
tms_local->dmalimit)
{
printk(KERN_INFO "%s: Memory not accessible for DMA\n",
dev->name);
@ -2370,8 +2370,6 @@ int tmsdev_init(struct net_device *dev, unsigned long dmalimit,
return 0;
}
#ifdef MODULE
EXPORT_SYMBOL(tms380tr_open);
EXPORT_SYMBOL(tms380tr_close);
EXPORT_SYMBOL(tms380tr_interrupt);
@ -2379,6 +2377,8 @@ EXPORT_SYMBOL(tmsdev_init);
EXPORT_SYMBOL(tmsdev_term);
EXPORT_SYMBOL(tms380tr_wait);
#ifdef MODULE
static struct module *TMS380_module = NULL;
int init_module(void)

Просмотреть файл

@ -17,8 +17,7 @@
int tms380tr_open(struct net_device *dev);
int tms380tr_close(struct net_device *dev);
irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
int tmsdev_init(struct net_device *dev, unsigned long dmalimit,
struct pci_dev *pdev);
int tmsdev_init(struct net_device *dev, struct device *pdev);
void tmsdev_term(struct net_device *dev);
void tms380tr_wait(unsigned long time);
@ -719,7 +718,7 @@ struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */
struct sk_buff *Skb;
unsigned char TPLIndex;
volatile unsigned char BusyFlag;/* Flag: TPL busy? */
dma_addr_t DMABuff; /* DMA IO bus address from pci_map */
dma_addr_t DMABuff; /* DMA IO bus address from dma_map */
};
/* ---------------------Receive Functions-------------------------------*
@ -1060,7 +1059,7 @@ struct s_RPL { /* Receive Parameter List */
struct sk_buff *Skb;
SKB_STAT SkbStat;
int RPLIndex;
dma_addr_t DMABuff; /* DMA IO bus address from pci_map */
dma_addr_t DMABuff; /* DMA IO bus address from dma_map */
};
/* Information that need to be kept for each board. */
@ -1091,7 +1090,7 @@ typedef struct net_local {
RPL *RplTail;
unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE];
struct pci_dev *pdev;
struct device *pdev;
int DataRate;
unsigned char ScbInUse;
unsigned short CMDqueue;

Просмотреть файл

@ -100,7 +100,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
unsigned int pci_irq_line;
unsigned long pci_ioaddr;
struct card_info *cardinfo = &card_info_table[ent->driver_data];
if (versionprinted++ == 0)
printk("%s", version);
@ -143,7 +143,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
printk(":%2.2x", dev->dev_addr[i]);
printk("\n");
ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev);
ret = tmsdev_init(dev, &pdev->dev);
if (ret) {
printk("%s: unable to get memory for dev->priv.\n", dev->name);
goto err_out_irq;

Просмотреть файл

@ -56,7 +56,7 @@
#include <linux/sched.h> /* for jiffies, HZ, etc. */
#include <linux/cycx_drv.h> /* API definitions */
#include <linux/cycx_cfm.h> /* CYCX firmware module definitions */
#include <linux/delay.h> /* udelay */
#include <linux/delay.h> /* udelay, msleep_interruptible */
#include <asm/io.h> /* read[wl], write[wl], ioremap, iounmap */
#define MOD_VERSION 0
@ -74,7 +74,6 @@ static int reset_cyc2x(void __iomem *addr);
static int detect_cyc2x(void __iomem *addr);
/* Miscellaneous functions */
static void delay_cycx(int sec);
static int get_option_index(long *optlist, long optval);
static u16 checksum(u8 *buf, u32 len);
@ -259,7 +258,7 @@ static int memory_exists(void __iomem *addr)
if (readw(addr + 0x10) == TEST_PATTERN)
return 1;
delay_cycx(1);
msleep_interruptible(1 * 1000);
}
return 0;
@ -316,7 +315,7 @@ static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len)
/* 80186 was in hold, go */
writeb(0, addr + START_CPU);
delay_cycx(1);
msleep_interruptible(1 * 1000);
}
/* Load data.bin file through boot (reset) interface. */
@ -462,13 +461,13 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len)
cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
/* reset is waiting for boot */
writew(GEN_POWER_ON, pt_cycld);
delay_cycx(1);
msleep_interruptible(1 * 1000);
for (j = 0 ; j < 3 ; j++)
if (!readw(pt_cycld))
goto reset_loaded;
else
delay_cycx(1);
msleep_interruptible(1 * 1000);
}
printk(KERN_ERR "%s: reset not started.\n", modname);
@ -495,7 +494,7 @@ reset_loaded:
/* Arthur Ganzert's tip: wait a while after the firmware loading...
seg abr 26 17:17:12 EST 1999 - acme */
delay_cycx(7);
msleep_interruptible(7 * 1000);
printk(KERN_INFO "%s: firmware loaded!\n", modname);
/* enable interrupts */
@ -547,20 +546,13 @@ static int get_option_index(long *optlist, long optval)
static int reset_cyc2x(void __iomem *addr)
{
writeb(0, addr + RST_ENABLE);
delay_cycx(2);
msleep_interruptible(2 * 1000);
writeb(0, addr + RST_DISABLE);
delay_cycx(2);
msleep_interruptible(2 * 1000);
return memory_exists(addr);
}
/* Delay */
static void delay_cycx(int sec)
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(sec * HZ);
}
/* Calculate 16-bit CRC using CCITT polynomial. */
static u16 checksum(u8 *buf, u32 len)
{

Просмотреть файл

@ -4322,36 +4322,36 @@ static const struct iw_priv_args orinoco_privtab[] = {
*/
static const iw_handler orinoco_handler[] = {
[SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
[SIOCGIWNAME -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
[SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
[SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
[SIOCSIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
[SIOCGIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
[SIOCSIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
[SIOCGIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
[SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
[SIOCSIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
[SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
[SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
[SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
[SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
[SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
[SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
[SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
[SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
[SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
[SIOCSIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
[SIOCGIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
[SIOCSIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
[SIOCGIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
[SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
[SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
[SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
[SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
[SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
[SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
[SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
[SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_commit,
[SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getname,
[SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfreq,
[SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfreq,
[SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setmode,
[SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getmode,
[SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens,
[SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens,
[SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange,
[SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setspy,
[SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getspy,
[SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap,
[SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap,
[SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan,
[SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getscan,
[SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setessid,
[SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getessid,
[SIOCSIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setnick,
[SIOCGIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getnick,
[SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrate,
[SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrate,
[SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrts,
[SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrts,
[SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfrag,
[SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfrag,
[SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getretry,
[SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setiwencode,
[SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwencode,
[SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setpower,
[SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getpower,
};
@ -4359,15 +4359,15 @@ static const iw_handler orinoco_handler[] = {
Added typecasting since we no longer use iwreq_data -- Moustafa
*/
static const iw_handler orinoco_private_handler[] = {
[0] (iw_handler) orinoco_ioctl_reset,
[1] (iw_handler) orinoco_ioctl_reset,
[2] (iw_handler) orinoco_ioctl_setport3,
[3] (iw_handler) orinoco_ioctl_getport3,
[4] (iw_handler) orinoco_ioctl_setpreamble,
[5] (iw_handler) orinoco_ioctl_getpreamble,
[6] (iw_handler) orinoco_ioctl_setibssport,
[7] (iw_handler) orinoco_ioctl_getibssport,
[9] (iw_handler) orinoco_ioctl_getrid,
[0] = (iw_handler) orinoco_ioctl_reset,
[1] = (iw_handler) orinoco_ioctl_reset,
[2] = (iw_handler) orinoco_ioctl_setport3,
[3] = (iw_handler) orinoco_ioctl_getport3,
[4] = (iw_handler) orinoco_ioctl_setpreamble,
[5] = (iw_handler) orinoco_ioctl_getpreamble,
[6] = (iw_handler) orinoco_ioctl_setibssport,
[7] = (iw_handler) orinoco_ioctl_getibssport,
[9] = (iw_handler) orinoco_ioctl_getrid,
};
static const struct iw_handler_def orinoco_handler_def = {

Просмотреть файл

@ -408,6 +408,8 @@ struct ethtool_ops {
#define SUPPORTED_FIBRE (1 << 10)
#define SUPPORTED_BNC (1 << 11)
#define SUPPORTED_10000baseT_Full (1 << 12)
#define SUPPORTED_Pause (1 << 13)
#define SUPPORTED_Asym_Pause (1 << 14)
/* Indicates what features are advertised by the interface. */
#define ADVERTISED_10baseT_Half (1 << 0)
@ -423,6 +425,8 @@ struct ethtool_ops {
#define ADVERTISED_FIBRE (1 << 10)
#define ADVERTISED_BNC (1 << 11)
#define ADVERTISED_10000baseT_Full (1 << 12)
#define ADVERTISED_Pause (1 << 13)
#define ADVERTISED_Asym_Pause (1 << 14)
/* The following are all involved in forcing a particular link
* mode for the device for setting things. When getting the

Просмотреть файл

@ -22,6 +22,7 @@
#define MII_EXPANSION 0x06 /* Expansion register */
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
#define MII_STAT1000 0x0a /* 1000BASE-T status */
#define MII_ESTATUS 0x0f /* Extended Status */
#define MII_DCOUNTER 0x12 /* Disconnect counter */
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
@ -54,7 +55,10 @@
#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
#define BMSR_RFAULT 0x0010 /* Remote fault detected */
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
#define BMSR_RESV 0x07c0 /* Unused... */
#define BMSR_RESV 0x00c0 /* Unused... */
#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
#define BMSR_100FULL2 0x0200 /* Can do 100BASE-T2 HDX */
#define BMSR_100HALF2 0x0400 /* Can do 100BASE-T2 FDX */
#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
@ -114,6 +118,9 @@
#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
#define EXPANSION_RESV 0xffe0 /* Unused... */
#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
/* N-way test register. */
#define NWAYTEST_RESV1 0x00ff /* Unused... */
#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */

377
include/linux/phy.h Normal file
Просмотреть файл

@ -0,0 +1,377 @@
/*
* include/linux/phy.h
*
* Framework and drivers for configuring and reading different PHYs
* Based on code in sungem_phy.c and gianfar_phy.c
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __PHY_H
#define __PHY_H
#include <linux/spinlock.h>
#include <linux/device.h>
#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | \
SUPPORTED_100baseT_Full | \
SUPPORTED_Autoneg | \
SUPPORTED_TP | \
SUPPORTED_MII)
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
SUPPORTED_1000baseT_Half | \
SUPPORTED_1000baseT_Full)
/* Set phydev->irq to PHY_POLL if interrupts are not supported,
* or not desired for this PHY. Set to PHY_IGNORE_INTERRUPT if
* the attached driver handles the interrupt
*/
#define PHY_POLL -1
#define PHY_IGNORE_INTERRUPT -2
#define PHY_HAS_INTERRUPT 0x00000001
#define PHY_HAS_MAGICANEG 0x00000002
#define MII_BUS_MAX 4
#define PHY_INIT_TIMEOUT 100000
#define PHY_STATE_TIME 1
#define PHY_FORCE_TIMEOUT 10
#define PHY_AN_TIMEOUT 10
#define PHY_MAX_ADDR 32
/* The Bus class for PHYs. Devices which provide access to
* PHYs should register using this structure */
struct mii_bus {
const char *name;
int id;
void *priv;
int (*read)(struct mii_bus *bus, int phy_id, int regnum);
int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val);
int (*reset)(struct mii_bus *bus);
/* A lock to ensure that only one thing can read/write
* the MDIO bus at a time */
spinlock_t mdio_lock;
struct device *dev;
/* list of all PHYs on bus */
struct phy_device *phy_map[PHY_MAX_ADDR];
/* Pointer to an array of interrupts, each PHY's
* interrupt at the index matching its address */
int *irq;
};
#define PHY_INTERRUPT_DISABLED 0x0
#define PHY_INTERRUPT_ENABLED 0x80000000
/* PHY state machine states:
*
* DOWN: PHY device and driver are not ready for anything. probe
* should be called if and only if the PHY is in this state,
* given that the PHY device exists.
* - PHY driver probe function will, depending on the PHY, set
* the state to STARTING or READY
*
* STARTING: PHY device is coming up, and the ethernet driver is
* not ready. PHY drivers may set this in the probe function.
* If they do, they are responsible for making sure the state is
* eventually set to indicate whether the PHY is UP or READY,
* depending on the state when the PHY is done starting up.
* - PHY driver will set the state to READY
* - start will set the state to PENDING
*
* READY: PHY is ready to send and receive packets, but the
* controller is not. By default, PHYs which do not implement
* probe will be set to this state by phy_probe(). If the PHY
* driver knows the PHY is ready, and the PHY state is STARTING,
* then it sets this STATE.
* - start will set the state to UP
*
* PENDING: PHY device is coming up, but the ethernet driver is
* ready. phy_start will set this state if the PHY state is
* STARTING.
* - PHY driver will set the state to UP when the PHY is ready
*
* UP: The PHY and attached device are ready to do work.
* Interrupts should be started here.
* - timer moves to AN
*
* AN: The PHY is currently negotiating the link state. Link is
* therefore down for now. phy_timer will set this state when it
* detects the state is UP. config_aneg will set this state
* whenever called with phydev->autoneg set to AUTONEG_ENABLE.
* - If autonegotiation finishes, but there's no link, it sets
* the state to NOLINK.
* - If aneg finishes with link, it sets the state to RUNNING,
* and calls adjust_link
* - If autonegotiation did not finish after an arbitrary amount
* of time, autonegotiation should be tried again if the PHY
* supports "magic" autonegotiation (back to AN)
* - If it didn't finish, and no magic_aneg, move to FORCING.
*
* NOLINK: PHY is up, but not currently plugged in.
* - If the timer notes that the link comes back, we move to RUNNING
* - config_aneg moves to AN
* - phy_stop moves to HALTED
*
* FORCING: PHY is being configured with forced settings
* - if link is up, move to RUNNING
* - If link is down, we drop to the next highest setting, and
* retry (FORCING) after a timeout
* - phy_stop moves to HALTED
*
* RUNNING: PHY is currently up, running, and possibly sending
* and/or receiving packets
* - timer will set CHANGELINK if we're polling (this ensures the
* link state is polled every other cycle of this state machine,
* which makes it every other second)
* - irq will set CHANGELINK
* - config_aneg will set AN
* - phy_stop moves to HALTED
*
* CHANGELINK: PHY experienced a change in link state
* - timer moves to RUNNING if link
* - timer moves to NOLINK if the link is down
* - phy_stop moves to HALTED
*
* HALTED: PHY is up, but no polling or interrupts are done. Or
* PHY is in an error state.
*
* - phy_start moves to RESUMING
*
* RESUMING: PHY was halted, but now wants to run again.
* - If we are forcing, or aneg is done, timer moves to RUNNING
* - If aneg is not done, timer moves to AN
* - phy_stop moves to HALTED
*/
enum phy_state {
PHY_DOWN=0,
PHY_STARTING,
PHY_READY,
PHY_PENDING,
PHY_UP,
PHY_AN,
PHY_RUNNING,
PHY_NOLINK,
PHY_FORCING,
PHY_CHANGELINK,
PHY_HALTED,
PHY_RESUMING
};
/* phy_device: An instance of a PHY
*
* drv: Pointer to the driver for this PHY instance
* bus: Pointer to the bus this PHY is on
* dev: driver model device structure for this PHY
* phy_id: UID for this device found during discovery
* state: state of the PHY for management purposes
* dev_flags: Device-specific flags used by the PHY driver.
* addr: Bus address of PHY
* link_timeout: The number of timer firings to wait before the
* giving up on the current attempt at acquiring a link
* irq: IRQ number of the PHY's interrupt (-1 if none)
* phy_timer: The timer for handling the state machine
* phy_queue: A work_queue for the interrupt
* attached_dev: The attached enet driver's device instance ptr
* adjust_link: Callback for the enet controller to respond to
* changes in the link state.
* adjust_state: Callback for the enet driver to respond to
* changes in the state machine.
*
* speed, duplex, pause, supported, advertising, and
* autoneg are used like in mii_if_info
*
* interrupts currently only supports enabled or disabled,
* but could be changed in the future to support enabling
* and disabling specific interrupts
*
* Contains some infrastructure for polling and interrupt
* handling, as well as handling shifts in PHY hardware state
*/
struct phy_device {
/* Information about the PHY type */
/* And management functions */
struct phy_driver *drv;
struct mii_bus *bus;
struct device dev;
u32 phy_id;
enum phy_state state;
u32 dev_flags;
/* Bus address of the PHY (0-32) */
int addr;
/* forced speed & duplex (no autoneg)
* partner speed & duplex & pause (autoneg)
*/
int speed;
int duplex;
int pause;
int asym_pause;
/* The most recently read link state */
int link;
/* Enabled Interrupts */
u32 interrupts;
/* Union of PHY and Attached devices' supported modes */
/* See mii.h for more info */
u32 supported;
u32 advertising;
int autoneg;
int link_timeout;
/* Interrupt number for this PHY
* -1 means no interrupt */
int irq;
/* private data pointer */
/* For use by PHYs to maintain extra state */
void *priv;
/* Interrupt and Polling infrastructure */
struct work_struct phy_queue;
struct timer_list phy_timer;
spinlock_t lock;
struct net_device *attached_dev;
void (*adjust_link)(struct net_device *dev);
void (*adjust_state)(struct net_device *dev);
};
#define to_phy_device(d) container_of(d, struct phy_device, dev)
/* struct phy_driver: Driver structure for a particular PHY type
*
* phy_id: The result of reading the UID registers of this PHY
* type, and ANDing them with the phy_id_mask. This driver
* only works for PHYs with IDs which match this field
* name: The friendly name of this PHY type
* phy_id_mask: Defines the important bits of the phy_id
* features: A list of features (speed, duplex, etc) supported
* by this PHY
* flags: A bitfield defining certain other features this PHY
* supports (like interrupts)
*
* The drivers must implement config_aneg and read_status. All
* other functions are optional. Note that none of these
* functions should be called from interrupt time. The goal is
* for the bus read/write functions to be able to block when the
* bus transaction is happening, and be freed up by an interrupt
* (The MPC85xx has this ability, though it is not currently
* supported in the driver).
*/
struct phy_driver {
u32 phy_id;
char *name;
unsigned int phy_id_mask;
u32 features;
u32 flags;
/* Called to initialize the PHY,
* including after a reset */
int (*config_init)(struct phy_device *phydev);
/* Called during discovery. Used to set
* up device-specific structures, if any */
int (*probe)(struct phy_device *phydev);
/* PHY Power Management */
int (*suspend)(struct phy_device *phydev);
int (*resume)(struct phy_device *phydev);
/* Configures the advertisement and resets
* autonegotiation if phydev->autoneg is on,
* forces the speed to the current settings in phydev
* if phydev->autoneg is off */
int (*config_aneg)(struct phy_device *phydev);
/* Determines the negotiated speed and duplex */
int (*read_status)(struct phy_device *phydev);
/* Clears any pending interrupts */
int (*ack_interrupt)(struct phy_device *phydev);
/* Enables or disables interrupts */
int (*config_intr)(struct phy_device *phydev);
/* Clears up any memory if needed */
void (*remove)(struct phy_device *phydev);
struct device_driver driver;
};
#define to_phy_driver(d) container_of(d, struct phy_driver, driver)
int phy_read(struct phy_device *phydev, u16 regnum);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
int phy_clear_interrupt(struct phy_device *phydev);
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
struct phy_device * phy_attach(struct net_device *dev,
const char *phy_id, u32 flags);
struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
void (*handler)(struct net_device *), u32 flags);
void phy_disconnect(struct phy_device *phydev);
void phy_detach(struct phy_device *phydev);
void phy_start(struct phy_device *phydev);
void phy_stop(struct phy_device *phydev);
int phy_start_aneg(struct phy_device *phydev);
int mdiobus_register(struct mii_bus *bus);
void mdiobus_unregister(struct mii_bus *bus);
void phy_sanitize_settings(struct phy_device *phydev);
int phy_stop_interrupts(struct phy_device *phydev);
static inline int phy_read_status(struct phy_device *phydev) {
return phydev->drv->read_status(phydev);
}
int genphy_config_advert(struct phy_device *phydev);
int genphy_setup_forced(struct phy_device *phydev);
int genphy_restart_aneg(struct phy_device *phydev);
int genphy_config_aneg(struct phy_device *phydev);
int genphy_update_link(struct phy_device *phydev);
int genphy_read_status(struct phy_device *phydev);
void phy_driver_unregister(struct phy_driver *drv);
int phy_driver_register(struct phy_driver *new_driver);
void phy_prepare_link(struct phy_device *phydev,
void (*adjust_link)(struct net_device *));
void phy_start_machine(struct phy_device *phydev,
void (*handler)(struct net_device *));
void phy_stop_machine(struct phy_device *phydev);
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd);
int phy_start_interrupts(struct phy_device *phydev);
void phy_print_status(struct phy_device *phydev);
extern struct bus_type mdio_bus_type;
#endif /* __PHY_H */