diff options
author | Casey Leedom <leedom@chelsio.com> | 2010-06-25 08:11:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-29 02:59:35 -0400 |
commit | 7ee9ff94857dd27144521118173786a03d490efb (patch) | |
tree | 6b76131ed3b3c8d77328bfdda158ac3d44d01bf4 /drivers/net/cxgb4 | |
parent | 17edf2594fef0c7ff186720915a9a73f77fee96b (diff) |
cxgb4vf: Add code to provision T4 PCI-E SR-IOV Virtual Functions with hardware resources
Add code to provision T4 PCI-E SR-IOV Virtual Functions with hardware
resources.
Signed-off-by: Casey Leedom
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/cxgb4')
-rw-r--r-- | drivers/net/cxgb4/cxgb4_main.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index 27f65b501a0a..65281674de91 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c | |||
@@ -77,6 +77,76 @@ | |||
77 | */ | 77 | */ |
78 | #define MAX_SGE_TIMERVAL 200U | 78 | #define MAX_SGE_TIMERVAL 200U |
79 | 79 | ||
80 | #ifdef CONFIG_PCI_IOV | ||
81 | /* | ||
82 | * Virtual Function provisioning constants. We need two extra Ingress Queues | ||
83 | * with Interrupt capability to serve as the VF's Firmware Event Queue and | ||
84 | * Forwarded Interrupt Queue (when using MSI mode) -- neither will have Free | ||
85 | * Lists associated with them). For each Ethernet/Control Egress Queue and | ||
86 | * for each Free List, we need an Egress Context. | ||
87 | */ | ||
88 | enum { | ||
89 | VFRES_NPORTS = 1, /* # of "ports" per VF */ | ||
90 | VFRES_NQSETS = 2, /* # of "Queue Sets" per VF */ | ||
91 | |||
92 | VFRES_NVI = VFRES_NPORTS, /* # of Virtual Interfaces */ | ||
93 | VFRES_NETHCTRL = VFRES_NQSETS, /* # of EQs used for ETH or CTRL Qs */ | ||
94 | VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */ | ||
95 | VFRES_NIQ = 0, /* # of non-fl/int ingress queues */ | ||
96 | VFRES_NEQ = VFRES_NQSETS*2, /* # of egress queues */ | ||
97 | VFRES_TC = 0, /* PCI-E traffic class */ | ||
98 | VFRES_NEXACTF = 16, /* # of exact MPS filters */ | ||
99 | |||
100 | VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT, | ||
101 | VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF, | ||
102 | }; | ||
103 | |||
104 | /* | ||
105 | * Provide a Port Access Rights Mask for the specified PF/VF. This is very | ||
106 | * static and likely not to be useful in the long run. We really need to | ||
107 | * implement some form of persistent configuration which the firmware | ||
108 | * controls. | ||
109 | */ | ||
110 | static unsigned int pfvfres_pmask(struct adapter *adapter, | ||
111 | unsigned int pf, unsigned int vf) | ||
112 | { | ||
113 | unsigned int portn, portvec; | ||
114 | |||
115 | /* | ||
116 | * Give PF's access to all of the ports. | ||
117 | */ | ||
118 | if (vf == 0) | ||
119 | return FW_PFVF_CMD_PMASK_MASK; | ||
120 | |||
121 | /* | ||
122 | * For VFs, we'll assign them access to the ports based purely on the | ||
123 | * PF. We assign active ports in order, wrapping around if there are | ||
124 | * fewer active ports than PFs: e.g. active port[pf % nports]. | ||
125 | * Unfortunately the adapter's port_info structs haven't been | ||
126 | * initialized yet so we have to compute this. | ||
127 | */ | ||
128 | if (adapter->params.nports == 0) | ||
129 | return 0; | ||
130 | |||
131 | portn = pf % adapter->params.nports; | ||
132 | portvec = adapter->params.portvec; | ||
133 | for (;;) { | ||
134 | /* | ||
135 | * Isolate the lowest set bit in the port vector. If we're at | ||
136 | * the port number that we want, return that as the pmask. | ||
137 | * otherwise mask that bit out of the port vector and | ||
138 | * decrement our port number ... | ||
139 | */ | ||
140 | unsigned int pmask = portvec ^ (portvec & (portvec-1)); | ||
141 | if (portn == 0) | ||
142 | return pmask; | ||
143 | portn--; | ||
144 | portvec &= ~pmask; | ||
145 | } | ||
146 | /*NOTREACHED*/ | ||
147 | } | ||
148 | #endif | ||
149 | |||
80 | enum { | 150 | enum { |
81 | MEMWIN0_APERTURE = 65536, | 151 | MEMWIN0_APERTURE = 65536, |
82 | MEMWIN0_BASE = 0x30000, | 152 | MEMWIN0_BASE = 0x30000, |
@@ -2925,6 +2995,42 @@ static int adap_init0(struct adapter *adap) | |||
2925 | t4_read_mtu_tbl(adap, adap->params.mtus, NULL); | 2995 | t4_read_mtu_tbl(adap, adap->params.mtus, NULL); |
2926 | t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, | 2996 | t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, |
2927 | adap->params.b_wnd); | 2997 | adap->params.b_wnd); |
2998 | |||
2999 | #ifdef CONFIG_PCI_IOV | ||
3000 | /* | ||
3001 | * Provision resource limits for Virtual Functions. We currently | ||
3002 | * grant them all the same static resource limits except for the Port | ||
3003 | * Access Rights Mask which we're assigning based on the PF. All of | ||
3004 | * the static provisioning stuff for both the PF and VF really needs | ||
3005 | * to be managed in a persistent manner for each device which the | ||
3006 | * firmware controls. | ||
3007 | */ | ||
3008 | { | ||
3009 | int pf, vf; | ||
3010 | |||
3011 | for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) { | ||
3012 | if (num_vf[pf] <= 0) | ||
3013 | continue; | ||
3014 | |||
3015 | /* VF numbering starts at 1! */ | ||
3016 | for (vf = 1; vf <= num_vf[pf]; vf++) { | ||
3017 | ret = t4_cfg_pfvf(adap, 0, pf, vf, | ||
3018 | VFRES_NEQ, VFRES_NETHCTRL, | ||
3019 | VFRES_NIQFLINT, VFRES_NIQ, | ||
3020 | VFRES_TC, VFRES_NVI, | ||
3021 | FW_PFVF_CMD_CMASK_MASK, | ||
3022 | pfvfres_pmask(adap, pf, vf), | ||
3023 | VFRES_NEXACTF, | ||
3024 | VFRES_R_CAPS, VFRES_WX_CAPS); | ||
3025 | if (ret < 0) | ||
3026 | dev_warn(adap->pdev_dev, "failed to " | ||
3027 | "provision pf/vf=%d/%d; " | ||
3028 | "err=%d\n", pf, vf, ret); | ||
3029 | } | ||
3030 | } | ||
3031 | } | ||
3032 | #endif | ||
3033 | |||
2928 | return 0; | 3034 | return 0; |
2929 | 3035 | ||
2930 | /* | 3036 | /* |