Commit 3fbc24f1 authored by Raghavendra Koushik's avatar Raghavendra Koushik Committed by Jeff Garzik

[PATCH] S2io: hardware fixes

1. Xena3's with a set of subsystem IDs had Link LED problems, fixed
that specifically for them.

2. To write into the Keyed Mac_Cfg register to enable broadcast,
writing two 32 bit writes into it along with a write to the key
register rather than a single write to key and a 64 bit write to
mac_cfg. This is necessary on 32 bit systems where a writeq(64 bit
write) is actually two writel (32 bit writes).

3. Writes to some special registers mentioned in UG is being done by
a special macro which defines which 32 bits of the 64 bit register
is to be written first. Again this applies only on 32 bit systems.

4. Configured pause frame related water marks and a shared_split
value which describes the Max TXDMA related split transaction that
can be used without giving room for the Rx transactions.

5. The mac_rmac_err_reg R1 register will be cleared in  the interrupt
handler itself rather than in the scheduled task as was being done
previously.

6. Even on PCC_FB_ECC error the card will be reset by disabling
adapter enable bit.
Signed-off-by: default avatarRaghavendra Koushik <raghavendra.koushik@s2io.com>
Signed-off-by: default avatarRavinandan Arakali <ravinandan.arakali@s2io.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent b3ea38cb
......@@ -71,6 +71,15 @@
static char s2io_driver_name[] = "s2io";
static char s2io_driver_version[] = "Version 1.7.5.1";
/*
* Cards with following subsystem_id have a link state indication
* problem, 600B, 600C, 600D, 640B, 640C and 640D.
* macro below identifies these cards given the subsystem_id.
*/
#define CARDS_WITH_FAULTY_LINK_INDICATORS(subid) \
(((subid >= 0x600B) && (subid <= 0x600D)) || \
((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0
#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
#define TASKLET_IN_USE test_and_set_bit(0, \
......@@ -563,10 +572,13 @@ static int init_nic(struct s2io_nic *nic)
schedule_timeout(HZ / 2);
/* Enable Receiving broadcasts */
add = (void *) &bar0->mac_cfg;
val64 = readq(&bar0->mac_cfg);
val64 |= MAC_RMAC_BCAST_ENABLE;
writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
writeq(val64, &bar0->mac_cfg);
writel((u32) val64, add);
writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
writel((u32) (val64 >> 32), (add + 4));
/* Read registers in all blocks */
val64 = readq(&bar0->mac_int_mask);
......@@ -598,8 +610,8 @@ static int init_nic(struct s2io_nic *nic)
dtx_cnt++;
goto mdio_cfg;
}
writeq(default_dtx_cfg[dtx_cnt],
&bar0->dtx_control);
SPECIAL_REG_WRITE(default_dtx_cfg[dtx_cnt],
&bar0->dtx_control, UF);
val64 = readq(&bar0->dtx_control);
dtx_cnt++;
}
......@@ -609,8 +621,8 @@ static int init_nic(struct s2io_nic *nic)
mdio_cnt++;
goto dtx_cfg;
}
writeq(default_mdio_cfg[mdio_cnt],
&bar0->mdio_control);
SPECIAL_REG_WRITE(default_mdio_cfg[mdio_cnt],
&bar0->mdio_control, UF);
val64 = readq(&bar0->mdio_control);
mdio_cnt++;
}
......@@ -873,6 +885,47 @@ static int init_nic(struct s2io_nic *nic)
writel((u32) (val64 >> 32), (add + 4));
val64 = readq(&bar0->mac_cfg);
/*
* Set the time value to be inserted in the pause frame
* generated by xena.
*/
val64 = readq(&bar0->rmac_pause_cfg);
val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
writeq(val64, &bar0->rmac_pause_cfg);
/*
* Set the Threshold Limit for Generating the pause frame
* If the amount of data in any Queue exceeds ratio of
* (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
* pause frame is generated
*/
val64 = 0;
for (i = 0; i < 4; i++) {
val64 |=
(((u64) 0xFF00 | nic->mac_control.
mc_pause_threshold_q0q3)
<< (i * 2 * 8));
}
writeq(val64, &bar0->mc_pause_thresh_q0q3);
val64 = 0;
for (i = 0; i < 4; i++) {
val64 |=
(((u64) 0xFF00 | nic->mac_control.
mc_pause_threshold_q4q7)
<< (i * 2 * 8));
}
writeq(val64, &bar0->mc_pause_thresh_q4q7);
/*
* TxDMA will stop Read request if the number of read split has
* exceeded the limit pointed by shared_splits
*/
val64 = readq(&bar0->pic_control);
val64 |= PIC_CNTL_SHARED_SPLITS(0);
writeq(val64, &bar0->pic_control);
return SUCCESS;
}
......@@ -1227,7 +1280,7 @@ static int start_nic(struct s2io_nic *nic)
*/
val64 = readq(&bar0->mc_rldram_mrs);
val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
writeq(val64, &bar0->mc_rldram_mrs);
SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
val64 = readq(&bar0->mc_rldram_mrs);
set_current_state(TASK_UNINTERRUPTIBLE);
......@@ -1291,13 +1344,13 @@ static int start_nic(struct s2io_nic *nic)
* force link down. Since link is already up, we will get
* link state change interrupt after this reset
*/
writeq(0x80010515001E0000ULL, &bar0->dtx_control);
SPECIAL_REG_WRITE(0x80010515001E0000ULL, &bar0->dtx_control, UF);
val64 = readq(&bar0->dtx_control);
udelay(50);
writeq(0x80010515001E00E0ULL, &bar0->dtx_control);
SPECIAL_REG_WRITE(0x80010515001E00E0ULL, &bar0->dtx_control, UF);
val64 = readq(&bar0->dtx_control);
udelay(50);
writeq(0x80070515001F00E4ULL, &bar0->dtx_control);
SPECIAL_REG_WRITE(0x80070515001F00E4ULL, &bar0->dtx_control, UF);
val64 = readq(&bar0->dtx_control);
udelay(50);
......@@ -1884,6 +1937,7 @@ static void alarm_intr_handler(struct s2io_nic *nic)
/* Handling link status change error Intr */
err_reg = readq(&bar0->mac_rmac_err_reg);
writeq(err_reg, &bar0->mac_rmac_err_reg);
if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
schedule_work(&nic->set_link_task);
}
......@@ -1896,6 +1950,22 @@ static void alarm_intr_handler(struct s2io_nic *nic)
schedule_work(&nic->rst_timer_task);
}
/*
* Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
* Error occurs, the adapter will be recycled by disabling the
* adapter enable bit and enabling it again after the device
* becomes Quiescent.
*/
val64 = readq(&bar0->pcc_err_reg);
writeq(val64, &bar0->pcc_err_reg);
if (val64 & PCC_FB_ECC_DB_ERR) {
u64 ac = readq(&bar0->adapter_control);
ac &= ~(ADAPTER_CNTL_EN);
writeq(ac, &bar0->adapter_control);
ac = readq(&bar0->adapter_control);
schedule_work(&nic->set_link_task);
}
/* Other type of interrupts are not being handled now, TODO */
}
......@@ -2870,12 +2940,13 @@ static void s2io_phy_id(unsigned long data)
static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
{
u64 val64 = 0;
u64 val64 = 0, last_gpio_ctrl_val;
nic_t *sp = dev->priv;
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0;
u16 subid;
subid = sp->pdev->subsystem_device;
last_gpio_ctrl_val = readq(&bar0->gpio_control);
if ((subid & 0xFF) < 0x07) {
val64 = readq(&bar0->adapter_control);
if (!(val64 & ADAPTER_CNTL_EN)) {
......@@ -2897,6 +2968,11 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
schedule_timeout(MAX_SCHEDULE_TIMEOUT);
del_timer_sync(&sp->id_timer);
if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
writeq(last_gpio_ctrl_val, &bar0->gpio_control);
last_gpio_ctrl_val = readq(&bar0->gpio_control);
}
return 0;
}
......@@ -2983,7 +3059,7 @@ static int read_eeprom(nic_t * sp, int off, u32 * data)
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
I2C_CONTROL_CNTL_START;
writeq(val64, &bar0->i2c_control);
SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
while (exit_cnt < 5) {
val64 = readq(&bar0->i2c_control);
......@@ -3024,7 +3100,7 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt)
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA(data) |
I2C_CONTROL_CNTL_START;
writeq(val64, &bar0->i2c_control);
SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
while (exit_cnt < 5) {
val64 = readq(&bar0->i2c_control);
......@@ -3352,10 +3428,10 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data)
val64 = readq(&bar0->mc_rldram_mrs);
val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
writeq(val64, &bar0->mc_rldram_mrs);
SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
val64 |= MC_RLDRAM_MRS_ENABLE;
writeq(val64, &bar0->mc_rldram_mrs);
SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
while (iteration < 2) {
val64 = 0x55555555aaaa0000ULL;
......@@ -3757,8 +3833,10 @@ static void s2io_set_link(unsigned long data)
nic_t *nic = (nic_t *) data;
struct net_device *dev = nic->dev;
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
register u64 val64, err_reg;
register u64 val64;
u16 subid;
subid = nic->pdev->subsystem_device;
/*
* Allow a small delay for the NICs self initiated
* cleanup to complete.
......@@ -3768,16 +3846,19 @@ static void s2io_set_link(unsigned long data)
val64 = readq(&bar0->adapter_status);
if (verify_xena_quiescence(val64, nic->device_enabled_once)) {
/* Acknowledge Intr and clear R1 register. */
err_reg = readq(&bar0->mac_rmac_err_reg);
writeq(err_reg, &bar0->mac_rmac_err_reg);
if (LINK_IS_UP(val64)) {
val64 = readq(&bar0->adapter_control);
val64 |= ADAPTER_CNTL_EN;
writeq(val64, &bar0->adapter_control);
val64 |= ADAPTER_LED_ON;
writeq(val64, &bar0->adapter_control);
if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
val64 = readq(&bar0->gpio_control);
val64 |= GPIO_CTRL_GPIO_0;
writeq(val64, &bar0->gpio_control);
val64 = readq(&bar0->gpio_control);
} else {
val64 |= ADAPTER_LED_ON;
writeq(val64, &bar0->adapter_control);
}
val64 = readq(&bar0->adapter_status);
if (!LINK_IS_UP(val64)) {
DBG_PRINT(ERR_DBG, "%s:", dev->name);
......@@ -3791,6 +3872,12 @@ static void s2io_set_link(unsigned long data)
}
s2io_link(nic, LINK_UP);
} else {
if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
val64 = readq(&bar0->gpio_control);
val64 &= ~GPIO_CTRL_GPIO_0;
writeq(val64, &bar0->gpio_control);
val64 = readq(&bar0->gpio_control);
}
s2io_link(nic, LINK_DOWN);
}
} else { /* NIC is not Quiescent. */
......@@ -3917,6 +4004,7 @@ static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no)
return SUCCESS;
}
/**
* s2io_link - stops/starts the Tx queue.
* @sp : private member of the device structure, which is a pointer to the
......
......@@ -693,6 +693,27 @@ static inline void writeq(u64 val, void *addr)
writel((u32) (val), addr);
writel((u32) (val >> 32), (addr + 4));
}
/* 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
* be used to specify the required write order.
*/
#define UF 1
#define LF 2
static inline void SPECIAL_REG_WRITE(u64 val, void *addr, int order)
{
if (order == LF) {
writel((u32) (val), addr);
writel((u32) (val >> 32), (addr + 4));
} else {
writel((u32) (val >> 32), (addr + 4));
writel((u32) (val), addr);
}
}
#else
#define SPECIAL_REG_WRITE(val, addr, dummy) writeq(val, addr)
#endif
/* Interrupt related values of Xena */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment