void t3_update_master_devs(struct toedev *tdev) { int i; for (i = 0; i < tdev->nlldev; i++) { struct net_device *dev = tdev->lldev[i]; if (dev->flags & IFF_SLAVE) { struct net_device *bond_dev = dev->master; struct bonding *bond = (struct bonding *)netdev_priv(bond_dev); struct toedev *slave_tdev = NULL; struct slave *slave; int i, ofld_cnt = 0; if (netdev_is_offload(bond_dev)) continue; read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { ofld_cnt += !!netdev_is_offload(slave->dev); if (!slave_tdev) slave_tdev = TOEDEV(slave->dev); else if (slave_tdev != TOEDEV(slave->dev)) { slave_tdev = NULL; break; } } read_unlock_bh(&bond->lock); if (ofld_cnt == bond->slave_cnt && slave_tdev) netdev_set_offload(bond_dev); } }
/* * Provide an opportunity for a TOE driver to offload. */ int tcp_offload_connect(struct socket *so, struct sockaddr *nam) { struct ifnet *ifp; struct toedev *tod; struct rtentry *rt; int error = EOPNOTSUPP; INP_WLOCK_ASSERT(sotoinpcb(so)); KASSERT(nam->sa_family == AF_INET || nam->sa_family == AF_INET6, ("%s: called with sa_family %d", __func__, nam->sa_family)); if (registered_toedevs == 0) return (error); rt = rtalloc1(nam, 0, 0); if (rt) RT_UNLOCK(rt); else return (EHOSTUNREACH); ifp = rt->rt_ifp; if (nam->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4)) goto done; if (nam->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6)) goto done; tod = TOEDEV(ifp); if (tod != NULL) error = tod->tod_connect(tod, so, rt, nam); done: RTFREE(rt); return (error); }
static inline int lookup_port(struct net_device *slave_dev) { int i, port = -1; struct toedev *tdev = TOEDEV(slave_dev); struct adap_ports *port_info = TOM_DATA(tdev)->ports; for (i = 0; i < port_info->nports; i++) { if (slave_dev != port_info->lldevs[i]) continue; port = i; break; } return port; }
int tcp_offload_connect(struct socket *so, struct sockaddr *nam) { struct ifnet *ifp; struct toedev *tdev; struct rtentry *rt; int error; if (toedev_registration_count == 0) return (EINVAL); /* * Look up the route used for the connection to * determine if it uses an interface capable of * offloading the connection. */ rt = rtalloc1(nam, 0 /*report*/, 0 /*ignflags*/); if (rt) RT_UNLOCK(rt); else return (EHOSTUNREACH); ifp = rt->rt_ifp; if ((ifp->if_capenable & IFCAP_TOE) == 0) { error = EINVAL; goto fail; } tdev = TOEDEV(ifp); if (tdev == NULL) { error = EPERM; goto fail; } if (tdev->tod_can_offload(tdev, so) == 0) { error = EPERM; goto fail; } return (tdev->tod_connect(tdev, so, rt, nam)); fail: RTFREE(rt); return (error); }
/* * Ground control to Major TOM * Commencing countdown, engines on */ static int t3_tom_activate(struct adapter *sc) { struct tom_data *td; struct toedev *tod; int i, rc = 0; struct mc5_params *mc5 = &sc->params.mc5; u_int ntids, natids, mtus; ADAPTER_LOCK_ASSERT_OWNED(sc); /* for sc->flags */ /* per-adapter softc for TOM */ td = malloc(sizeof(*td), M_CXGB, M_ZERO | M_NOWAIT); if (td == NULL) return (ENOMEM); /* List of TOE PCBs and associated lock */ mtx_init(&td->toep_list_lock, "PCB list lock", NULL, MTX_DEF); TAILQ_INIT(&td->toep_list); /* Listen context */ mtx_init(&td->lctx_hash_lock, "lctx hash lock", NULL, MTX_DEF); td->listen_hash = hashinit_flags(LISTEN_HASH_SIZE, M_CXGB, &td->listen_mask, HASH_NOWAIT); /* TID release task */ TASK_INIT(&td->tid_release_task, 0 , t3_process_tid_release_list, td); mtx_init(&td->tid_release_lock, "tid release", NULL, MTX_DEF); /* L2 table */ td->l2t = t3_init_l2t(L2T_SIZE); if (td->l2t == NULL) { rc = ENOMEM; goto done; } /* TID tables */ ntids = t3_mc5_size(&sc->mc5) - mc5->nroutes - mc5->nfilters - mc5->nservers; natids = min(ntids / 2, 64 * 1024); rc = alloc_tid_tabs(&td->tid_maps, ntids, natids, mc5->nservers, 0x100000 /* ATID_BASE */, ntids); if (rc != 0) goto done; /* CPL handlers */ t3_init_listen_cpl_handlers(sc); t3_init_l2t_cpl_handlers(sc); t3_init_cpl_io(sc); /* toedev ops */ tod = &td->tod; init_toedev(tod); tod->tod_softc = sc; tod->tod_connect = t3_connect; tod->tod_listen_start = t3_listen_start; tod->tod_listen_stop = t3_listen_stop; tod->tod_rcvd = t3_rcvd; tod->tod_output = t3_tod_output; tod->tod_send_rst = t3_send_rst; tod->tod_send_fin = t3_send_fin; tod->tod_pcb_detach = t3_pcb_detach; tod->tod_l2_update = t3_l2_update; tod->tod_syncache_added = t3_syncache_added; tod->tod_syncache_removed = t3_syncache_removed; tod->tod_syncache_respond = t3_syncache_respond; tod->tod_offload_socket = t3_offload_socket; /* port MTUs */ mtus = sc->port[0].ifp->if_mtu; if (sc->params.nports > 1) mtus |= sc->port[1].ifp->if_mtu << 16; t3_write_reg(sc, A_TP_MTU_PORT_TABLE, mtus); t3_load_mtus(sc, sc->params.mtus, sc->params.a_wnd, sc->params.b_wnd, sc->params.rev == 0 ? sc->port[0].ifp->if_mtu : 0xffff); /* SMT entry for each port */ for_each_port(sc, i) { write_smt_entry(sc, i); TOEDEV(sc->port[i].ifp) = &td->tod; }
/* * Allocate a TOM data structure, * initialize its cpl_handlers * and register it as a T3C client */ static void t3c_tom_add(struct t3cdev *cdev) { int i; unsigned int wr_len; struct tom_data *t; struct toedev *tdev; struct adap_ports *port_info; t = malloc(sizeof(*t), M_CXGB, M_NOWAIT|M_ZERO); if (t == NULL) return; cdev->send = t3_offload_tx; cdev->ctl = cxgb_offload_ctl; if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0) goto out_free_tom; port_info = malloc(sizeof(*port_info), M_CXGB, M_NOWAIT|M_ZERO); if (!port_info) goto out_free_tom; if (cdev->ctl(cdev, GET_PORTS, port_info) < 0) goto out_free_all; t3_init_wr_tab(wr_len); t->cdev = cdev; t->client = &t3c_tom_client; /* Register TCP offload device */ tdev = &t->tdev; tdev->tod_ttid = cdev2type(cdev); tdev->tod_lldev = cdev->lldev; if (register_toedev(tdev, "toe%d")) { printf("unable to register offload device"); goto out_free_all; } TOM_DATA(tdev) = t; for (i = 0; i < port_info->nports; i++) { struct ifnet *ifp = port_info->lldevs[i]; TOEDEV(ifp) = tdev; CTR1(KTR_TOM, "enabling toe on %p", ifp); ifp->if_capabilities |= IFCAP_TOE4; ifp->if_capenable |= IFCAP_TOE4; } t->ports = port_info; /* Add device to the list of offload devices */ t3cdev_add(t); /* Activate TCP offload device */ cxgb_offload_activate(TOM_DATA(tdev)->cdev->adapter); activate_offload(tdev); cxgb_register_listeners(); return; out_free_all: printf("out_free_all fail\n"); free(port_info, M_CXGB); out_free_tom: printf("out_free_tom fail\n"); free(t, M_CXGB); return; }