aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2014-05-16 15:48:19 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-16 22:39:01 -0400
commitf8afb73da3758a9543f4b7c70caa59a18d864c9b (patch)
tree8024f98dfce8787b752b916babd76a5f43e50de4 /drivers/net/usb
parent5aa73d5d72bddfcac253d06f84e80e38c5bb430c (diff)
net: cdc_ncm: factor out one-time device initialization
Split the parts of setup dealing with device initialization from parts just setting defaults for attributes which might be changed after initialization. Some commands of the device initialization are only allowed when the data interface is in its disabled altsetting, so we must separate them out of we are to allow rerunning parts of setup. Signed-off-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/cdc_ncm.c251
1 files changed, 155 insertions, 96 deletions
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index e5f5153bf8c6..b70e061e3473 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -120,19 +120,51 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
120 ctx->tx_max = val; 120 ctx->tx_max = val;
121} 121}
122 122
123static int cdc_ncm_setup(struct usbnet *dev) 123/* helpers for NCM and MBIM differences */
124static u8 cdc_ncm_flags(struct usbnet *dev)
124{ 125{
125 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; 126 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
126 u32 val;
127 u8 flags;
128 u8 iface_no;
129 int err;
130 int eth_hlen;
131 u16 mbim_mtu;
132 u16 ntb_fmt_supported;
133 __le16 max_datagram_size;
134 127
135 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; 128 if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
129 return ctx->mbim_desc->bmNetworkCapabilities;
130 if (ctx->func_desc)
131 return ctx->func_desc->bmNetworkCapabilities;
132 return 0;
133}
134
135static int cdc_ncm_eth_hlen(struct usbnet *dev)
136{
137 if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
138 return 0;
139 return ETH_HLEN;
140}
141
142static u32 cdc_ncm_min_dgram_size(struct usbnet *dev)
143{
144 if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
145 return CDC_MBIM_MIN_DATAGRAM_SIZE;
146 return CDC_NCM_MIN_DATAGRAM_SIZE;
147}
148
149static u32 cdc_ncm_max_dgram_size(struct usbnet *dev)
150{
151 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
152
153 if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
154 return le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize);
155 if (ctx->ether_desc)
156 return le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
157 return CDC_NCM_MAX_DATAGRAM_SIZE;
158}
159
160/* initial one-time device setup. MUST be called with the data interface
161 * in altsetting 0
162 */
163static int cdc_ncm_init(struct usbnet *dev)
164{
165 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
166 u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
167 int err;
136 168
137 err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS, 169 err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
138 USB_TYPE_CLASS | USB_DIR_IN 170 USB_TYPE_CLASS | USB_DIR_IN
@@ -144,7 +176,35 @@ static int cdc_ncm_setup(struct usbnet *dev)
144 return err; /* GET_NTB_PARAMETERS is required */ 176 return err; /* GET_NTB_PARAMETERS is required */
145 } 177 }
146 178
147 /* read correct set of parameters according to device mode */ 179 /* set CRC Mode */
180 if (cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_CRC_MODE) {
181 dev_dbg(&dev->intf->dev, "Setting CRC mode off\n");
182 err = usbnet_write_cmd(dev, USB_CDC_SET_CRC_MODE,
183 USB_TYPE_CLASS | USB_DIR_OUT
184 | USB_RECIP_INTERFACE,
185 USB_CDC_NCM_CRC_NOT_APPENDED,
186 iface_no, NULL, 0);
187 if (err < 0)
188 dev_err(&dev->intf->dev, "SET_CRC_MODE failed\n");
189 }
190
191 /* set NTB format, if both formats are supported.
192 *
193 * "The host shall only send this command while the NCM Data
194 * Interface is in alternate setting 0."
195 */
196 if (le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported) & USB_CDC_NCM_NTH32_SIGN) {
197 dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit\n");
198 err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
199 USB_TYPE_CLASS | USB_DIR_OUT
200 | USB_RECIP_INTERFACE,
201 USB_CDC_NCM_NTB16_FORMAT,
202 iface_no, NULL, 0);
203 if (err < 0)
204 dev_err(&dev->intf->dev, "SET_NTB_FORMAT failed\n");
205 }
206
207 /* set initial device values */
148 ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize); 208 ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
149 ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize); 209 ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
150 ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder); 210 ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
@@ -152,43 +212,73 @@ static int cdc_ncm_setup(struct usbnet *dev)
152 ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment); 212 ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
153 /* devices prior to NCM Errata shall set this field to zero */ 213 /* devices prior to NCM Errata shall set this field to zero */
154 ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams); 214 ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
155 ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
156
157 /* there are some minor differences in NCM and MBIM defaults */
158 if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) {
159 if (!ctx->mbim_desc)
160 return -EINVAL;
161 eth_hlen = 0;
162 flags = ctx->mbim_desc->bmNetworkCapabilities;
163 ctx->max_datagram_size = le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize);
164 if (ctx->max_datagram_size < CDC_MBIM_MIN_DATAGRAM_SIZE)
165 ctx->max_datagram_size = CDC_MBIM_MIN_DATAGRAM_SIZE;
166 } else {
167 if (!ctx->func_desc)
168 return -EINVAL;
169 eth_hlen = ETH_HLEN;
170 flags = ctx->func_desc->bmNetworkCapabilities;
171 ctx->max_datagram_size = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
172 if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
173 ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
174 }
175
176 /* common absolute max for NCM and MBIM */
177 if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
178 ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
179 215
180 dev_dbg(&dev->intf->dev, 216 dev_dbg(&dev->intf->dev,
181 "dwNtbInMaxSize=%u dwNtbOutMaxSize=%u wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n", 217 "dwNtbInMaxSize=%u dwNtbOutMaxSize=%u wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n",
182 ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus, 218 ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
183 ctx->tx_ndp_modulus, ctx->tx_max_datagrams, flags); 219 ctx->tx_ndp_modulus, ctx->tx_max_datagrams, cdc_ncm_flags(dev));
184 220
185 /* max count of tx datagrams */ 221 /* max count of tx datagrams */
186 if ((ctx->tx_max_datagrams == 0) || 222 if ((ctx->tx_max_datagrams == 0) ||
187 (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX)) 223 (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
188 ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX; 224 ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
189 225
190 /* clamp rx_max and tx_max and inform device */ 226 return 0;
191 cdc_ncm_update_rxtx_max(dev, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize), le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)); 227}
228
229/* set a new max datagram size */
230static void cdc_ncm_set_dgram_size(struct usbnet *dev, int new_size)
231{
232 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
233 u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
234 __le16 max_datagram_size;
235 u16 mbim_mtu;
236 int err;
237
238 /* set default based on descriptors */
239 ctx->max_datagram_size = clamp_t(u32, new_size,
240 cdc_ncm_min_dgram_size(dev),
241 CDC_NCM_MAX_DATAGRAM_SIZE);
242
243 /* inform the device about the selected Max Datagram Size? */
244 if (!(cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE))
245 goto out;
246
247 /* read current mtu value from device */
248 err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
249 USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
250 0, iface_no, &max_datagram_size, 2);
251 if (err < 0) {
252 dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n");
253 goto out;
254 }
255
256 if (le16_to_cpu(max_datagram_size) == ctx->max_datagram_size)
257 goto out;
258
259 max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
260 err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE,
261 USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
262 0, iface_no, &max_datagram_size, 2);
263 if (err < 0)
264 dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
265
266out:
267 /* set MTU to max supported by the device if necessary */
268 dev->net->mtu = min_t(int, dev->net->mtu, ctx->max_datagram_size - cdc_ncm_eth_hlen(dev));
269
270 /* do not exceed operater preferred MTU */
271 if (ctx->mbim_extended_desc) {
272 mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
273 if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
274 dev->net->mtu = mbim_mtu;
275 }
276}
277
278static void cdc_ncm_fix_modulus(struct usbnet *dev)
279{
280 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
281 u32 val;
192 282
193 /* 283 /*
194 * verify that the structure alignment is: 284 * verify that the structure alignment is:
@@ -225,68 +315,26 @@ static int cdc_ncm_setup(struct usbnet *dev)
225 } 315 }
226 316
227 /* adjust TX-remainder according to NCM specification. */ 317 /* adjust TX-remainder according to NCM specification. */
228 ctx->tx_remainder = ((ctx->tx_remainder - eth_hlen) & 318 ctx->tx_remainder = ((ctx->tx_remainder - cdc_ncm_eth_hlen(dev)) &
229 (ctx->tx_modulus - 1)); 319 (ctx->tx_modulus - 1));
320}
230 321
231 /* additional configuration */ 322static int cdc_ncm_setup(struct usbnet *dev)
232 323{
233 /* set CRC Mode */ 324 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
234 if (flags & USB_CDC_NCM_NCAP_CRC_MODE) {
235 err = usbnet_write_cmd(dev, USB_CDC_SET_CRC_MODE,
236 USB_TYPE_CLASS | USB_DIR_OUT
237 | USB_RECIP_INTERFACE,
238 USB_CDC_NCM_CRC_NOT_APPENDED,
239 iface_no, NULL, 0);
240 if (err < 0)
241 dev_dbg(&dev->intf->dev, "Setting CRC mode off failed\n");
242 }
243
244 /* set NTB format, if both formats are supported */
245 if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) {
246 err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
247 USB_TYPE_CLASS | USB_DIR_OUT
248 | USB_RECIP_INTERFACE,
249 USB_CDC_NCM_NTB16_FORMAT,
250 iface_no, NULL, 0);
251 if (err < 0)
252 dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit failed\n");
253 }
254
255 /* inform the device about the selected Max Datagram Size */
256 if (!(flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE))
257 goto out;
258
259 /* read current mtu value from device */
260 err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
261 USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
262 0, iface_no, &max_datagram_size, 2);
263 if (err < 0) {
264 dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n");
265 goto out;
266 }
267 325
268 if (le16_to_cpu(max_datagram_size) == ctx->max_datagram_size) 326 /* initialize basic device settings */
269 goto out; 327 cdc_ncm_init(dev);
270 328
271 max_datagram_size = cpu_to_le16(ctx->max_datagram_size); 329 /* clamp rx_max and tx_max and inform device */
272 err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE, 330 cdc_ncm_update_rxtx_max(dev, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize),
273 USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, 331 le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
274 0, iface_no, &max_datagram_size, 2);
275 if (err < 0)
276 dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
277
278out:
279 /* set MTU to max supported by the device if necessary */
280 if (dev->net->mtu > ctx->max_datagram_size - eth_hlen)
281 dev->net->mtu = ctx->max_datagram_size - eth_hlen;
282 332
283 /* do not exceed operater preferred MTU */ 333 /* sanitize the modulus and remainder values */
284 if (ctx->mbim_extended_desc) { 334 cdc_ncm_fix_modulus(dev);
285 mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
286 if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
287 dev->net->mtu = mbim_mtu;
288 }
289 335
336 /* set max datagram size */
337 cdc_ncm_set_dgram_size(dev, cdc_ncm_max_dgram_size(dev));
290 return 0; 338 return 0;
291} 339}
292 340
@@ -450,10 +498,21 @@ advance:
450 } 498 }
451 499
452 /* check if we got everything */ 500 /* check if we got everything */
453 if (!ctx->data || (!ctx->mbim_desc && !ctx->ether_desc)) { 501 if (!ctx->data) {
454 dev_dbg(&intf->dev, "CDC descriptors missing\n"); 502 dev_dbg(&intf->dev, "CDC Union missing and no IAD found\n");
455 goto error; 503 goto error;
456 } 504 }
505 if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) {
506 if (!ctx->mbim_desc) {
507 dev_dbg(&intf->dev, "MBIM functional descriptor missing\n");
508 goto error;
509 }
510 } else {
511 if (!ctx->ether_desc || !ctx->func_desc) {
512 dev_dbg(&intf->dev, "NCM or ECM functional descriptors missing\n");
513 goto error;
514 }
515 }
457 516
458 /* claim data interface, if different from control */ 517 /* claim data interface, if different from control */
459 if (ctx->data != ctx->control) { 518 if (ctx->data != ctx->control) {