diff options
author | Vipul Pandya <vipul@chelsio.com> | 2012-12-10 04:30:53 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2012-12-19 12:28:19 -0500 |
commit | dca4faeb812f665dab0607d8e0660ae564387186 (patch) | |
tree | 5fd3def8d745eb588f7dc2f65833bc711371ea6f /drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |
parent | f2b7e78dbc79e09fc1164b226adc03ed91a326cb (diff) |
cxgb4: Add LE hash collision bug fix path in LLD driver
It supports establishing passive open connection through firmware filter work
request. Passive open connection will go through this path as now instead of
listening server we create a server filter which will redirect the incoming SYN
packet to the offload queue.
It divides filter region into regular filters and server filter portion. It
introduces new server filter region which will be exclusively used for creating
server filters. This region will not overlap with regular filter region.
It provides new API cxgb4_alloc_sftid in LLD for getting stid in case of LE
hash collision path. This new stid will be used to open server filter in the
filter region.
Signed-off-by: Vipul Pandya <vipul@chelsio.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c')
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 151 |
1 files changed, 143 insertions, 8 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 41537a403eef..888bc7fc7a38 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
@@ -2481,8 +2481,34 @@ int cxgb4_alloc_stid(struct tid_info *t, int family, void *data) | |||
2481 | } | 2481 | } |
2482 | EXPORT_SYMBOL(cxgb4_alloc_stid); | 2482 | EXPORT_SYMBOL(cxgb4_alloc_stid); |
2483 | 2483 | ||
2484 | /* | 2484 | /* Allocate a server filter TID and set it to the supplied value. |
2485 | * Release a server TID. | 2485 | */ |
2486 | int cxgb4_alloc_sftid(struct tid_info *t, int family, void *data) | ||
2487 | { | ||
2488 | int stid; | ||
2489 | |||
2490 | spin_lock_bh(&t->stid_lock); | ||
2491 | if (family == PF_INET) { | ||
2492 | stid = find_next_zero_bit(t->stid_bmap, | ||
2493 | t->nstids + t->nsftids, t->nstids); | ||
2494 | if (stid < (t->nstids + t->nsftids)) | ||
2495 | __set_bit(stid, t->stid_bmap); | ||
2496 | else | ||
2497 | stid = -1; | ||
2498 | } else { | ||
2499 | stid = -1; | ||
2500 | } | ||
2501 | if (stid >= 0) { | ||
2502 | t->stid_tab[stid].data = data; | ||
2503 | stid += t->stid_base; | ||
2504 | t->stids_in_use++; | ||
2505 | } | ||
2506 | spin_unlock_bh(&t->stid_lock); | ||
2507 | return stid; | ||
2508 | } | ||
2509 | EXPORT_SYMBOL(cxgb4_alloc_sftid); | ||
2510 | |||
2511 | /* Release a server TID. | ||
2486 | */ | 2512 | */ |
2487 | void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) | 2513 | void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) |
2488 | { | 2514 | { |
@@ -2597,12 +2623,14 @@ static int tid_init(struct tid_info *t) | |||
2597 | unsigned int stid_bmap_size; | 2623 | unsigned int stid_bmap_size; |
2598 | unsigned int natids = t->natids; | 2624 | unsigned int natids = t->natids; |
2599 | 2625 | ||
2600 | stid_bmap_size = BITS_TO_LONGS(t->nstids); | 2626 | stid_bmap_size = BITS_TO_LONGS(t->nstids + t->nsftids); |
2601 | size = t->ntids * sizeof(*t->tid_tab) + | 2627 | size = t->ntids * sizeof(*t->tid_tab) + |
2602 | natids * sizeof(*t->atid_tab) + | 2628 | natids * sizeof(*t->atid_tab) + |
2603 | t->nstids * sizeof(*t->stid_tab) + | 2629 | t->nstids * sizeof(*t->stid_tab) + |
2630 | t->nsftids * sizeof(*t->stid_tab) + | ||
2604 | stid_bmap_size * sizeof(long) + | 2631 | stid_bmap_size * sizeof(long) + |
2605 | t->nftids * sizeof(*t->ftid_tab); | 2632 | t->nftids * sizeof(*t->ftid_tab) + |
2633 | t->nsftids * sizeof(*t->ftid_tab); | ||
2606 | 2634 | ||
2607 | t->tid_tab = t4_alloc_mem(size); | 2635 | t->tid_tab = t4_alloc_mem(size); |
2608 | if (!t->tid_tab) | 2636 | if (!t->tid_tab) |
@@ -2610,7 +2638,7 @@ static int tid_init(struct tid_info *t) | |||
2610 | 2638 | ||
2611 | t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids]; | 2639 | t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids]; |
2612 | t->stid_tab = (struct serv_entry *)&t->atid_tab[natids]; | 2640 | t->stid_tab = (struct serv_entry *)&t->atid_tab[natids]; |
2613 | t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids]; | 2641 | t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids + t->nsftids]; |
2614 | t->ftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size]; | 2642 | t->ftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size]; |
2615 | spin_lock_init(&t->stid_lock); | 2643 | spin_lock_init(&t->stid_lock); |
2616 | spin_lock_init(&t->atid_lock); | 2644 | spin_lock_init(&t->atid_lock); |
@@ -2626,7 +2654,7 @@ static int tid_init(struct tid_info *t) | |||
2626 | t->atid_tab[natids - 1].next = &t->atid_tab[natids]; | 2654 | t->atid_tab[natids - 1].next = &t->atid_tab[natids]; |
2627 | t->afree = t->atid_tab; | 2655 | t->afree = t->atid_tab; |
2628 | } | 2656 | } |
2629 | bitmap_zero(t->stid_bmap, t->nstids); | 2657 | bitmap_zero(t->stid_bmap, t->nstids + t->nsftids); |
2630 | return 0; | 2658 | return 0; |
2631 | } | 2659 | } |
2632 | 2660 | ||
@@ -2988,6 +3016,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) | |||
2988 | { | 3016 | { |
2989 | void *handle; | 3017 | void *handle; |
2990 | struct cxgb4_lld_info lli; | 3018 | struct cxgb4_lld_info lli; |
3019 | unsigned short i; | ||
2991 | 3020 | ||
2992 | lli.pdev = adap->pdev; | 3021 | lli.pdev = adap->pdev; |
2993 | lli.l2t = adap->l2t; | 3022 | lli.l2t = adap->l2t; |
@@ -3014,10 +3043,16 @@ static void uld_attach(struct adapter *adap, unsigned int uld) | |||
3014 | lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET( | 3043 | lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET( |
3015 | t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >> | 3044 | t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >> |
3016 | (adap->fn * 4)); | 3045 | (adap->fn * 4)); |
3046 | lli.filt_mode = tp_vlan_pri_map; | ||
3047 | /* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */ | ||
3048 | for (i = 0; i < NCHAN; i++) | ||
3049 | lli.tx_modq[i] = i; | ||
3017 | lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS); | 3050 | lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS); |
3018 | lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); | 3051 | lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); |
3019 | lli.fw_vers = adap->params.fw_vers; | 3052 | lli.fw_vers = adap->params.fw_vers; |
3020 | lli.dbfifo_int_thresh = dbfifo_int_thresh; | 3053 | lli.dbfifo_int_thresh = dbfifo_int_thresh; |
3054 | lli.sge_pktshift = adap->sge.pktshift; | ||
3055 | lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN; | ||
3021 | 3056 | ||
3022 | handle = ulds[uld].add(&lli); | 3057 | handle = ulds[uld].add(&lli); |
3023 | if (IS_ERR(handle)) { | 3058 | if (IS_ERR(handle)) { |
@@ -3258,7 +3293,7 @@ static int delete_filter(struct adapter *adapter, unsigned int fidx) | |||
3258 | struct filter_entry *f; | 3293 | struct filter_entry *f; |
3259 | int ret; | 3294 | int ret; |
3260 | 3295 | ||
3261 | if (fidx >= adapter->tids.nftids) | 3296 | if (fidx >= adapter->tids.nftids + adapter->tids.nsftids) |
3262 | return -EINVAL; | 3297 | return -EINVAL; |
3263 | 3298 | ||
3264 | f = &adapter->tids.ftid_tab[fidx]; | 3299 | f = &adapter->tids.ftid_tab[fidx]; |
@@ -3271,6 +3306,77 @@ static int delete_filter(struct adapter *adapter, unsigned int fidx) | |||
3271 | return 0; | 3306 | return 0; |
3272 | } | 3307 | } |
3273 | 3308 | ||
3309 | int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, | ||
3310 | __be32 sip, __be16 sport, unsigned int queue) | ||
3311 | { | ||
3312 | int ret; | ||
3313 | struct filter_entry *f; | ||
3314 | struct adapter *adap; | ||
3315 | int i; | ||
3316 | u8 *val; | ||
3317 | |||
3318 | adap = netdev2adap(dev); | ||
3319 | |||
3320 | /* Check to make sure the filter requested is writable ... | ||
3321 | */ | ||
3322 | f = &adap->tids.ftid_tab[stid]; | ||
3323 | ret = writable_filter(f); | ||
3324 | if (ret) | ||
3325 | return ret; | ||
3326 | |||
3327 | /* Clear out any old resources being used by the filter before | ||
3328 | * we start constructing the new filter. | ||
3329 | */ | ||
3330 | if (f->valid) | ||
3331 | clear_filter(adap, f); | ||
3332 | |||
3333 | /* Clear out filter specifications */ | ||
3334 | memset(&f->fs, 0, sizeof(struct ch_filter_specification)); | ||
3335 | f->fs.val.lport = cpu_to_be16(sport); | ||
3336 | f->fs.mask.lport = ~0; | ||
3337 | val = (u8 *)&sip; | ||
3338 | if ((val[0] | val[1] | val[2] | val[3]) != 0) | ||
3339 | for (i = 0; i < 4; i++) { | ||
3340 | f->fs.val.lip[i] = val[i]; | ||
3341 | f->fs.mask.lip[i] = ~0; | ||
3342 | } | ||
3343 | |||
3344 | f->fs.dirsteer = 1; | ||
3345 | f->fs.iq = queue; | ||
3346 | /* Mark filter as locked */ | ||
3347 | f->locked = 1; | ||
3348 | f->fs.rpttid = 1; | ||
3349 | |||
3350 | ret = set_filter_wr(adap, stid); | ||
3351 | if (ret) { | ||
3352 | clear_filter(adap, f); | ||
3353 | return ret; | ||
3354 | } | ||
3355 | |||
3356 | return 0; | ||
3357 | } | ||
3358 | EXPORT_SYMBOL(cxgb4_create_server_filter); | ||
3359 | |||
3360 | int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid, | ||
3361 | unsigned int queue, bool ipv6) | ||
3362 | { | ||
3363 | int ret; | ||
3364 | struct filter_entry *f; | ||
3365 | struct adapter *adap; | ||
3366 | |||
3367 | adap = netdev2adap(dev); | ||
3368 | f = &adap->tids.ftid_tab[stid]; | ||
3369 | /* Unlock the filter */ | ||
3370 | f->locked = 0; | ||
3371 | |||
3372 | ret = delete_filter(adap, stid); | ||
3373 | if (ret) | ||
3374 | return ret; | ||
3375 | |||
3376 | return 0; | ||
3377 | } | ||
3378 | EXPORT_SYMBOL(cxgb4_remove_server_filter); | ||
3379 | |||
3274 | static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev, | 3380 | static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev, |
3275 | struct rtnl_link_stats64 *ns) | 3381 | struct rtnl_link_stats64 *ns) |
3276 | { | 3382 | { |
@@ -3517,6 +3623,34 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) | |||
3517 | v = t4_read_reg(adap, TP_PIO_DATA); | 3623 | v = t4_read_reg(adap, TP_PIO_DATA); |
3518 | t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR); | 3624 | t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR); |
3519 | 3625 | ||
3626 | /* first 4 Tx modulation queues point to consecutive Tx channels */ | ||
3627 | adap->params.tp.tx_modq_map = 0xE4; | ||
3628 | t4_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, | ||
3629 | V_TX_MOD_QUEUE_REQ_MAP(adap->params.tp.tx_modq_map)); | ||
3630 | |||
3631 | /* associate each Tx modulation queue with consecutive Tx channels */ | ||
3632 | v = 0x84218421; | ||
3633 | t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, | ||
3634 | &v, 1, A_TP_TX_SCHED_HDR); | ||
3635 | t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, | ||
3636 | &v, 1, A_TP_TX_SCHED_FIFO); | ||
3637 | t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, | ||
3638 | &v, 1, A_TP_TX_SCHED_PCMD); | ||
3639 | |||
3640 | #define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */ | ||
3641 | if (is_offload(adap)) { | ||
3642 | t4_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, | ||
3643 | V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | | ||
3644 | V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | | ||
3645 | V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | | ||
3646 | V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); | ||
3647 | t4_write_reg(adap, A_TP_TX_MOD_CHANNEL_WEIGHT, | ||
3648 | V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | | ||
3649 | V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | | ||
3650 | V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | | ||
3651 | V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); | ||
3652 | } | ||
3653 | |||
3520 | /* get basic stuff going */ | 3654 | /* get basic stuff going */ |
3521 | return t4_early_init(adap, adap->fn); | 3655 | return t4_early_init(adap, adap->fn); |
3522 | } | 3656 | } |
@@ -4938,7 +5072,8 @@ static void remove_one(struct pci_dev *pdev) | |||
4938 | */ | 5072 | */ |
4939 | if (adapter->tids.ftid_tab) { | 5073 | if (adapter->tids.ftid_tab) { |
4940 | struct filter_entry *f = &adapter->tids.ftid_tab[0]; | 5074 | struct filter_entry *f = &adapter->tids.ftid_tab[0]; |
4941 | for (i = 0; i < adapter->tids.nftids; i++, f++) | 5075 | for (i = 0; i < (adapter->tids.nftids + |
5076 | adapter->tids.nsftids); i++, f++) | ||
4942 | if (f->valid) | 5077 | if (f->valid) |
4943 | clear_filter(adapter, f); | 5078 | clear_filter(adapter, f); |
4944 | } | 5079 | } |