summaryrefslogtreecommitdiff
path: root/sys/dev/cxgb/cxgb_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/cxgb/cxgb_main.c')
-rw-r--r--sys/dev/cxgb/cxgb_main.c202
1 files changed, 177 insertions, 25 deletions
diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c
index 90df81777d1f8..593a8d6c33edb 100644
--- a/sys/dev/cxgb/cxgb_main.c
+++ b/sys/dev/cxgb/cxgb_main.c
@@ -1,6 +1,6 @@
/**************************************************************************
-Copyright (c) 2007-2008, Chelsio Inc.
+Copyright (c) 2007-2009, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,7 @@ static int offload_open(struct port_info *pi);
static void touch_bars(device_t dev);
static int offload_close(struct t3cdev *tdev);
static void cxgb_link_start(struct port_info *p);
+static void cxgb_link_fault(void *arg, int ncount);
static device_method_t cxgb_controller_methods[] = {
DEVMETHOD(device_probe, cxgb_controller_probe),
@@ -364,8 +365,8 @@ cxgb_controller_probe(device_t dev)
}
#define FW_FNAME "cxgb_t3fw"
-#define TPEEPROM_NAME "t3b_tp_eeprom"
-#define TPSRAM_NAME "t3b_protocol_sram"
+#define TPEEPROM_NAME "t3%c_tp_eeprom"
+#define TPSRAM_NAME "t3%c_protocol_sram"
static int
upgrade_fw(adapter_t *sc)
@@ -403,7 +404,6 @@ cxgb_controller_attach(device_t dev)
#ifdef MSI_SUPPORTED
int msi_needed, reg;
#endif
- int must_load = 0;
char buf[80];
sc = device_get_softc(dev);
@@ -553,7 +553,7 @@ cxgb_controller_attach(device_t dev)
/* Create a periodic callout for checking adapter status */
callout_init(&sc->cxgb_tick_ch, TRUE);
- if ((t3_check_fw_version(sc, &must_load) != 0 && must_load) || force_fw_update) {
+ if (t3_check_fw_version(sc) < 0 || force_fw_update) {
/*
* Warn user that a firmware update will be attempted in init.
*/
@@ -564,7 +564,7 @@ cxgb_controller_attach(device_t dev)
sc->flags |= FW_UPTODATE;
}
- if (t3_check_tpsram_version(sc, &must_load) != 0 && must_load) {
+ if (t3_check_tpsram_version(sc) < 0) {
/*
* Warn user that a firmware update will be attempted in init.
*/
@@ -1019,6 +1019,9 @@ cxgb_port_attach(device_t dev)
/* Get the latest mac address, User can use a LAA */
bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN);
t3_sge_init_port(p);
+
+ TASK_INIT(&p->link_fault_task, 0, cxgb_link_fault, p);
+
#if defined(LINK_ATTACH)
cxgb_link_start(p);
t3_link_changed(sc, p->port_id);
@@ -1139,6 +1142,32 @@ t3_os_pci_restore_state(struct adapter *sc)
return (0);
}
+void t3_os_link_fault(struct adapter *adap, int port_id, int state)
+{
+ struct port_info *pi = &adap->port[port_id];
+
+ if (!state) {
+ if_link_state_change(pi->ifp, LINK_STATE_DOWN);
+ return;
+ }
+
+ if (adap->params.nports <= 2) {
+ struct cmac *mac = &pi->mac;
+
+ /* Clear local faults */
+ t3_xgm_intr_disable(adap, port_id);
+ t3_read_reg(adap, A_XGM_INT_STATUS + pi->mac.offset);
+ t3_write_reg(adap, A_XGM_INT_CAUSE + pi->mac.offset, F_XGM_INT);
+
+ t3_set_reg_field(adap, A_XGM_INT_ENABLE + pi->mac.offset,
+ F_XGM_INT, F_XGM_INT);
+ t3_xgm_intr_enable(adap, pi->port_id);
+ t3_mac_enable(mac, MAC_DIRECTION_TX);
+ }
+
+ if_link_state_change(pi->ifp, LINK_STATE_UP);
+}
+
/**
* t3_os_link_changed - handle link status changes
* @adapter: the adapter associated with the link change
@@ -1162,17 +1191,41 @@ t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
if (link_status) {
DELAY(10);
t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
- /* Clear errors created by MAC enable */
+ /* Clear errors created by MAC enable */
+ t3_set_reg_field(adapter, A_XGM_STAT_CTRL + pi->mac.offset,
+ F_CLRSTATS, 1);
+
+ if (adapter->params.nports <= 2) {
+ /* Clear local faults */
+ t3_xgm_intr_disable(adapter, pi->port_id);
+ t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
+ t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset,
+ F_XGM_INT);
+
t3_set_reg_field(adapter,
- A_XGM_STAT_CTRL + pi->mac.offset,
- F_CLRSTATS, 1);
- if_link_state_change(pi->ifp, LINK_STATE_UP);
+ A_XGM_INT_ENABLE + pi->mac.offset,
+ F_XGM_INT, F_XGM_INT);
+ t3_xgm_intr_enable(adapter, pi->port_id);
+ }
+ if_link_state_change(pi->ifp, LINK_STATE_UP);
} else {
- pi->phy.ops->power_down(&pi->phy, 1);
+ t3_xgm_intr_disable(adapter, pi->port_id);
+ t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
+ if (adapter->params.nports <= 2) {
+ t3_set_reg_field(adapter,
+ A_XGM_INT_ENABLE + pi->mac.offset,
+ F_XGM_INT, 0);
+ }
+
+ /* PR 5666. We shouldn't power down 1G phys */
+ if (is_10G(adapter))
+ pi->phy.ops->power_down(&pi->phy, 1);
+
+ t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
t3_mac_disable(mac, MAC_DIRECTION_RX);
t3_link_start(&pi->phy, mac, &pi->link_config);
- t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+
if_link_state_change(pi->ifp, LINK_STATE_DOWN);
}
}
@@ -1227,6 +1280,24 @@ t3_os_ext_intr_handler(adapter_t *sc)
ADAPTER_UNLOCK(sc);
}
+static void
+cxgb_link_fault(void *arg, int ncount)
+{
+ struct port_info *pi = arg;
+
+ t3_link_fault(pi->adapter, pi->port_id);
+}
+
+void t3_os_link_fault_handler(struct adapter *sc, int port_id)
+{
+ struct port_info *pi = &sc->port[port_id];
+
+ ADAPTER_LOCK(sc);
+ pi->link_fault = 1;
+ taskqueue_enqueue(sc->tq, &pi->link_fault_task);
+ ADAPTER_UNLOCK(sc);
+}
+
void
t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
{
@@ -1510,7 +1581,7 @@ update_tpeeprom(struct adapter *adap)
uint32_t version;
unsigned int major, minor;
int ret, len;
- char rev;
+ char rev, name[32];
t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
@@ -1520,8 +1591,9 @@ update_tpeeprom(struct adapter *adap)
return;
rev = t3rev2char(adap);
+ snprintf(name, sizeof(name), TPEEPROM_NAME, rev);
- tpeeprom = firmware_get(TPEEPROM_NAME);
+ tpeeprom = firmware_get(name);
if (tpeeprom == NULL) {
device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n",
TPEEPROM_NAME);
@@ -1564,15 +1636,14 @@ update_tpsram(struct adapter *adap)
struct firmware *tpsram;
#endif
int ret;
- char rev;
+ char rev, name[32];
rev = t3rev2char(adap);
- if (!rev)
- return 0;
+ snprintf(name, sizeof(name), TPSRAM_NAME, rev);
update_tpeeprom(adap);
- tpsram = firmware_get(TPSRAM_NAME);
+ tpsram = firmware_get(name);
if (tpsram == NULL){
device_printf(adap->dev, "could not load TP SRAM\n");
return (EINVAL);
@@ -1600,7 +1671,6 @@ release_tpsram:
* Called when the first port is enabled, this function performs the
* actions necessary to make an adapter operational, such as completing
* the initialization of HW modules, and enabling interrupts.
- *
*/
static int
cxgb_up(struct adapter *sc)
@@ -1692,7 +1762,7 @@ cxgb_down_locked(struct adapter *sc)
t3_sge_stop(sc);
t3_intr_disable(sc);
-
+
if (sc->intr_tag != NULL) {
bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
sc->intr_tag = NULL;
@@ -2274,6 +2344,7 @@ cxgb_tick_handler(void *arg, int count)
adapter_t *sc = (adapter_t *)arg;
const struct adapter_params *p = &sc->params;
int i;
+ uint32_t cause, reset;
if(sc->flags & CXGB_SHUTDOWN)
return;
@@ -2282,7 +2353,6 @@ cxgb_tick_handler(void *arg, int count)
if (p->linkpoll_period)
check_link_status(sc);
-
sc->check_task_cnt++;
/*
@@ -2294,15 +2364,38 @@ cxgb_tick_handler(void *arg, int count)
if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
check_t3b2_mac(sc);
+ cause = t3_read_reg(sc, A_SG_INT_CAUSE);
+ reset = 0;
+ if (cause & F_FLEMPTY) {
+ struct sge_qset *qs = &sc->sge.qs[0];
+
+ i = 0;
+ reset |= F_FLEMPTY;
+
+ cause = (t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) >>
+ S_FL0EMPTY) & 0xffff;
+ while (cause) {
+ qs->fl[i].empty += (cause & 1);
+ if (i)
+ qs++;
+ i ^= 1;
+ cause >>= 1;
+ }
+ }
+ t3_write_reg(sc, A_SG_INT_CAUSE, reset);
+
for (i = 0; i < sc->params.nports; i++) {
struct port_info *pi = &sc->port[i];
struct ifnet *ifp = pi->ifp;
- struct mac_stats *mstats = &pi->mac.stats;
+ struct cmac *mac = &pi->mac;
+ struct mac_stats *mstats = &mac->stats;
PORT_LOCK(pi);
- t3_mac_update_stats(&pi->mac);
+ t3_mac_update_stats(mac);
PORT_UNLOCK(pi);
-
+ if (pi->link_fault)
+ taskqueue_enqueue(sc->tq, &pi->link_fault_task);
+
ifp->if_opackets =
mstats->tx_frames_64 +
mstats->tx_frames_65_127 +
@@ -2347,6 +2440,18 @@ cxgb_tick_handler(void *arg, int count)
mstats->rx_mac_internal_errs +
mstats->rx_short +
mstats->rx_fcs_errs;
+
+ if (mac->multiport)
+ continue;
+
+ /* Count rx fifo overflows, once per second */
+ cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset);
+ reset = 0;
+ if (cause & F_RXFIFO_OVERFLOW) {
+ mac->stats.rx_fifo_ovfl++;
+ reset |= F_RXFIFO_OVERFLOW;
+ }
+ t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset);
}
}
@@ -2818,7 +2923,7 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
if (regs->len > reglen)
regs->len = reglen;
else if (regs->len < reglen)
- error = E2BIG;
+ error = ENOBUFS;
if (!error) {
cxgb_get_regs(sc, regs, buf);
@@ -2892,6 +2997,53 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
PORT_UNLOCK(pi);
break;
}
+ case CHELSIO_GET_UP_LA: {
+ struct ch_up_la *la = (struct ch_up_la *)data;
+ uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT);
+ if (buf == NULL) {
+ return (ENOMEM);
+ }
+ if (la->bufsize < LA_BUFSIZE)
+ error = ENOBUFS;
+
+ if (!error)
+ error = -t3_get_up_la(sc, &la->stopped, &la->idx,
+ &la->bufsize, buf);
+ if (!error)
+ error = copyout(buf, la->data, la->bufsize);
+
+ free(buf, M_DEVBUF);
+ break;
+ }
+ case CHELSIO_GET_UP_IOQS: {
+ struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data;
+ uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT);
+ uint32_t *v;
+
+ if (buf == NULL) {
+ return (ENOMEM);
+ }
+ if (ioqs->bufsize < IOQS_BUFSIZE)
+ error = ENOBUFS;
+
+ if (!error)
+ error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf);
+
+ if (!error) {
+ v = (uint32_t *)buf;
+
+ ioqs->bufsize -= 4 * sizeof(uint32_t);
+ ioqs->ioq_rx_enable = *v++;
+ ioqs->ioq_tx_enable = *v++;
+ ioqs->ioq_rx_status = *v++;
+ ioqs->ioq_tx_status = *v++;
+
+ error = copyout(v, ioqs->data, ioqs->bufsize);
+ }
+
+ free(buf, M_DEVBUF);
+ break;
+ }
default:
return (EOPNOTSUPP);
break;